246 lines
5.0 KiB
Ruby
246 lines
5.0 KiB
Ruby
|
VALUES = [:two, :three, :four, :five, :six, :seven, :eight, :nine, :ten, :jack, :queen, :king, :ace]
|
||
|
SUITS = [:heart, :diamond, :spade, :club]
|
||
|
|
||
|
STRING_TO_SUIT_MAP = { 'H' => :heart,
|
||
|
'D' => :diamond,
|
||
|
'S' => :spade,
|
||
|
'C' => :club }
|
||
|
|
||
|
STRING_TO_VALUE_MAP = {'A' => :ace,
|
||
|
'K' => :king,
|
||
|
'Q' => :queen,
|
||
|
'J' => :jack,
|
||
|
'10' => :ten,
|
||
|
'T' => :ten,
|
||
|
'9' => :nine,
|
||
|
'8' => :eight,
|
||
|
'7' => :seven,
|
||
|
'6' => :six,
|
||
|
'5' => :five,
|
||
|
'4' => :four,
|
||
|
'3' => :three,
|
||
|
'2' => :two}
|
||
|
|
||
|
class Card
|
||
|
include Comparable
|
||
|
|
||
|
attr_reader :suit, :value
|
||
|
|
||
|
def initialize(suit, value)
|
||
|
@suit = STRING_TO_SUIT_MAP[suit]
|
||
|
@value = STRING_TO_VALUE_MAP[value]
|
||
|
end
|
||
|
|
||
|
def succ_value
|
||
|
if value == :ace
|
||
|
:two
|
||
|
else
|
||
|
VALUES[VALUES.index(value) + 1]
|
||
|
end
|
||
|
end
|
||
|
|
||
|
def succ? other
|
||
|
succ_value == other.value
|
||
|
end
|
||
|
|
||
|
def <=> other
|
||
|
VALUES.index(value) <=> VALUES.index(other.value)
|
||
|
end
|
||
|
|
||
|
def === other
|
||
|
suit == other.suit and value == other.value
|
||
|
end
|
||
|
|
||
|
def ace?
|
||
|
value == :ace
|
||
|
end
|
||
|
end
|
||
|
|
||
|
class Hand
|
||
|
include Comparable
|
||
|
|
||
|
attr_reader :cards
|
||
|
|
||
|
def initialize(*cards)
|
||
|
if cards.first.is_a? String
|
||
|
card_strings = cards.first.split(' ')
|
||
|
@cards = card_strings.map { |str| str.split('') }.map { |value, suit| Card.new(suit, value) }
|
||
|
else
|
||
|
@cards = cards
|
||
|
end
|
||
|
end
|
||
|
|
||
|
def flush?
|
||
|
suits.uniq.one?
|
||
|
end
|
||
|
|
||
|
def straight?
|
||
|
if ace?
|
||
|
all_successors? cards.sort or all_successors? aces_low
|
||
|
else
|
||
|
all_successors? cards.sort
|
||
|
end
|
||
|
end
|
||
|
|
||
|
def straight_flush?
|
||
|
straight? and flush?
|
||
|
end
|
||
|
|
||
|
def royal_flush?
|
||
|
flush? and
|
||
|
values.include?(:ten) and
|
||
|
values.include?(:jack) and
|
||
|
values.include?(:queen) and
|
||
|
values.include?(:king) and
|
||
|
values.include?(:ace)
|
||
|
end
|
||
|
|
||
|
def four_of_a_kind?
|
||
|
same_of_value?(4)
|
||
|
end
|
||
|
|
||
|
def three_of_a_kind?
|
||
|
same_of_value?(3)
|
||
|
end
|
||
|
|
||
|
def full_house?
|
||
|
same_of_value?(3) and same_of_value?(2)
|
||
|
end
|
||
|
|
||
|
def two_pair?
|
||
|
collapsed == 2 and same_of_value?(2)
|
||
|
end
|
||
|
|
||
|
def pair?
|
||
|
same_of_value?(2)
|
||
|
end
|
||
|
|
||
|
def values
|
||
|
cards.map(&:value)
|
||
|
end
|
||
|
|
||
|
def suits
|
||
|
cards.map(&:suit)
|
||
|
end
|
||
|
|
||
|
def aces_low
|
||
|
sorted = cards.sort
|
||
|
while sorted.last.ace?
|
||
|
ace = sorted.pop
|
||
|
sorted.insert(0, ace)
|
||
|
end
|
||
|
sorted
|
||
|
end
|
||
|
|
||
|
def ace?
|
||
|
cards.any? { |card| card.ace? }
|
||
|
end
|
||
|
|
||
|
def high_card
|
||
|
cards.sort.last
|
||
|
end
|
||
|
|
||
|
def full_house_high_value
|
||
|
cards.group_by { |card| card.value }.detect { |k, v| v.count == 3 }.first
|
||
|
end
|
||
|
|
||
|
def full_house_low_value
|
||
|
cards.group_by { |card| card.value }.detect { |k, v| v.count == 2 }.first
|
||
|
end
|
||
|
|
||
|
def high_match_value
|
||
|
cards.group_by { |card| card.value }.select { |k, v| v.count > 1 }.keys.max { |a, b| VALUES.index(a) <=> VALUES.index(b) }
|
||
|
end
|
||
|
|
||
|
def low_match_value
|
||
|
cards.group_by { |card| card.value }.select { |k, v| v.count > 1 }.keys.min { |a, b| VALUES.index(a) <=> VALUES.index(b) }
|
||
|
end
|
||
|
|
||
|
def kicker
|
||
|
removed_value(high_match_value).sort.last
|
||
|
end
|
||
|
|
||
|
def <=> other
|
||
|
poker_score <=> other.poker_score
|
||
|
end
|
||
|
|
||
|
def poker_score
|
||
|
if royal_flush?
|
||
|
900000
|
||
|
elsif straight_flush?
|
||
|
800000 + high_card_score
|
||
|
elsif four_of_a_kind?
|
||
|
700000 + high_match_score * 100 + kicker_score
|
||
|
elsif full_house?
|
||
|
600000 + full_house_high_score * 1000 + full_house_low_score * 10
|
||
|
elsif flush?
|
||
|
500000 + high_card_score
|
||
|
elsif straight?
|
||
|
400000 + high_card_score
|
||
|
elsif three_of_a_kind?
|
||
|
300000 + high_match_score * 100 + kicker_score
|
||
|
elsif two_pair?
|
||
|
200000 + high_match_score * 1000 + low_match_score * 10 + kicker_score
|
||
|
elsif pair?
|
||
|
100000 + high_match_score * 100 + kicker_score
|
||
|
else
|
||
|
high_card_score
|
||
|
end
|
||
|
end
|
||
|
|
||
|
private
|
||
|
|
||
|
def kicker_score
|
||
|
VALUES.index(kicker.value)
|
||
|
end
|
||
|
|
||
|
def high_card_score
|
||
|
VALUES.index(high_card.value)
|
||
|
end
|
||
|
|
||
|
def high_match_score
|
||
|
VALUES.index(high_match_value)
|
||
|
end
|
||
|
|
||
|
def low_match_score
|
||
|
VALUES.index(low_match_value)
|
||
|
end
|
||
|
|
||
|
def full_house_high_score
|
||
|
VALUES.index(full_house_high_value)
|
||
|
end
|
||
|
|
||
|
def full_house_low_score
|
||
|
VALUES.index(full_house_low_value)
|
||
|
end
|
||
|
|
||
|
def removed_value(value)
|
||
|
cards.reject { |card| card.value == value }
|
||
|
end
|
||
|
|
||
|
def collapsed
|
||
|
cards.size - values.uniq.size
|
||
|
end
|
||
|
|
||
|
def same_of_value(n)
|
||
|
cards.detect { |card| cards.count { |c| c.value == card.value } == n }.value
|
||
|
end
|
||
|
|
||
|
def same_of_value?(n)
|
||
|
cards.any? { |card| cards.count { |c| c.value == card.value } == n }
|
||
|
end
|
||
|
|
||
|
def all_successors?(cards)
|
||
|
cards.all? {|card| card === cards.last || card.succ?(cards[cards.index(card) + 1]) }
|
||
|
end
|
||
|
end
|
||
|
|
||
|
def games
|
||
|
game_lines = File.readlines("../input/p054_poker.txt")
|
||
|
game_lines.map { |game_line| [game_line[0..13], game_line[15..28]] }.map { |one, two| [Hand.new(one), Hand.new(two)] }
|
||
|
end
|
||
|
|
||
|
def solution
|
||
|
games.map { |one, two| one > two }.count(true)
|
||
|
end
|