Created
January 15, 2021 06:45
-
-
Save baweaver/f641a4d70e563c6dadf61b93c6faabf8 to your computer and use it in GitHub Desktop.
This time with a bit more gusto in the refactoring and care to remembering classes exist and things related to them should go in them
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 | |
SUITS_SCORES = SUITS.each_with_index.to_h | |
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.[](suit, rank) = new(suit, rank) | |
def to_a() = [@suit, @rank] | |
alias_method :deconstruct, :to_a | |
def precedence() = RANKS_SCORES[@rank] | |
def <=>(other) = precedence <=> other.precedence | |
def to_s() = "#{@suit}#{@rank}" | |
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 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: | |
Card::RANKS.last(5).map { Card['S', _1] }, | |
straight_flush: | |
Card::RANKS.first(5).map { Card['S', _1] }, | |
four_of_a_kind: [ | |
CARDS[0], | |
*Card::SUITS.map { Card[_1, 'A'] } | |
], | |
full_house: | |
Card::SUITS.first(3).map { Card[_1, 'A'] } + | |
Card::SUITS.first(2).map { Card[_1, 'K'] }, | |
flush: | |
(0..Card::RANKS.size) | |
.step(2) | |
.first(5) | |
.map { Card['S', Card::RANKS[_1]] }, | |
straight: [ | |
Card['H', Card::RANKS.first], | |
*Card::RANKS[1..4].map { Card['S', _1] } | |
], | |
three_of_a_kind: | |
CARDS.first(2) + | |
Card::SUITS.first(3).map { Card[_1, 'A'] }, | |
two_pair: | |
CARDS.first(1) + | |
Card::SUITS.first(2).flat_map { [Card[_1, 'A'], Card[_1, 'K']] }, | |
one_pair: [ | |
CARDS[10], | |
CARDS[15], | |
CARDS[20], | |
*Card::SUITS.first(2).map { Card[_1, 'A'] } | |
], | |
high_card: [ | |
CARDS[10], | |
CARDS[15], | |
CARDS[20], | |
CARDS[5], | |
Card['S', 'A'] | |
] | |
}.freeze | |
EXAMPLES.each do |hand_type, cards| | |
hand = Hand[*cards] | |
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