# frozen_string_literal: true module HandTypeName FIVE_OF_A_KIND = 7 FOUR_OF_A_KIND = 6 FULL_HOUSE = 5 THREE_OF_A_KIND = 4 TWO_PAIR = 3 ONE_PAIR = 2 HIGH_CARD = 1 end class HandType def initialize(type_name, card_value) @type_name = type_name @card_value = card_value.split("").sort.join("") end def ==(o) o.class == self.class && o.type_name == @type_name && o.card_value == @card_value end def <=>(o) @type_name <=> o.type_name end attr_accessor :type_name attr_accessor :card_value end def compare_card(card1, card2) ordered_cards = "AKQJT98765432".reverse if !ordered_cards.include?(card1) || !ordered_cards.include?(card2) raise Exception.new("Unknown card #{card1} or #{card2}") end ordered_cards.index(card1) <=> ordered_cards.index(card2) end class Hand def initialize(cards, bid) @cards = cards @bid = bid end def _card_map card_map = {} @cards.each_char do |card| if card_map.include? card card_map[card] += 1 else card_map[card] = 1 end end card_map end def _reversed_card_map ret = {} _card_map.each_pair do |key, value| if ret.include? value ret[value].append key else ret[value] = [key] end end ret end def _get_five_of_a_kind if _card_map.values.include? 5 return HandType.new HandTypeName::FIVE_OF_A_KIND, _reversed_card_map[5][0] end nil end def _get_four_of_a_kind if _card_map.values.include? 4 return HandType.new HandTypeName::FOUR_OF_A_KIND, _reversed_card_map[4][0] end nil end def _get_full_house if _card_map.values.include?(3) && _card_map.values.include?(2) return HandType.new HandTypeName::FULL_HOUSE, _reversed_card_map[3][0] + _reversed_card_map[2][0] end nil end def _get_three_of_a_kind if _card_map.values.include?(3) return HandType.new HandTypeName::THREE_OF_A_KIND, _reversed_card_map[3][0] end nil end def _get_two_pairs if _card_map.values.include?(2) && (_reversed_card_map[2].length == 2) return HandType.new HandTypeName::TWO_PAIR, _reversed_card_map[2][0] + _reversed_card_map[2][1] end nil end def _get_one_pair if _card_map.values.include?(2) return HandType.new HandTypeName::ONE_PAIR, _reversed_card_map[2][0] end nil end def _get_high_card high_card = @cards.split("").sort {|c1, c2| compare_card(c1, c2)} .last HandType.new HandTypeName::HIGH_CARD, high_card end def get_type (_get_five_of_a_kind or _get_four_of_a_kind or _get_full_house or _get_three_of_a_kind or _get_two_pairs or _get_one_pair or _get_high_card) end def <=>(other) if (get_type <=> other.get_type) != 0 return get_type <=> other.get_type end ((0...5).map {|i| compare_card(@cards[i], other.cards[i])}.drop_while { |v| v == 0}.first) or 0 end def self.deserialize(line) parts = line.split(/\s+/) self.new parts[0], parts[1].to_i end attr_accessor :cards attr_accessor :bid end def play_part_1_game(input) input.strip.split("\n") .filter {|line| !line.empty?} .map {|line| Hand.deserialize line} .sort .each_with_index .map {|hand, idx| hand.bid * (idx + 1)} .reduce 0, :+ end if __FILE__ == $0 input_file_name = File.join(File.dirname(__FILE__), "day_7_input.txt") input_content = File.open(input_file_name).read puts "Solution to part 1: #{play_part_1_game input_content}" end