bakineggs-poker 1.3

Sign up to get free protection for your applications and to get access to all the features.
data/lib/card.rb ADDED
@@ -0,0 +1,68 @@
1
+ module Poker
2
+ class Card
3
+ include Comparable
4
+
5
+ SUITS_SHORTHAND = {
6
+ 'Spades' => 's',
7
+ 'Diamonds' => 'd',
8
+ 'Clubs' => 'c',
9
+ 'Hearts' => 'h'
10
+ }
11
+ SUITS = SUITS_SHORTHAND.keys
12
+ VALUES = {
13
+ 'Ace' => 14,
14
+ 'King' => 13,
15
+ 'Queen' => 12,
16
+ 'Jack' => 11,
17
+ '10' => 10,
18
+ '9' => 9,
19
+ '8' => 8,
20
+ '7' => 7,
21
+ '6' => 6,
22
+ '5' => 5,
23
+ '4' => 4,
24
+ '3' => 3,
25
+ '2' => 2,
26
+ }
27
+ FACES = VALUES.keys
28
+ FACES_SHORTHAND = {
29
+ 'Ace' => 'A',
30
+ 'King' => 'K',
31
+ 'Queen' => 'Q',
32
+ 'Jack' => 'J',
33
+ '10' => 'T',
34
+ '9' => '9',
35
+ '8' => '8',
36
+ '7' => '7',
37
+ '6' => '6',
38
+ '5' => '5',
39
+ '4' => '4',
40
+ '3' => '3',
41
+ '2' => '2'
42
+ }
43
+
44
+ attr_reader :value, :suit
45
+
46
+ def initialize suit_or_chars, face_or_value = nil
47
+ if face_or_value.nil?
48
+ raise ArgumentError unless suit_or_chars.length == 2
49
+ face_or_value = FACES_SHORTHAND.index(suit_or_chars[0, 1])
50
+ suit_or_chars = SUITS_SHORTHAND.index(suit_or_chars[1, 1])
51
+ end
52
+ self.suit = suit_or_chars
53
+ self.value = VALUES[face_or_value] || face_or_value
54
+ raise ArgumentError unless SUITS.include?(suit_or_chars) && VALUES.has_value?(value)
55
+ end
56
+
57
+ def face
58
+ VALUES.index(value)
59
+ end
60
+
61
+ def <=> other_card
62
+ value <=> other_card.value
63
+ end
64
+
65
+ private
66
+ attr_writer :value, :suit
67
+ end
68
+ end
data/lib/deck.rb ADDED
@@ -0,0 +1,28 @@
1
+ module Poker
2
+ class Deck
3
+ attr_reader :cards
4
+
5
+ def initialize
6
+ @cards = Card::SUITS.map do |suit|
7
+ Card::FACES.map do |value|
8
+ Card.new(suit, value)
9
+ end
10
+ end.flatten
11
+ @card_index = 0
12
+ end
13
+
14
+ def shuffle
15
+ @cards = @cards.sort_by {rand}
16
+ @card_index = 0
17
+ self
18
+ end
19
+
20
+ def next(quantity = 1)
21
+ raise IndexError if @card_index + quantity > 52
22
+ @cards[@card_index...(@card_index += quantity)]
23
+ end
24
+
25
+ private
26
+ attr_writer :cards
27
+ end
28
+ end
data/lib/hand.rb ADDED
@@ -0,0 +1,164 @@
1
+ module Poker
2
+ class Hand
3
+ include Comparable
4
+ attr_reader :cards
5
+
6
+ def initialize *params
7
+ @cards = params.map do |param|
8
+ if param.is_a? Hand
9
+ param.cards
10
+ elsif param.is_a? Card
11
+ param
12
+ elsif param.is_a? String
13
+ param.split(' ').map {|str| Card.new str}
14
+ end
15
+ end.flatten.uniq.sort.reverse
16
+ end
17
+
18
+ def straight_flush?
19
+ @straight_flush ||= suited_cards.any? do |cards|
20
+ Hand.new(*cards).straight?
21
+ end
22
+ end
23
+
24
+ def quads?
25
+ @quads ||= matched_cards.any? do |cards|
26
+ cards.length >= 4
27
+ end
28
+ end
29
+
30
+ def full_house?
31
+ @full_house ||= set? && two_pair?
32
+ end
33
+
34
+ def flush?
35
+ @flush ||= suited_cards.any? do |cards|
36
+ cards.length >= 5
37
+ end
38
+ end
39
+
40
+ def straight?
41
+ @straight ||= !straight_cards.empty?
42
+ end
43
+
44
+ def set?
45
+ @set ||= matched_cards.any? do |cards|
46
+ cards.length >= 3
47
+ end
48
+ end
49
+
50
+ def two_pair?
51
+ @two_pair ||= matched_cards.length >= 2
52
+ end
53
+
54
+ def pair?
55
+ @pair ||= matched_cards.length >= 1
56
+ end
57
+
58
+ def four_to_flush?
59
+ @four_to_flush ||= suited_cards.any? do |cards|
60
+ cards.length >= 4
61
+ end
62
+ end
63
+
64
+ def open_ended?
65
+ @open_ended ||= straight_cards(4).any? do |cards|
66
+ cards.first.face != 'Ace' && cards.last.face != 'Ace'
67
+ end
68
+ end
69
+
70
+ def gutshot?
71
+ @gutshot ||= !gutshot_cards.empty?
72
+ end
73
+
74
+ def double_gutshot?
75
+ @double_gutshot ||= gutshot_cards.length >= 2
76
+ end
77
+
78
+ def <=> other_hand
79
+ return rank <=> other_hand.rank unless rank == other_hand.rank
80
+ return 0 if tie_breaker == other_hand.tie_breaker
81
+ tie_breaker.each_with_index do |card, i|
82
+ compared = card.value <=> other_hand.tie_breaker[i].value
83
+ return compared unless compared == 0
84
+ end
85
+ end
86
+
87
+ protected
88
+ def rank
89
+ @rank ||= if straight_flush?: 8
90
+ elsif quads?: 7
91
+ elsif full_house?: 6
92
+ elsif flush?: 5
93
+ elsif straight?: 4
94
+ elsif set?: 3
95
+ elsif two_pair?: 2
96
+ elsif pair?: 1
97
+ else; 0
98
+ end
99
+ end
100
+
101
+ def tie_breaker
102
+ @tie_breaker ||= if flush?
103
+ Hand.new(*suited_cards.find{|cards| cards.length >= 5}).unsuited!.tie_breaker
104
+ elsif quads?
105
+ quads = matched_cards.find{|cards| cards.length == 4}
106
+ quads + [(@cards - quads).first]
107
+ elsif full_house?
108
+ set = matched_cards.find{|cards| cards.length == 3}
109
+ set + (matched_cards - [set]).first.first(2)
110
+ elsif straight?
111
+ [straight_cards.last.last]
112
+ elsif set?
113
+ set = matched_cards.first
114
+ set + (@cards - set).first(2)
115
+ elsif two_pair?
116
+ two_pair = matched_cards.first(2).flatten
117
+ two_pair + [(@cards - two_pair).first]
118
+ elsif pair?
119
+ pair = matched_cards.first
120
+ pair + (@cards - pair).first(3)
121
+ else
122
+ @cards.first(5)
123
+ end
124
+ end
125
+
126
+ def unsuited!
127
+ @suited_cards = []
128
+ self
129
+ end
130
+
131
+ private
132
+ def matched_cards
133
+ @matched_cards ||= @cards.map{|card| card.value}.uniq.map do |value|
134
+ cards = @cards.select{|card| card.value == value}
135
+ cards.length > 1 ? cards : nil
136
+ end.compact
137
+ end
138
+
139
+ def suited_cards
140
+ @suited_cards ||= @cards.map{|card| card.suit}.uniq.map do |suit|
141
+ @cards.select{|card| card.suit == suit}
142
+ end
143
+ end
144
+
145
+ def straight_cards(length = 5)
146
+ @straight_cards ||= {}
147
+ @straight_cards[length] ||= (1..14-(length-1)).map do |low| # straight can start at a low ace up to a 10
148
+ high = low + (length - 1)
149
+ cards = (low..high).map do |value|
150
+ @cards.find{|card| card.value % 13 == value % 13} # %13 allows an ace to be high or low
151
+ end.compact
152
+ end.select{|cards| cards.length == length}
153
+ end
154
+
155
+ def gutshot_cards
156
+ @gutshot_cards ||= (1..10).map do |low|
157
+ high = low + 4
158
+ (low..high).reject do |value|
159
+ @cards.find{|card| card.value % 13 == value % 13}
160
+ end
161
+ end.reject{|cards| cards.length != 1}.uniq.flatten
162
+ end
163
+ end
164
+ end
data/lib/poker.rb ADDED
@@ -0,0 +1,3 @@
1
+ require File.dirname(__FILE__) + '/card'
2
+ require File.dirname(__FILE__) + '/hand'
3
+ require File.dirname(__FILE__) + '/deck'
data/spec/card_spec.rb ADDED
@@ -0,0 +1,111 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ module Poker
4
+ describe Card, '#new' do
5
+ it 'should accept the four suits' do
6
+ lambda {
7
+ ['Spades', 'Diamonds', 'Clubs', 'Hearts'].each do |suit|
8
+ Card.new(suit, 'Ace')
9
+ end
10
+ }.should_not raise_error
11
+ end
12
+
13
+ it 'should reject unknown suits' do
14
+ lambda { Card.new('Rubies', 'Ace') }.should raise_error(ArgumentError)
15
+ end
16
+
17
+ it 'should accept a string of a card name' do
18
+ lambda {
19
+ Card.new('Spades', 'Ace')
20
+ Card.new('Spades', 'King')
21
+ Card.new('Spades', 'Queen')
22
+ Card.new('Spades', 'Jack')
23
+ (2..10).each do |value|
24
+ Card.new('Spades', value.to_s)
25
+ end
26
+ }.should_not raise_error
27
+ end
28
+
29
+ it 'should accept short representations of a card' do
30
+ faces = {'Ace' => 'A', 'King' => 'K', 'Queen' => 'Q', 'Jack' => 'J', '10' => 'T'}
31
+ (2..9).each {|value| faces[value.to_s] = value.to_s }
32
+ {'Spades' => 's', 'Diamonds' => 'd', 'Clubs' => 'c', 'Hearts' => 'h'}.each do |suit, suit_short|
33
+ faces.each do |face, face_short|
34
+ Card.new("#{face_short}#{suit_short}").should == Card.new(suit, face)
35
+ end
36
+ end
37
+ end
38
+
39
+ it 'should reject unknown short representations' do
40
+ lambda { Card.new 'Ar' }.should raise_error(ArgumentError)
41
+ lambda { Card.new '1s' }.should raise_error(ArgumentError)
42
+ lambda { Card.new '11s' }.should raise_error(ArgumentError)
43
+ lambda { Card.new 'AsJc' }.should raise_error(ArgumentError)
44
+ end
45
+
46
+ it 'should reject unknown card names' do
47
+ lambda { Card.new('Spades', '1') }.should raise_error(ArgumentError)
48
+ lambda { Card.new('Spades', '11') }.should raise_error(ArgumentError)
49
+ lambda { Card.new('Spades', 'Joker') }.should raise_error(ArgumentError)
50
+ end
51
+
52
+ it 'should accept card values' do
53
+ lambda {
54
+ (2..14).each do |value|
55
+ Card.new('Spades', value)
56
+ end
57
+ }.should_not raise_error
58
+ end
59
+
60
+ it 'should consider cards made by face and value the same' do
61
+ Card.new('Spades', 'Ace').should == Card.new('Spades', 14)
62
+ Card.new('Spades', 'King').should == Card.new('Spades', 13)
63
+ Card.new('Spades', 'Queen').should == Card.new('Spades', 12)
64
+ Card.new('Spades', 'Jack').should == Card.new('Spades', 11)
65
+ (2..10).each do |value|
66
+ Card.new('Spades', value.to_s).should == Card.new('Spades', value)
67
+ end
68
+ end
69
+
70
+ it 'should reject values outside the range' do
71
+ lambda { Card.new('Spades', 1) }.should raise_error(ArgumentError)
72
+ lambda { Card.new('Spades', 15) }.should raise_error(ArgumentError)
73
+ end
74
+ end
75
+
76
+ describe Card, '#face' do
77
+ it 'should return the face for that card' do
78
+ Card.new('Spades', 'Ace').face.should == 'Ace'
79
+ Card.new('Spades', 'King').face.should == 'King'
80
+ Card.new('Spades', 'Queen').face.should == 'Queen'
81
+ Card.new('Spades', 'Jack').face.should == 'Jack'
82
+ (2..10).each do |value|
83
+ Card.new('Spades', value).face.should == value.to_s
84
+ end
85
+ end
86
+ end
87
+
88
+ describe Card, '#value' do
89
+ it 'should return the value for that card' do
90
+ Card.new('Spades', 'Ace').value.should == 14
91
+ Card.new('Spades', 'King').value.should == 13
92
+ Card.new('Spades', 'Queen').value.should == 12
93
+ Card.new('Spades', 'Jack').value.should == 11
94
+ (2..10).each do |value|
95
+ Card.new('Spades', value).value.should == value
96
+ end
97
+ end
98
+ end
99
+
100
+ describe Card, '#<=>' do
101
+ it 'should order the cards by value' do
102
+ Card.new('Spades', 'Ace').should > Card.new('Spades', 'King')
103
+ Card.new('Spades', 'King').should > Card.new('Spades', 'Queen')
104
+ Card.new('Spades', 'Queen').should > Card.new('Spades', 'Jack')
105
+ Card.new('Spades', 'Jack').should > Card.new('Spades', '10')
106
+ (2..9).each do |value|
107
+ Card.new('Spades', value+1).should > Card.new('Spades', value)
108
+ end
109
+ end
110
+ end
111
+ end
data/spec/deck_spec.rb ADDED
@@ -0,0 +1,50 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ module Poker
4
+ describe Deck, '#next' do
5
+ it 'should give you the number of cards you ask for' do
6
+ count = rand 10
7
+ Deck.new.next(count).length.should == count
8
+ end
9
+
10
+ it 'should give 1 card by default' do
11
+ Deck.new.next.length.should == 1
12
+ end
13
+
14
+ it 'should not give out the same card twice' do
15
+ Deck.new.next(52).uniq.length.should == 52
16
+ end
17
+
18
+ it 'should not give out the same card(s) on subsequent calls' do
19
+ deck = Deck.new
20
+ count = rand(10)+1
21
+ deck.next(count).should_not == deck.next(count)
22
+ end
23
+
24
+ it 'should eventually run out of cards' do
25
+ lambda {
26
+ Deck.new.next(53)
27
+ }.should raise_error(IndexError)
28
+ lambda {
29
+ deck = Deck.new
30
+ deck.next 40
31
+ deck.next 13
32
+ }.should raise_error(IndexError)
33
+ end
34
+ end
35
+
36
+ describe Deck, '#shuffle' do
37
+ it 'should allow you to take out more cards' do
38
+ deck = Deck.new
39
+ deck.next 52
40
+ lambda {
41
+ deck.shuffle.next 52
42
+ }.should_not raise_error
43
+ end
44
+
45
+ it 'should change the order of the cards' do
46
+ deck = Deck.new
47
+ deck.next(52).should_not == deck.shuffle.next(52)
48
+ end
49
+ end
50
+ end
data/spec/hand_spec.rb ADDED
@@ -0,0 +1,656 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ module Poker
4
+ describe Hand, '#new' do
5
+ before do
6
+ @cards = [
7
+ Card.new('Hearts', '6'),
8
+ Card.new('Spades', 'Queen'),
9
+ Card.new('Diamonds', '4'),
10
+ Card.new('Clubs', '7'),
11
+ Card.new('Diamonds', 'Jack'),
12
+ Card.new('Spades', '8')
13
+ ]
14
+ end
15
+
16
+ it 'should contain the given cards' do
17
+ Hand.new(*@cards).cards.sort.should == @cards.sort
18
+ end
19
+
20
+ it 'should contain the cards in any given hands' do
21
+ Hand.new(Hand.new(*@cards[0..2]), Hand.new(*@cards[3..5])).cards.sort.should == @cards.sort
22
+ end
23
+
24
+ it 'should accept a combination of hands and cards' do
25
+ Hand.new(Hand.new(*@cards[0..2]), *@cards[3..5]).cards.sort.should == @cards.sort
26
+ end
27
+
28
+ it 'should ignore the same card if given twice' do
29
+ Hand.new(@cards[3], *@cards).cards.sort.should == @cards.sort
30
+ end
31
+
32
+ it 'should ignore the same card if given in two hands' do
33
+ Hand.new(Hand.new(*@cards[0..3]), Hand.new(*@cards[2..5])).cards.sort.should == @cards.sort
34
+ end
35
+
36
+ it 'should ignore the same card if given in a combo of cards and hands' do
37
+ Hand.new(Hand.new(*@cards[0..3]), *@cards[2..5]).cards.sort.should == @cards.sort
38
+ end
39
+
40
+ it 'should accept a string of card values' do
41
+ Hand.new('6h Qs 4d 7c Jc 8s').should == Hand.new(*@cards)
42
+ end
43
+
44
+ it 'should accept string of card calues intermixed with cards and hands' do
45
+ Hand.new('7c Jc', Hand.new(@cards[5]), *@cards[0..2]).should == Hand.new(*@cards)
46
+ end
47
+ end
48
+
49
+ describe Hand do
50
+ before do
51
+ @straight_flush = Hand.new '6s 5s 9s 7s 8s'
52
+ @quads = Hand.new '6h 6s 6c 7s 6d'
53
+ @full_house = Hand.new '6s 6h 6d 7s 7c'
54
+ @flush = Hand.new '6s Qs 3s 7s 8s'
55
+ @straight = Hand.new '6s 5c 9s 7d 8h'
56
+ @set = Hand.new '6s 6h 9s 6c 8d'
57
+ @two_pair = Hand.new '6s 5h 6c 5d 8s'
58
+ @pair = Hand.new '6h 5s 8c 7d 8s'
59
+ @high_card = Hand.new '6h Qs 4d 7c Jd'
60
+ end
61
+
62
+ describe 'straight flush' do
63
+ it 'should be a straight flush' do
64
+ @straight_flush.should be_straight_flush
65
+ end
66
+
67
+ it 'should be a flush' do
68
+ @straight_flush.should be_flush
69
+ end
70
+
71
+ it 'should be a straight' do
72
+ @straight_flush.should be_straight
73
+ end
74
+
75
+ it 'should not be anything else' do
76
+ @straight_flush.should_not be_pair
77
+ @straight_flush.should_not be_two_pair
78
+ @straight_flush.should_not be_set
79
+ @straight_flush.should_not be_full_house
80
+ @straight_flush.should_not be_quads
81
+ end
82
+
83
+ describe 'wheel' do
84
+ it 'should be a straight flush' do
85
+ Hand.new(
86
+ Card.new('Spades', 'Ace'),
87
+ Card.new('Spades', '2'),
88
+ Card.new('Spades', '3'),
89
+ Card.new('Spades', '4'),
90
+ Card.new('Spades', '5')
91
+ ).should be_straight_flush
92
+ end
93
+ end
94
+ end
95
+
96
+ describe 'quads' do
97
+ it 'should be quads' do
98
+ @quads.should be_quads
99
+ end
100
+
101
+ it 'should be a set' do
102
+ @quads.should be_set
103
+ end
104
+
105
+ it 'should be a pair' do
106
+ @quads.should be_set
107
+ end
108
+
109
+ it 'should not be anything else' do
110
+ @quads.should_not be_two_pair
111
+ @quads.should_not be_straight
112
+ @quads.should_not be_flush
113
+ @quads.should_not be_full_house
114
+ @quads.should_not be_straight_flush
115
+ end
116
+ end
117
+
118
+ describe 'full house' do
119
+ it 'should be a full house' do
120
+ @full_house.should be_full_house
121
+ end
122
+
123
+ it 'should be a set' do
124
+ @full_house.should be_set
125
+ end
126
+
127
+ it 'should be two pair' do
128
+ @full_house.should be_two_pair
129
+ end
130
+
131
+ it 'should be a pair' do
132
+ @full_house.should be_pair
133
+ end
134
+
135
+ it 'should not be anything else' do
136
+ @full_house.should_not be_straight
137
+ @full_house.should_not be_flush
138
+ @full_house.should_not be_quads
139
+ @full_house.should_not be_straight_flush
140
+ end
141
+ end
142
+
143
+ describe 'flush' do
144
+ it 'should be a flush' do
145
+ @flush.should be_flush
146
+ end
147
+
148
+ it 'should not be anything else' do
149
+ @flush.should_not be_pair
150
+ @flush.should_not be_two_pair
151
+ @flush.should_not be_set
152
+ @flush.should_not be_straight
153
+ @flush.should_not be_full_house
154
+ @flush.should_not be_quads
155
+ @flush.should_not be_straight_flush
156
+ end
157
+ end
158
+
159
+ describe 'straight' do
160
+ it 'should be a straight' do
161
+ @straight.should be_straight
162
+ end
163
+
164
+ it 'should not be anything else' do
165
+ @straight.should_not be_pair
166
+ @straight.should_not be_two_pair
167
+ @straight.should_not be_set
168
+ @straight.should_not be_flush
169
+ @straight.should_not be_full_house
170
+ @straight.should_not be_quads
171
+ @straight.should_not be_straight_flush
172
+ end
173
+
174
+ describe 'wheel' do
175
+ it 'should be a straight' do
176
+ Hand.new(
177
+ Card.new('Spades', 'Ace'),
178
+ Card.new('Clubs', '2'),
179
+ Card.new('Spades', '3'),
180
+ Card.new('Hearts', '4'),
181
+ Card.new('Diamonds', '5')
182
+ ).should be_straight
183
+ end
184
+ end
185
+ end
186
+
187
+ describe 'set' do
188
+ it 'should be a set' do
189
+ @set.should be_set
190
+ end
191
+
192
+ it 'should be a pair' do
193
+ @set.should be_pair
194
+ end
195
+
196
+ it 'should not be anything else' do
197
+ @set.should_not be_two_pair
198
+ @set.should_not be_straight
199
+ @set.should_not be_flush
200
+ @set.should_not be_full_house
201
+ @set.should_not be_quads
202
+ @set.should_not be_straight_flush
203
+ end
204
+ end
205
+
206
+ describe 'two pair' do
207
+ it 'should be two pair' do
208
+ @two_pair.should be_two_pair
209
+ end
210
+
211
+ it 'should be a pair' do
212
+ @two_pair.should be_pair
213
+ end
214
+
215
+ it 'should not be anything else' do
216
+ @two_pair.should_not be_set
217
+ @two_pair.should_not be_straight
218
+ @two_pair.should_not be_flush
219
+ @two_pair.should_not be_full_house
220
+ @two_pair.should_not be_quads
221
+ @two_pair.should_not be_straight_flush
222
+ end
223
+ end
224
+
225
+ describe 'pair' do
226
+ it 'should be a pair' do
227
+ @pair.should be_pair
228
+ end
229
+
230
+ it 'should not be anything else' do
231
+ @pair.should_not be_two_pair
232
+ @pair.should_not be_set
233
+ @pair.should_not be_straight
234
+ @pair.should_not be_flush
235
+ @pair.should_not be_full_house
236
+ @pair.should_not be_quads
237
+ @pair.should_not be_full_house
238
+ end
239
+ end
240
+
241
+ describe 'high card' do
242
+ it 'should not be anything else' do
243
+ @high_card.should_not be_pair
244
+ @high_card.should_not be_two_pair
245
+ @high_card.should_not be_set
246
+ @high_card.should_not be_straight
247
+ @high_card.should_not be_flush
248
+ @high_card.should_not be_full_house
249
+ @high_card.should_not be_quads
250
+ @high_card.should_not be_straight_flush
251
+ end
252
+ end
253
+
254
+ describe 'straight and flush' do
255
+ before do
256
+ @straight_and_flush = Hand.new 'As Ts 9s 8c 7s 6s'
257
+ end
258
+
259
+ it 'should be a straight' do
260
+ @straight_and_flush.should be_straight
261
+ end
262
+
263
+ it 'should be a flush' do
264
+ @straight_and_flush.should be_flush
265
+ end
266
+
267
+ it 'should not be a straight flush' do
268
+ @straight_and_flush.should_not be_straight_flush
269
+ end
270
+ end
271
+
272
+ describe 'four to flush' do
273
+ before do
274
+ @four_to_flush = Hand.new 'As Ts 8c 7s 6s'
275
+ end
276
+
277
+ it 'should be four to a flush' do
278
+ @four_to_flush.should be_four_to_flush
279
+ end
280
+
281
+ it 'should not be a flush' do
282
+ @four_to_flush.should_not be_flush
283
+ end
284
+ end
285
+
286
+ describe 'open ended' do
287
+ before do
288
+ @open_ended = Hand.new 'As 9s 8c 7s 6s'
289
+ end
290
+
291
+ it 'should be open ended' do
292
+ @open_ended.should be_open_ended
293
+ end
294
+
295
+ it 'should not be a straight' do
296
+ @open_ended.should_not be_straight
297
+ end
298
+
299
+ it 'should not include Ace through 4' do
300
+ Hand.new('As 2c 3s 4h 8d').should_not be_open_ended
301
+ end
302
+
303
+ it 'should not include Jack through Ace' do
304
+ Hand.new('As Kc Qs Jh 8d').should_not be_open_ended
305
+ end
306
+ end
307
+
308
+ describe 'gutshot' do
309
+ it 'should include 1-card gaps between 1 card and 3 others' do
310
+ Hand.new('Js 2c 5s 4h 6d').should be_gutshot
311
+ end
312
+
313
+ it 'should include 1-card gaps between 2 cards and 2 others' do
314
+ Hand.new('Js 2c 5s 3h 6d').should be_gutshot
315
+ end
316
+
317
+ it 'should include 1-card gaps between 3 cards and 1 other' do
318
+ Hand.new('Js 2c 3s 4h 6d').should be_gutshot
319
+ end
320
+
321
+ it 'should include Ace through 4' do
322
+ Hand.new('As 2c 3s 4h 8d').should be_gutshot
323
+ end
324
+
325
+ it 'should include Jack through Ace' do
326
+ Hand.new('As Kc Qs Jh 8d').should be_gutshot
327
+ end
328
+ end
329
+
330
+ describe 'double gutshot' do
331
+ it 'should include 2 1-card gaps between 1, 3, and 1 cards' do
332
+ Hand.new('4s 6c 7s 8h Td').should be_double_gutshot
333
+ end
334
+
335
+ it 'should include 2 1-card gaps between 2, 2, and 2 cards' do
336
+ Hand.new('4s 5c 7s 8h Td Jh').should be_double_gutshot
337
+ end
338
+
339
+ it 'should include 2 1-card gaps between 3, 1, and 3 cards' do
340
+ Hand.new('4s 5c 6s 8h Td Jh Qc').should be_double_gutshot
341
+ end
342
+
343
+ it 'should not include 2-card gaps between 2 cards and 3 cards' do
344
+ Hand.new('4s 5c 8s 9h Td').should_not be_double_gutshot
345
+ end
346
+
347
+ it 'should not include 2-card gaps between 3 cards and 2 cards' do
348
+ Hand.new('4s 5c 6s 9h Td').should_not be_double_gutshot
349
+ end
350
+
351
+ it 'should not include 1-card gaps between 3 cards and 3 cards' do
352
+ Hand.new('4s 5c 6s 8c 9h Td').should_not be_double_gutshot
353
+ end
354
+ end
355
+
356
+ describe 'rankings' do
357
+ before do
358
+ @highest_quads = Hand.new 'Ac Ah As Ad Kh'
359
+ @highest_full_house = Hand.new 'Ac Ah As Kd Kh'
360
+ @highest_flush = Hand.new 'Ac Kc Qc Jc 9c'
361
+ @highest_straight = Hand.new 'Ac Kh Qs Jd Th'
362
+ @highest_set = Hand.new 'Ac Ah As Kd Qh'
363
+ @highest_two_pair = Hand.new 'Ac Ah Ks Kd Qh'
364
+ @highest_pair = Hand.new 'Ah Ad Ks Qd Jc'
365
+ @highest_high_card = Hand.new 'Ah Ks Qd Jc 9d'
366
+ end
367
+
368
+ describe 'straight flush' do
369
+ before do
370
+ @highest_straight_flush = Hand.new 'Ac Kc Qc Jc Tc'
371
+ @lowest_straight_flush = Hand.new 'Ac 2c 3c 4c 5c'
372
+ end
373
+
374
+ it 'should beat a smaller straight flush' do
375
+ @highest_straight_flush.should > @straight_flush
376
+ @straight_flush.should > @lowest_straight_flush
377
+ end
378
+
379
+ it 'should beat any quads' do
380
+ @lowest_straight_flush.should > @highest_quads
381
+ end
382
+
383
+ it 'should beat any full house' do
384
+ @lowest_straight_flush.should > @highest_full_house
385
+ end
386
+
387
+ it 'should beat any flush' do
388
+ @lowest_straight_flush.should > @highest_flush
389
+ end
390
+
391
+ it 'should beat any straight' do
392
+ @lowest_straight_flush.should > @highest_straight
393
+ end
394
+
395
+ it 'should beat any set' do
396
+ @lowest_straight_flush.should > @highest_set
397
+ end
398
+
399
+ it 'should beat any two pair' do
400
+ @lowest_straight_flush.should > @highest_two_pair
401
+ end
402
+
403
+ it 'should beat any pair' do
404
+ @lowest_straight_flush.should > @highest_pair
405
+ end
406
+
407
+ it 'should beat any high card' do
408
+ @lowest_straight_flush.should > @highest_high_card
409
+ end
410
+ end
411
+
412
+ describe 'quads' do
413
+ before do
414
+ @lowest_quads = Hand.new '2c 2h 2s 2d 3h'
415
+ end
416
+
417
+ it 'should beat smaller quads' do
418
+ @highest_quads.should > @quads
419
+ @quads.should > @lowest_quads
420
+ end
421
+
422
+ it 'should beat any full house' do
423
+ @lowest_quads.should > @highest_full_house
424
+ end
425
+
426
+ it 'should beat any flush' do
427
+ @lowest_quads.should > @highest_flush
428
+ end
429
+
430
+ it 'should beat any straight' do
431
+ @lowest_quads.should > @highest_straight
432
+ end
433
+
434
+ it 'should beat any set' do
435
+ @lowest_quads.should > @highest_set
436
+ end
437
+
438
+ it 'should beat any two pair' do
439
+ @lowest_quads.should > @highest_two_pair
440
+ end
441
+
442
+ it 'should beat any pair' do
443
+ @lowest_quads.should > @highest_pair
444
+ end
445
+
446
+ it 'should beat any high card' do
447
+ @lowest_quads.should > @highest_high_card
448
+ end
449
+
450
+ it 'should consider the quads first' do
451
+ Hand.new('Ac Ah As Ad 2h').should > Hand.new('Kc Kh Ks Kd Qh')
452
+ end
453
+
454
+ it 'should consider the kicker if the quads are the same' do
455
+ Hand.new('Ac Ah As Ad Qh').should > Hand.new('Ac Ah As Ad Jh')
456
+ end
457
+ end
458
+
459
+ describe 'full house' do
460
+ before do
461
+ @lowest_full_house = Hand.new '2c 2h 2s 3d 3h'
462
+ end
463
+
464
+ it 'should beat a smaller full house' do
465
+ @highest_full_house.should > @full_house
466
+ @full_house.should > @lowest_full_house
467
+ end
468
+
469
+ it 'should beat any flush' do
470
+ @lowest_full_house.should > @highest_flush
471
+ end
472
+
473
+ it 'should beat any straight' do
474
+ @lowest_full_house.should > @highest_straight
475
+ end
476
+
477
+ it 'should beat any set' do
478
+ @lowest_full_house.should > @highest_set
479
+ end
480
+
481
+ it 'should beat any two pair' do
482
+ @lowest_full_house.should > @highest_two_pair
483
+ end
484
+
485
+ it 'should beat any pair' do
486
+ @lowest_full_house.should > @highest_pair
487
+ end
488
+
489
+ it 'should beat any high card' do
490
+ @lowest_full_house.should > @highest_high_card
491
+ end
492
+
493
+ it 'should consider the set first' do
494
+ Hand.new('Ac Ah As 2d 2h').should > Hand.new('Kc Kh Ks Qd Qh')
495
+ end
496
+
497
+ it 'should consider the pair if the set is the same' do
498
+ Hand.new('Ac Ah As Qd Qh').should > Hand.new('Ac Ah As Jd Jh')
499
+ end
500
+ end
501
+
502
+ describe 'flush' do
503
+ before do
504
+ @lowest_flush = Hand.new '2c 3c 4c 5c 7c'
505
+ end
506
+
507
+ it 'should beat a smaller flush' do
508
+ @highest_flush.should > @flush
509
+ @flush.should > @lowest_flush
510
+ end
511
+
512
+ it 'should beat any straight' do
513
+ @lowest_flush.should > @highest_straight
514
+ end
515
+
516
+ it 'should beat any set' do
517
+ @lowest_flush.should > @highest_set
518
+ end
519
+
520
+ it 'should beat any two pair' do
521
+ @lowest_flush.should > @highest_two_pair
522
+ end
523
+
524
+ it 'should beat any pair' do
525
+ @lowest_flush.should > @highest_pair
526
+ end
527
+
528
+ it 'should beat any high card' do
529
+ @lowest_flush.should > @highest_high_card
530
+ end
531
+
532
+ it 'should compare the highest cards in the flush' do
533
+ Hand.new('As Ks 4s 3s 2s').should > Hand.new('As Qs Js Ts 9s')
534
+ end
535
+ end
536
+
537
+ describe 'straight' do
538
+ before do
539
+ @lowest_straight = Hand.new 'Ac 2h 3s 4d 5h'
540
+ end
541
+
542
+ it 'should beat a smaller straight' do
543
+ @highest_straight.should > @straight
544
+ @straight.should > @lowest_straight
545
+ end
546
+
547
+ it 'should beat any set' do
548
+ @lowest_straight.should > @highest_set
549
+ end
550
+
551
+ it 'should beat any two pair' do
552
+ @lowest_straight.should > @highest_two_pair
553
+ end
554
+
555
+ it 'should beat any pair' do
556
+ @lowest_straight.should > @highest_pair
557
+ end
558
+
559
+ it 'should beat any high card' do
560
+ @lowest_straight.should > @highest_high_card
561
+ end
562
+ end
563
+
564
+ describe 'set' do
565
+ before do
566
+ @lowest_set = Hand.new '2s 2c 2h 3d 4c'
567
+ end
568
+
569
+ it 'should beat a smaller set' do
570
+ @highest_set.should > @set
571
+ @set.should > @lowest_set
572
+ end
573
+
574
+ it 'should beat any two pair' do
575
+ @lowest_set.should > @highest_two_pair
576
+ end
577
+
578
+ it 'should beat any pair' do
579
+ @lowest_set.should > @highest_pair
580
+ end
581
+
582
+ it 'should beat any high card' do
583
+ @lowest_set.should > @highest_high_card
584
+ end
585
+
586
+ it 'should beat smaller sets' do
587
+ Hand.new('7s 7c 7d 2h 3c').should > Hand.new('6s 6c 6d Kh Ac')
588
+ end
589
+
590
+ it 'should beat smaller kickers' do
591
+ Hand.new('7s 7c 7d Ah Jc').should > Hand.new('7s 7c 7d Ah Tc')
592
+ end
593
+ end
594
+
595
+ describe 'two pair' do
596
+ before do
597
+ @lowest_two_pair = Hand.new '2s 2c 3h 3d 4c'
598
+ end
599
+
600
+ it 'should beat a smaller two pair' do
601
+ @highest_two_pair.should > @two_pair
602
+ @two_pair.should > @lowest_two_pair
603
+ end
604
+
605
+ it 'should beat any pair' do
606
+ @lowest_two_pair.should > @highest_pair
607
+ end
608
+
609
+ it 'should beat any high card' do
610
+ @lowest_two_pair.should > @highest_high_card
611
+ end
612
+
613
+ it 'should beat smaller first pairs' do
614
+ Hand.new('As Ac 2d 2h 3c').should > Hand.new('Ks Kc Qd Qh Ac')
615
+ end
616
+
617
+ it 'should beat smaller second pairs' do
618
+ Hand.new('Ks Kc Qd Qh 2c').should > Hand.new('Ks Kc Jd Jh Ac')
619
+ end
620
+
621
+ it 'should beat smaller kickers' do
622
+ Hand.new('Ks Kc Qd Qh Ac').should > Hand.new('Ks Kc Qd Qh Jc')
623
+ end
624
+ end
625
+
626
+ describe 'pair' do
627
+ before do
628
+ @lowest_pair = Hand.new '2s 2c 3h 4d 5d'
629
+ end
630
+
631
+ it 'should beat a smaller pair' do
632
+ @highest_pair.should > @pair
633
+ @pair.should > @lowest_pair
634
+ end
635
+
636
+ it 'should beat any high card' do
637
+ @lowest_pair.should > @highest_high_card
638
+ end
639
+
640
+ it 'should beat smaller kickers' do
641
+ Hand.new('As Ac Kd Qh 2c').should > Hand.new('As Ac Kd Jh Tc')
642
+ end
643
+ end
644
+
645
+ describe 'high card' do
646
+ it 'should beat a smaller high card' do
647
+ @highest_high_card.should > @high_card
648
+ end
649
+
650
+ it 'should beat a smaller subsequent card' do
651
+ Hand.new('As Kc 4d 3h 2c').should > Hand.new('As Qc Jd Th 9c')
652
+ end
653
+ end
654
+ end
655
+ end
656
+ end
data/spec/helper.rb ADDED
@@ -0,0 +1,3 @@
1
+ require 'rubygems'
2
+ require 'spec'
3
+ require File.dirname(__FILE__) + '/../lib/poker'
metadata ADDED
@@ -0,0 +1,59 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: bakineggs-poker
3
+ version: !ruby/object:Gem::Version
4
+ version: "1.3"
5
+ platform: ruby
6
+ authors:
7
+ - Dan Barry
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-06-13 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: A library for constructing and comparing poker hands. Also provides a deck of cards.
17
+ email: dan@bakineggs.com
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files: []
23
+
24
+ files:
25
+ - lib/card.rb
26
+ - lib/deck.rb
27
+ - lib/hand.rb
28
+ - lib/poker.rb
29
+ has_rdoc: false
30
+ homepage: http://github.com/danbarry/poker
31
+ post_install_message:
32
+ rdoc_options: []
33
+
34
+ require_paths:
35
+ - lib
36
+ required_ruby_version: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: "0"
41
+ version:
42
+ required_rubygems_version: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: "0"
47
+ version:
48
+ requirements: []
49
+
50
+ rubyforge_project:
51
+ rubygems_version: 1.2.0
52
+ signing_key:
53
+ specification_version: 2
54
+ summary: A library for constructing and comparing poker hands. Also provides a deck of cards.
55
+ test_files:
56
+ - spec/helper.rb
57
+ - spec/card_spec.rb
58
+ - spec/deck_spec.rb
59
+ - spec/hand_spec.rb