AdventOfCode 2023 Day 7

Part One

比较简单的poker game,比较手牌大小

32T3K
T55J5

按手牌count后降序组合起来,比如41、311、32等。

WITH cards(rn, hands, bid) AS (
  SELECT row_number() over () as rn, split_part(line, ' ', 1) as hands, split_part(line, ' ', 2) :: integer as bid
  FROM lance_input
),
score(rn, ord) AS (
  SELECT rn, string_agg(cnt::text, '' order by cnt desc) as ord
  FROM (
    SELECT rn, card, count(*) as cnt
    FROM (
    SELECT rn, unnest(regexp_split_to_array(hands, '')) as card
    FROM cards
    ) t
    GROUP by rn, card
  ) s
  GROUP BY rn
)
SELECT sum(bid * rank)
FROM (
SELECT x.rn, bid, row_number() over (order by ord, replace(replace(replace(replace(replace(hands, 'T', 'B'), 'J', 'C'), 'Q', 'D'), 'K', 'E'), 'A', 'F')) as rank
FROM cards x
JOIN score y
ON x.rn = y.rn
) t;

Part Two

第二部分变成了惯蛋游戏,J可以变成任意牌

T55J5 -> T5555

需要先求出每手牌最多的牌

max_card (rn, card, cnt) AS (
  SELECT rn, card, cnt
  FROM (
    SELECT rn, card, cnt, row_number() over (partition by rn order by cnt desc) as rank
    FROM (
      SELECT rn, card, cnt
      FROM all_card
      WHERE card != 'J'
    ) t
  )s
  WHERE rank = 1
)

再使用J替换最多牌后,重新进行汇总

replace_card(rn, card, cnt) AS (
  SELECT rn, card, sum(cnt)
  FROM (
    SELECT x.rn, case when x.card = 'J' AND y.card IS NOT NULL then y.card else x.card end as card, x.cnt
    FROM all_card x
    LEFT JOIN max_card y
    ON x.rn = y.rn
  ) t
  GROUP by rn, card
)

最终SQL如下:

WITH cards(rn, hands, bid) AS (
  SELECT row_number() over () as rn, split_part(line, ' ', 1) as hands, split_part(line, ' ', 2) :: integer as bid
  FROM lance_input
),
all_card(rn, card, cnt) AS (
  SELECT rn, card, count(*) as cnt
  FROM (
  SELECT rn, unnest(regexp_split_to_array(hands, '')) as card
  FROM cards
  ) t
  GROUP by rn, card
),
max_card (rn, card, cnt) AS (
  SELECT rn, card, cnt
  FROM (
    SELECT rn, card, cnt, row_number() over (partition by rn order by cnt desc) as rank
    FROM (
      SELECT rn, card, cnt
      FROM all_card
      WHERE card != 'J'
    ) t
  )s
  WHERE rank = 1
),
replace_card(rn, card, cnt) AS (
  SELECT rn, card, sum(cnt)
  FROM (
    SELECT x.rn, case when x.card = 'J' AND y.card IS NOT NULL then y.card else x.card end as card, x.cnt
    FROM all_card x
    LEFT JOIN max_card y
    ON x.rn = y.rn
  ) t
  GROUP by rn, card
),
score(rn, ord) AS (
  SELECT rn, string_agg(cnt::text, '' order by cnt desc) as ord
  FROM replace_card s
  GROUP BY rn
)
SELECT sum(bid * rank)
FROM (
SELECT x.rn, bid, row_number() over (order by ord, replace(replace(replace(replace(replace(hands, 'T', 'B'), 'J', 'C'), 'Q', 'D'), 'K', 'E'), 'A', 'F')) as rank
FROM cards x
JOIN score y
ON x.rn = y.rn
) t

发表评论