167 lines
3.5 KiB
Ruby
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
|
|
|