Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@baweaver
Created January 28, 2021 19:53
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save baweaver/488beb90583bfd8fd5e56098b44e5687 to your computer and use it in GitHub Desktop.
Save baweaver/488beb90583bfd8fd5e56098b44e5687 to your computer and use it in GitHub Desktop.
Variant of pattern matching example from RubyGalaxy talk
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