Created
January 14, 2021 04:45
-
-
Save baweaver/0d566a6afe1214b37718b166bbfa9ece to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Card = Struct.new(:suit, :rank) do | |
include Comparable | |
def precedence() = [SUITS_SCORES[self.suit], RANKS_SCORES[self.rank]] | |
def rank_precedence() = RANKS_SCORES[self.rank] | |
def suit_precedence() = SUITS_SCORES[self.rank] | |
def <=>(other) = self.precedence <=> other.precedence | |
def to_s() = "#{self.suit}#{self.rank}" | |
end | |
Hand = Struct.new(:cards) do | |
def sort() = Hand[self.cards.sort] | |
def sort_by_rank() = Hand[self.cards.sort_by(&:rank_precedence)] | |
def to_s() = self.cards.map(&:to_s).join(', ') | |
end | |
SUITS = %w(S H D C).freeze | |
SUITS_SCORES = SUITS.each_with_index.to_h | |
RANKS = [*2..10, *%w(J Q K A)].map(&:to_s).freeze | |
RANKS_SCORES = RANKS.each_with_index.to_h | |
SCORES = %i( | |
royal_flush | |
straight_flush | |
four_of_a_kind | |
full_house | |
flush | |
straight | |
three_of_a_kind | |
two_pair | |
one_pair | |
high_card | |
).reverse_each.with_index(1).to_h.freeze | |
CARDS = SUITS.flat_map { |suit| | |
RANKS.map { |rank| Card[suit, rank] } | |
}.freeze | |
def add_rank(rank, n) = RANKS[RANKS_SCORES[rank] + n] | |
def royal_flush?(hand) | |
hand in [ | |
Card[suit, '10'], | |
Card[^suit, 'J'], | |
Card[^suit, 'Q'], | |
Card[^suit, 'K'], | |
Card[^suit, 'A'] | |
] | |
end | |
def straight_flush?(hand) = straight?(hand) && flush?(hand) | |
def straight?(hand) | |
hand in [ | |
Card[*, rank], | |
Card[*, "#{add_rank(rank, 1)}"], | |
Card[*, "#{add_rank(rank, 2)}"], | |
Card[*, "#{add_rank(rank, 3)}"], | |
Card[*, "#{add_rank(rank, 4)}"], | |
] | |
end | |
def flush?(hand) | |
hand in [ | |
Card[suit, *], | |
Card[^suit, *], | |
Card[^suit, *], | |
Card[^suit, *], | |
Card[^suit, *] | |
] | |
end | |
def four_of_a_kind?(hand) | |
hand in [ | |
*, | |
Card[*, rank], | |
Card[*, ^rank], | |
Card[*, ^rank], | |
Card[*, ^rank], | |
* | |
] | |
end | |
def full_house?(hand) | |
return true if hand in [ | |
Card[*, rank_one], | |
Card[*, ^rank_one], | |
Card[*, rank_two], | |
Card[*, ^rank_two], | |
Card[*, ^rank_two] | |
] | |
hand in [ | |
Card[*, rank_one], | |
Card[*, ^rank_one], | |
Card[*, ^rank_one], | |
Card[*, rank_two], | |
Card[*, ^rank_two] | |
] | |
end | |
def three_of_a_kind?(hand) | |
hand in [ | |
*, | |
Card[*, rank], | |
Card[*, ^rank], | |
Card[*, ^rank], | |
* | |
] | |
end | |
def two_pair?(hand) | |
return true if hand in [ | |
Card[*, rank_one], | |
Card[*, ^rank_one], | |
*, | |
Card[*, rank_two], | |
Card[*, ^rank_two] | |
] | |
hand in [ | |
*, | |
Card[*, rank_one], | |
Card[*, ^rank_one], | |
Card[*, rank_two], | |
Card[*, ^rank_two], | |
* | |
] | |
end | |
def one_pair?(hand) | |
hand in [ | |
*, | |
Card[*, rank], | |
Card[*, ^rank], | |
* | |
] | |
end | |
def hand_score(unsorted_hand) | |
hand = Hand[unsorted_hand].sort_by_rank.cards | |
return SCORES[:royal_flush] if royal_flush?(hand) | |
return SCORES[:straight_flush] if straight_flush?(hand) | |
return SCORES[:four_of_a_kind] if four_of_a_kind?(hand) | |
return SCORES[:full_house] if full_house?(hand) | |
return SCORES[:flush] if flush?(hand) | |
return SCORES[:straight] if straight?(hand) | |
return SCORES[:three_of_a_kind] if three_of_a_kind?(hand) | |
return SCORES[:two_pair] if two_pair?(hand) | |
return SCORES[:one_pair] if one_pair?(hand) | |
SCORES[:high_card] | |
end | |
# --- Testing ------ | |
EXAMPLES = { | |
royal_flush: | |
RANKS.last(5).map { Card['S', _1] }, | |
straight_flush: | |
RANKS.first(5).map { Card['S', _1] }, | |
four_of_a_kind: | |
[CARDS[0], *SUITS.map { Card[_1, 'A'] }], | |
full_house: | |
SUITS.first(3).map { Card[_1, 'A'] } + | |
SUITS.first(2).map { Card[_1, 'K'] }, | |
flush: | |
(0..RANKS.size).step(2).first(5).map { Card['S', RANKS[_1]] }, | |
straight: | |
[Card['H', RANKS.first], *RANKS[1..4].map { Card['S', _1] }], | |
three_of_a_kind: | |
CARDS.first(2) + | |
SUITS.first(3).map { Card[_1, 'A'] }, | |
two_pair: | |
CARDS.first(1) + | |
SUITS.first(2).flat_map { [Card[_1, 'A'], Card[_1, 'K']] }, | |
one_pair: | |
[CARDS[10], CARDS[15], CARDS[20], *SUITS.first(2).map { Card[_1, 'A'] }], | |
high_card: | |
[CARDS[10], CARDS[15], CARDS[20], CARDS[5], Card['S', 'A']] | |
}.freeze | |
SCORE_MAP = SCORES.invert | |
EXAMPLES.each do |hand_type, hand| | |
score = hand_score(hand) | |
correct_text = hand_type == SCORE_MAP[score] ? 'correct' : 'incorrect' | |
puts <<~OUT | |
Hand: #{Hand[hand]} (#{hand_type}) | |
Score: #{score} (#{correct_text}) | |
OUT | |
puts | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment