Skip to content

Instantly share code, notes, and snippets.

@danielvlopes
Forked from jeffrydegrande/poker.rb
Created December 14, 2010 19:06
Show Gist options
  • Save danielvlopes/740894 to your computer and use it in GitHub Desktop.
Save danielvlopes/740894 to your computer and use it in GitHub Desktop.
require 'rubygems'
require 'test/unit'
require 'redgreen'
class Card
attr_reader :suite, :value
def initialize(options={})
@suite = options[:suite]
@value = options[:value]
end
def to_i
case value
when :ace then 14
when :king then 13
when :queen then 12
when :jack then 11
else
value
end
end
def self.of_spades
Card.new :suite => :spades, :value => value
end
def self.of_hearts
Card.new :suite => :hearts, :value => value
end
def self.of_clubs
Card.new :suite => :clubs, :value => value
end
def self.of_diamonds
Card.new :suite => :diamonds, :value => value
end
def self.has_value(value)
(class << self; self; end).instance_eval { define_method :value, lambda { value } }
end
end
class Two < Card; has_value 2; end
class Three < Card; has_value 3; end
class Four < Card; has_value 4; end
class Five < Card; has_value 5; end
class Six < Card; has_value 6; end
class Seven < Card; has_value 7; end
class Eight < Card; has_value 8; end
class Nine < Card; has_value 9; end
class Ten < Card; has_value 10; end
class Jack < Card; has_value 11; end
class Queen < Card; has_value 12; end
class King < Card; has_value 13; end
class Ace < Card; has_value 14; end
class Hand
attr_reader :cards
STRING_TRANSLATIONS = {
:royal_flush => "Royal Flush",
:straight_flush => "Straight Flush",
:four_of_a_kind => "Four Of a Kind",
:full_house => "Full House",
:flush => "Flush",
:straight => "Straight",
:three_of_a_kind => "Three Of a Kind",
:two_pair => "Two Pair",
:pair => "Pair",
:high_card => "High Card"
}
HAND_VALUES = [
:high_card,
:pair,
:two_pair,
:three_of_a_kind,
:straight,
:flush,
:full_house,
:four_of_a_kind,
:straight_flush,
:royal_flush
]
def <<(value)
@cards ||= []
@cards << value
end
def to_s
STRING_TRANSLATIONS[ranking]
end
def >(other)
Hand.calculate_value(self) > Hand.calculate_value(other)
end
def self.calculate_value(hand)
if hand.ranking == :high_card
hand.highest_card.to_i
else
HAND_VALUES.index(hand.ranking).to_i + 1000
end
end
def ranking
@ranking ||= detect_ranking!
end
def detect_ranking!
if is_royal_flush?
:royal_flush
elsif is_straight_flush?
:straight_flush
elsif is_four_of_a_kind?
:four_of_a_kind
elsif is_full_house?
:full_house
elsif is_flush?
:flush
elsif is_straight?
:straight
elsif is_three_of_a_kind?
:three_of_a_kind
elsif is_two_pair?
:two_pair
elsif is_pair?
:pair
else
:high_card
end
end
def is_royal_flush?
all_cards_in_same_suite? and values_of_cards_in_hand == [10, 11, 12, 13, 14]
end
def is_straight_flush?
all_cards_in_same_suite? and cards_in_hand_are_sequential?
end
def is_flush?
all_cards_in_same_suite?
end
def is_four_of_a_kind?
four_cards_of_same_rank?
end
def is_three_of_a_kind?
three_cards_of_same_rank?
end
def is_full_house?
three_cards_of_same_rank? and pair_of_same_rank?
end
def is_straight?
cards_in_hand_are_sequential?
end
def is_two_pair?
number_of_pairs_of_same_rank == 2
end
def is_pair?
pair_of_same_rank?
end
def four_cards_of_same_rank?
number_of_cards_of_same_rank.has_value?(4)
end
def three_cards_of_same_rank?
number_of_cards_of_same_rank.has_value?(3)
end
def pair_of_same_rank?
number_of_cards_of_same_rank.has_value?(2)
end
def number_of_pairs_of_same_rank
number_of_cards_of_same_rank.select { |k, v| v == 2 }.length
end
def number_of_cards_of_same_rank
@number_of_cards_of_same_rank ||= begin
h = Hash.new(0)
values_of_cards_in_hand.each do |v|
h.store(v, h[v] + 1)
end
h = h.delete_if { |key, value| value == 1 }
end
end
def cards_in_hand_are_sequential?
values_of_cards_in_hand == expected_sequence_for_hand
end
def expected_sequence_for_hand
first_card = values_of_cards_in_hand[0]
last_card = values_of_cards_in_hand[0] + 4
Array[*(first_card..last_card)]
end
def values_of_cards_in_hand
@values ||= @cards.map { |i| i.to_i }.sort
end
def highest_card
cards.sort do |a, b|
a.to_i <=> b.to_i
end.last
end
def all_cards_in_same_suite?
@all_cards_in_same_suite ||= cards.collect { |card| card.suite }.uniq.count == 1
end
end
class TestCard < Test::Unit::TestCase
def check_card(card, suite, value)
assert_equal value, card.to_i
assert_equal suite, card.suite
end
def test_cards_of_spades
check_card(Two.of_spades, :spades, 2)
check_card(Three.of_spades, :spades, 3)
check_card(Four.of_spades, :spades, 4)
check_card(Five.of_spades, :spades, 5)
check_card(Six.of_spades, :spades, 6)
check_card(Seven.of_spades, :spades, 7)
check_card(Eight.of_spades, :spades, 8)
check_card(Nine.of_spades, :spades, 9)
check_card(Ten.of_spades, :spades, 10)
check_card(Jack.of_spades, :spades, 11)
check_card(Queen.of_spades, :spades, 12)
check_card(King.of_spades, :spades, 13)
check_card(Ace.of_spades, :spades, 14)
end
def test_cards_of_hearts
check_card(Two.of_hearts, :hearts, 2)
check_card(Three.of_hearts, :hearts, 3)
check_card(Four.of_hearts, :hearts, 4)
check_card(Five.of_hearts, :hearts, 5)
check_card(Six.of_hearts, :hearts, 6)
check_card(Seven.of_hearts, :hearts, 7)
check_card(Eight.of_hearts, :hearts, 8)
check_card(Nine.of_hearts, :hearts, 9)
check_card(Ten.of_hearts, :hearts, 10)
check_card(Jack.of_hearts, :hearts, 11)
check_card(Queen.of_hearts, :hearts, 12)
check_card(King.of_hearts, :hearts, 13)
check_card(Ace.of_hearts, :hearts, 14)
end
def test_cards_of_clubs
check_card(Two.of_clubs, :clubs, 2)
check_card(Three.of_clubs, :clubs, 3)
check_card(Four.of_clubs, :clubs, 4)
check_card(Five.of_clubs, :clubs, 5)
check_card(Six.of_clubs, :clubs, 6)
check_card(Seven.of_clubs, :clubs, 7)
check_card(Eight.of_clubs, :clubs, 8)
check_card(Nine.of_clubs, :clubs, 9)
check_card(Ten.of_clubs, :clubs, 10)
check_card(Jack.of_clubs, :clubs, 11)
check_card(Queen.of_clubs, :clubs, 12)
check_card(King.of_clubs, :clubs, 13)
check_card(Ace.of_clubs, :clubs, 14)
end
def test_cards_of_clubs
check_card(Two.of_diamonds, :diamonds, 2)
check_card(Three.of_diamonds, :diamonds, 3)
check_card(Four.of_diamonds, :diamonds, 4)
check_card(Five.of_diamonds, :diamonds, 5)
check_card(Six.of_diamonds, :diamonds, 6)
check_card(Seven.of_diamonds, :diamonds, 7)
check_card(Eight.of_diamonds, :diamonds, 8)
check_card(Nine.of_diamonds, :diamonds, 9)
check_card(Ten.of_diamonds, :diamonds, 10)
check_card(Jack.of_diamonds, :diamonds, 11)
check_card(Queen.of_diamonds, :diamonds, 12)
check_card(King.of_diamonds, :diamonds, 13)
check_card(Ace.of_diamonds, :diamonds, 14)
end
end
class PokerTest < Test::Unit::TestCase
# :spades, :hearts, :diamonds, :clubs
# :ace, :king, :queen, :jack, 10 => 2
#
def make_royal_flush
hand = Hand.new
hand << Ten.of_spades
hand << Jack.of_spades
hand << Queen.of_spades
hand << King.of_spades
hand << Ace.of_spades
hand
end
def make_straight_flush
hand = Hand.new
hand << Two.of_spades
hand << Three.of_spades
hand << Four.of_spades
hand << Five.of_spades
hand << Six.of_spades
hand
end
def make_high_card
hand = Hand.new
hand << Two.of_spades
hand << Three.of_clubs
hand << Seven.of_diamonds
hand << Four.of_spades
hand << Six.of_hearts
hand
end
def make_four_of_a_kind
hand = Hand.new
hand << Jack.of_spades
hand << Jack.of_hearts
hand << Jack.of_diamonds
hand << Jack.of_clubs
hand << Queen.of_spades
hand
end
def make_full_house
hand = Hand.new
hand << Two.of_spades
hand << Two.of_hearts
hand << Two.of_diamonds
hand << Jack.of_clubs
hand << Jack.of_spades
hand
end
def make_flush
hand = Hand.new
hand << Two.of_spades
hand << Seven.of_spades
hand << King.of_spades
hand << Six.of_spades
hand << Jack.of_spades
hand
end
def make_pair
hand = Hand.new
hand << Two.of_spades
hand << Two.of_clubs
hand << Seven.of_diamonds
hand << Four.of_spades
hand << Six.of_hearts
hand
end
def test_royal_flush
hand = make_royal_flush
assert_equal "Royal Flush", hand.to_s
end
def test_royal_flush_with_mixed_suite
hand = Hand.new
hand << Ten.of_spades
hand << Jack.of_hearts
hand << Queen.of_spades
hand << King.of_spades
hand << Ace.of_spades
assert_not_equal "Royal Flush", hand.to_s
end
def test_royal_flush_unordered
hand = Hand.new
hand << Ace.of_spades
hand << Ten.of_spades
hand << King.of_spades
hand << Queen.of_spades
hand << Jack.of_spades
assert_equal "Royal Flush", hand.to_s
end
def test_royal_flush_fails_with_low_card
hand = Hand.new
hand << Two.of_spades
hand << Ten.of_spades
hand << King.of_spades
hand << Queen.of_spades
hand << Jack.of_spades
assert_not_equal "Royal Flush", hand.to_s
end
def test_straight_flush
hand = make_straight_flush
assert_equal "Straight Flush", hand.to_s
end
def test_another_straight_flush
hand = Hand.new
hand << Nine.of_hearts
hand << Ten.of_hearts
hand << Jack.of_hearts
hand << Queen.of_hearts
hand << King.of_hearts
assert_equal "Straight Flush", hand.to_s
end
def test_straight_flush_with_mixed_suites
hand = Hand.new
hand << Nine.of_spades
hand << Ten.of_hearts
hand << Jack.of_spades
hand << Queen.of_spades
hand << King.of_spades
assert_not_equal "Straight Flush", hand.to_s
end
def test_not_a_straight_flush
hand = Hand.new
hand << Eight.of_spades
hand << Ten.of_spades
hand << Jack.of_spades
hand << Queen.of_spades
hand << King.of_spades
assert_not_equal "Straight Flush", hand.to_s
end
def test_four_of_a_kind
hand = Hand.new
hand << Ten.of_spades
hand << Ten.of_hearts
hand << Ten.of_diamonds
hand << Ten.of_clubs
hand << Queen.of_spades
assert_equal "Four Of a Kind", hand.to_s
end
def test_four_of_a_kind
hand = Hand.new
hand << Two.of_spades
hand << Two.of_hearts
hand << Two.of_diamonds
hand << Two.of_clubs
hand << Queen.of_spades
assert_equal "Four Of a Kind", hand.to_s
end
def test_four_of_a_kind
hand = make_four_of_a_kind
assert_equal "Four Of a Kind", hand.to_s
end
def test_three_of_a_kind
hand = Hand.new
hand << Two.of_spades
hand << Two.of_hearts
hand << Two.of_diamonds
hand << Jack.of_clubs
hand << Queen.of_spades
assert_equal "Three Of a Kind", hand.to_s
end
def test_full_house
hand = make_full_house
assert_equal "Full House", hand.to_s
end
def test_a_flush
hand = make_flush
assert_equal "Flush", hand.to_s
end
def test_a_straight
hand = Hand.new
hand << Two.of_spades
hand << Three.of_clubs
hand << Four.of_diamonds
hand << Five.of_spades
hand << Six.of_hearts
assert_equal "Straight", hand.to_s
end
def test_two_pairs
hand = Hand.new
hand << Two.of_spades
hand << Two.of_clubs
hand << Four.of_diamonds
hand << Four.of_spades
hand << Six.of_hearts
assert_equal "Two Pair", hand.to_s
end
def test_pair
hand = make_pair
assert_equal "Pair", hand.to_s
end
def test_high_card
hand = make_high_card
assert_equal "High Card", hand.to_s
end
def test_royal_flush_beats_straight_flush
assert_operator make_royal_flush, :>, make_straight_flush
end
def test_straight_flush_beats_four_of_a_kind
assert_operator make_straight_flush, :>, make_four_of_a_kind
end
def test_four_of_a_kind_beats_full_house
assert_operator make_four_of_a_kind, :>, make_full_house
end
def test_full_house_beats_flush
assert_operator make_full_house, :>, make_flush
end
def test_pair_beats_high_card
assert_operator make_pair, :>, make_high_card
end
def test_high_card_beats_other_high_card_with_higher_value
mine = Hand.new
mine << Ace.of_clubs
mine << Two.of_clubs
mine << Three.of_hearts
mine << Four.of_hearts
mine << Six.of_clubs
assert_equal :high_card, mine.ranking
yours = Hand.new
yours << Eight.of_clubs
yours << Two.of_hearts
yours << Three.of_diamonds
yours << Seven.of_clubs
yours << Six.of_spades
assert_equal :high_card, yours.ranking
assert_operator mine, :>, yours
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment