Created
December 14, 2010 19:05
-
-
Save jeffrydegrande/740892 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
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