HAND_STRENGTH = [ [5], # five of a kind [1, 4], # four of a kind [2, 3], # full house [1, 1, 3], # three of a kind [1, 2, 2], # two pair [1, 1, 1, 2], # one pair [1, 1, 1, 1, 1], # high card ].reverse.each.with_index.to_h { [_1, _2] } class PartOne CARD_RANK = ((?2..?9).to_a + %w[ T J Q K A ]).each.with_index.to_h def strength(cards) tally = cards.tally strengths = [ self.hand_type(tally), *cards.map { CARD_RANK.fetch(_1) }, ] strengths.map { (?a.ord + _1).chr }.join end def hand_type(tally) HAND_STRENGTH.fetch(tally.values.sort) end end class PartTwo < PartOne CARD_RANK = ([?J] + (?2..?9).to_a + %w[ T Q K A ]).each.with_index.to_h def hand_type(tally) jokers = tally.delete(?J) || 0 counts = tally.values.sort if counts.empty? counts = [5] else counts[-1] += jokers end HAND_STRENGTH.fetch(counts) end end hands = ARGF.read.scan(/(\w+)\s+(\d+)/).to_h { [_1.chars, _2.to_i ] } part_one = PartOne.new p hands .sort_by {|(hand,_)| part_one.strength(hand) } .map.with_index {|(_,bid),i| bid * (i+1) } .sum part_two = PartTwo.new p hands .sort_by {|(hand,_)| part_two.strength(hand) } .map.with_index {|(_,bid),i| bid * (i+1) } .sum