Files
advend-of-code-2023-in-ruby/src/advent/day7.rb
T
2023-12-07 09:48:17 -05:00

167 lines
3.5 KiB
Ruby

# 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