Created
January 28, 2021 19:53
-
-
Save baweaver/488beb90583bfd8fd5e56098b44e5687 to your computer and use it in GitHub Desktop.
Variant of pattern matching example from RubyGalaxy talk
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
class Card | |
SUITS = %w(S H D C).freeze | |
RANKS = %w(2 3 4 5 6 7 8 9 10 J Q K A).freeze | |
RANKS_SCORES = RANKS.each_with_index.to_h | |
include Comparable | |
attr_reader :suit, :rank | |
def initialize(suit, rank) | |
@suit = suit | |
@rank = rank | |
end | |
def self.[](...) = new(...) | |
def self.from_str(s) = new(s[0], s[1..]) | |
def to_s() = "#{@suit}#{@rank}" | |
def to_a() = [@suit, @rank] | |
alias_method :deconstruct, :to_a | |
def precedence() = RANKS_SCORES[@rank] | |
def <=>(other) = precedence <=> other.precedence | |
def add_rank(n) = Card[@suit, RANKS[RANKS_SCORES[@rank] + n]] | |
def self.add_rank(rank, n) = RANKS[RANKS_SCORES[rank] + n] | |
end | |
class Hand | |
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 | |
SCORE_MAP = SCORES.invert | |
attr_reader :cards | |
def initialize(*cards) | |
@cards = cards.sort | |
end | |
def self.[](*cards) = new(*cards) | |
def self.from_str(s) = new(*s.split(/[ ,]+/).map { Card.from_str(_1) }) | |
def to_s() = @cards.map(&:to_s).join(', ') | |
def to_a() = @cards | |
alias_method :deconstruct, :to_a | |
def royal_flush? | |
@cards in [ | |
Card[suit, '10'], | |
Card[^suit, 'J'], | |
Card[^suit, 'Q'], | |
Card[^suit, 'K'], | |
Card[^suit, 'A'] | |
] | |
end | |
def straight_flush? | |
straight? && flush? | |
end | |
def straight? | |
@cards in [ | |
Card[_, rank], | |
Card[_, "#{Card.add_rank(rank, 1)}"], | |
Card[_, "#{Card.add_rank(rank, 2)}"], | |
Card[_, "#{Card.add_rank(rank, 3)}"], | |
Card[_, "#{Card.add_rank(rank, 4)}"], | |
] | |
end | |
def flush? | |
@cards in [ | |
Card[suit, _], | |
Card[^suit, _], | |
Card[^suit, _], | |
Card[^suit, _], | |
Card[^suit, _] | |
] | |
end | |
def four_of_a_kind? | |
@cards in [ | |
*, | |
Card[_, rank], | |
Card[_, ^rank], | |
Card[_, ^rank], | |
Card[_, ^rank], | |
* | |
] | |
end | |
def full_house? | |
return true if @cards in [ | |
Card[_, rank_one], | |
Card[_, ^rank_one], | |
Card[_, rank_two], | |
Card[_, ^rank_two], | |
Card[_, ^rank_two] | |
] | |
@cards in [ | |
Card[_, rank_one], | |
Card[_, ^rank_one], | |
Card[_, ^rank_one], | |
Card[_, rank_two], | |
Card[_, ^rank_two] | |
] | |
end | |
def three_of_a_kind? | |
@cards in [ | |
*, | |
Card[_, rank], | |
Card[_, ^rank], | |
Card[_, ^rank], | |
* | |
] | |
end | |
def two_pair? | |
return true if @cards in [ | |
Card[_, rank_one], | |
Card[_, ^rank_one], | |
*, | |
Card[_, rank_two], | |
Card[_, ^rank_two] | |
] | |
@cards in [ | |
*, | |
Card[_, rank_one], | |
Card[_, ^rank_one], | |
Card[_, rank_two], | |
Card[_, ^rank_two], | |
* | |
] | |
end | |
def one_pair? | |
@cards in [ | |
*, | |
Card[_, rank], | |
Card[_, ^rank], | |
* | |
] | |
end | |
def score | |
return SCORES[:royal_flush] if royal_flush? | |
return SCORES[:straight_flush] if straight_flush? | |
return SCORES[:four_of_a_kind] if four_of_a_kind? | |
return SCORES[:full_house] if full_house? | |
return SCORES[:flush] if flush? | |
return SCORES[:straight] if straight? | |
return SCORES[:three_of_a_kind] if three_of_a_kind? | |
return SCORES[:two_pair] if two_pair? | |
return SCORES[:one_pair] if one_pair? | |
SCORES[:high_card] | |
end | |
end | |
# --- Testing ------ | |
CARDS = Card::SUITS.flat_map { |suit| | |
Card::RANKS.map { |rank| Card[suit, rank] } | |
}.freeze | |
EXAMPLES = { | |
royal_flush: Hand.from_str('SA SK SQ SJ S10'), | |
straight_flush: Hand.from_str('S9 SK SQ SJ S10'), | |
four_of_a_kind: Hand.from_str('SA DA HA CA C2'), | |
full_house: Hand.from_str('SA CA HA HK DK'), | |
flush: Hand.from_str('S2 S4 S6 S8 S10'), | |
straight: Hand.from_str('H2 S3 D4 C5 D6'), | |
three_of_a_kind: Hand.from_str('HA DA CA D2 D4'), | |
two_pair: Hand.from_str('HA CA DK HK H3'), | |
one_pair: Hand.from_str('HA CA CK D3 C5'), | |
high_card: Hand.from_str('SA D2 C4 H8 CK'), | |
}.freeze | |
EXAMPLES.each do |hand_type, hand| | |
score = hand.score | |
correct_text = hand_type == Hand::SCORE_MAP[score] ? 'correct' : 'incorrect' | |
puts <<~OUT | |
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