ruby-poker 0.3.2 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/ruby-poker.gemspec CHANGED
@@ -1,32 +1,30 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = "ruby-poker"
3
- s.version = "0.3.1"
4
- s.date = "2009-01-24"
5
- s.rubyforge_project = "rubypoker"
3
+ s.version = "1.0.0"
6
4
  s.platform = Gem::Platform::RUBY
7
- s.summary = "Poker library in Ruby"
5
+ s.summary = "Poker library in Ruby"
8
6
  s.description = "Ruby library for comparing poker hands and determining the winner."
9
- s.author = "Rob Olson"
10
- s.email = "rko618@gmail.com"
11
- s.homepage = "http://github.com/robolson/ruby-poker"
12
- s.has_rdoc = true
7
+ s.author = "Rob Olson"
8
+ s.email = "rob@thinkingdigitally.com"
9
+ s.homepage = "https://github.com/robolson/ruby-poker"
10
+ s.license = 'BSD'
13
11
  s.files = ["CHANGELOG",
14
- "examples/deck.rb",
15
- "examples/quick_example.rb",
16
- "lib/card.rb",
17
- "lib/ruby-poker.rb",
18
- "LICENSE",
19
- "Rakefile",
20
- "README.rdoc",
21
- "ruby-poker.gemspec"]
22
- s.test_files = ["test/test_card.rb",
23
- "test/test_poker_hand.rb"]
12
+ "examples/deck.rb",
13
+ "examples/quick_example.rb",
14
+ "lib/ruby-poker.rb",
15
+ "lib/ruby-poker/card.rb",
16
+ "lib/ruby-poker/poker_hand.rb",
17
+ "LICENSE",
18
+ "Rakefile",
19
+ "README.rdoc",
20
+ "ruby-poker.gemspec"]
21
+ s.test_files = ["test/test_helper.rb", "test/test_card.rb", "test/test_poker_hand.rb"]
24
22
  s.require_paths << 'lib'
25
-
26
- s.extra_rdoc_files = ["README", "CHANGELOG", "LICENSE"]
23
+
24
+ s.extra_rdoc_files = ["README.rdoc", "CHANGELOG", "LICENSE"]
27
25
  s.rdoc_options << '--title' << 'Ruby Poker Documentation' <<
28
26
  '--main' << 'README.rdoc' <<
29
27
  '--inline-source' << '-q'
30
-
31
- # s.add_dependency("thoughtbot-shoulda", ["> 2.0.0"])
28
+
29
+ s.add_development_dependency('shoulda-context', '~> 1.1')
32
30
  end
data/test/test_card.rb CHANGED
@@ -7,29 +7,65 @@ class TestCard < Test::Unit::TestCase
7
7
  @c2 = Card.new("TD")
8
8
  @c3 = Card.new("jh")
9
9
  @c4 = Card.new("qS")
10
+ @c5 = Card.new("AC")
10
11
  end
11
-
12
- def test_build_from_card
13
- assert_equal("9c", Card.new(@c1).to_s)
14
- end
15
-
12
+
16
13
  def test_class_face_value
17
- assert_nil(Card.face_value('L'))
14
+ assert_equal(0, Card.face_value('L'))
18
15
  assert_equal(13, Card.face_value('A'))
19
16
  end
20
17
 
18
+ def test_build_from_card
19
+ assert_equal("9c", Card.new(@c1).to_s)
20
+ end
21
+
21
22
  def test_build_from_value
22
- assert_equal(@c1, Card.new(7))
23
+ assert_equal(@c1, Card.new(8))
23
24
  assert_equal(@c2, Card.new(22))
24
- assert_equal(@c3, Card.new(37))
25
- assert_equal(@c4, Card.new(52))
25
+ assert_equal(@c3, Card.new(36))
26
+ assert_equal(@c4, Card.new(50))
27
+ assert_equal(@c5, Card.new(13))
28
+ end
29
+
30
+ def test_build_from_face_suit
31
+ assert_equal(8, Card.new('9', 'c').value)
32
+ assert_equal(22, Card.new('T', 'd').value)
33
+ assert_equal(36, Card.new('J', 'h').value)
34
+ assert_equal(50, Card.new('Q', 's').value)
35
+ assert_equal(13, Card.new('A', 'c').value)
36
+ end
37
+
38
+ def test_build_from_value_and_from_face_suit_match
39
+ ticker = 0
40
+ Card::SUITS.each_char do |suit|
41
+ "23456789TJQKA".each_char do |face|
42
+ ticker += 1
43
+ from_value = Card.new(ticker)
44
+ from_face_suit = Card.new(face, suit)
45
+ assert_equal(from_face_suit, from_value,
46
+ "Face and suit #{face + suit} did not match card from value #{ticker}")
47
+ end
48
+ end
49
+ end
50
+
51
+ def test_build_from_value_and_from_face_suit_values_match
52
+ ticker = 0
53
+ 0.upto(3) do |suit|
54
+ 1.upto(13) do |face|
55
+ ticker += 1
56
+ from_value = Card.new(ticker)
57
+ from_face_suit_values = Card.new(face, suit)
58
+ assert_equal(from_face_suit_values, from_value,
59
+ "Face=#{face} and suit=#{suit} did not match card from value #{ticker}")
60
+ end
61
+ end
26
62
  end
27
63
 
28
64
  def test_face
29
65
  assert_equal(8, @c1.face)
30
66
  assert_equal(9, @c2.face)
31
67
  assert_equal(10, @c3.face)
32
- assert_equal(11, @c4.face)
68
+ assert_equal(11, @c4.face)
33
69
  end
34
70
 
35
71
  def test_suit
@@ -40,12 +76,13 @@ class TestCard < Test::Unit::TestCase
40
76
  end
41
77
 
42
78
  def test_value
43
- assert_equal(7, @c1.value)
79
+ assert_equal(8, @c1.value)
44
80
  assert_equal(22, @c2.value)
45
- assert_equal(37, @c3.value)
46
- assert_equal(52, @c4.value)
81
+ assert_equal(36, @c3.value)
82
+ assert_equal(50, @c4.value)
83
+ assert_equal(13, @c5.value)
47
84
  end
48
-
85
+
49
86
  def test_natural_value
50
87
  assert_equal(1, Card.new("AC").natural_value)
51
88
  assert_equal(15, Card.new("2D").natural_value)
@@ -56,14 +93,10 @@ class TestCard < Test::Unit::TestCase
56
93
  assert(@c1 < @c2)
57
94
  assert(@c3 > @c2)
58
95
  end
59
-
96
+
60
97
  def test_equals
61
98
  c = Card.new("9h")
62
99
  assert_not_equal(@c1, c)
63
100
  assert_equal(@c1, @c1)
64
101
  end
65
-
66
- def test_hash
67
- assert_equal(15, @c1.hash)
68
- end
69
- end
102
+ end
data/test/test_helper.rb CHANGED
@@ -1,7 +1,6 @@
1
1
  require 'rubygems'
2
+ require 'bundler/setup'
2
3
  require 'test/unit'
3
- require 'shoulda'
4
+ require 'shoulda-context'
4
5
 
5
- $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
6
- $LOAD_PATH.unshift(File.dirname(__FILE__))
7
- require 'ruby-poker'
6
+ require 'ruby-poker'
@@ -2,22 +2,62 @@ require File.expand_path(File.dirname(__FILE__) + '/test_helper')
2
2
 
3
3
  class TestPokerHand < Test::Unit::TestCase
4
4
  context "A PokerHand instance" do
5
-
5
+
6
6
  setup do
7
- @trips = PokerHand.new("2D 9C AS AH AC")
7
+ @quads = PokerHand.new('Kc Kh Kd Ks Qs')
8
8
  @full_boat = PokerHand.new(["2H", "2D", "4C", "4D", "4S"])
9
9
  @flush = PokerHand.new("3D 6D 7D TD QD 5H 2S")
10
10
  @straight = PokerHand.new("8H 9D TS JH QC AS")
11
+ @trips = PokerHand.new("2D 9C AS AH AC")
12
+ @two_pair = PokerHand.new("As Ac Kc Kd 2s")
13
+ @pair = PokerHand.new("As Ac Kc Qd 2s")
14
+ @ace_high = PokerHand.new("As Jh 9c 7d 5s")
15
+ end
16
+
17
+ should "handle empty hands" do
18
+ assert_equal(PokerHand.new.rank, "Empty Hand")
19
+ end
20
+
21
+ should "handle single card hands" do
22
+ assert_equal(PokerHand.new('As').rank, @ace_high.rank)
23
+ end
24
+
25
+ should "handle two card hands" do
26
+ assert_equal(PokerHand.new('As Ac').rank, @pair.rank)
27
+ end
28
+
29
+ should "handle three card hands" do
30
+ assert_equal(PokerHand.new('As Ac Ah').rank, @trips.rank)
31
+ end
32
+
33
+ should "handle four card hands" do
34
+ assert_equal(PokerHand.new('As Ac Kd Kh').rank, @two_pair.rank)
35
+ assert_equal(PokerHand.new('As Ac Ad Ah').rank, @quads.rank)
36
+ end
37
+
38
+ should "handle lower case face card names" do
39
+ assert_equal(0, PokerHand.new('kc kd') <=> PokerHand.new('Kc Kd'))
40
+ assert_equal(0, PokerHand.new('kc kd') <=> PokerHand.new('Kc KD'))
41
+ end
42
+
43
+ should "handle hands without space" do
44
+ assert_equal(0, PokerHand.new('KcKd') <=> PokerHand.new('Kc Kd'))
45
+ assert_equal(0, PokerHand.new('KcKd9d') <=> PokerHand.new('Kc Kd 9d'))
46
+ end
47
+
48
+ should "raise a clear error with invalid cards" do
49
+ e = assert_raises(ArgumentError) { PokerHand.new('Fc') }
50
+ assert_match(/"Fc"/, e.message)
51
+ e = assert_raises(ArgumentError) { PokerHand.new('Tp') }
52
+ assert_match(/"Tp"/, e.message)
11
53
  end
12
-
13
- # there are a lot of combinations that should be tested here. I will add more
14
- # troublesome cases as I think of them.
54
+
15
55
  should "sort using rank" do
16
56
  assert_equal("As Ah Ac 9c 2d", @trips.sort_using_rank)
17
57
  assert_equal("4s 4d 4c 2h 2d", @full_boat.sort_using_rank)
18
58
  assert_equal("Qd Td 7d 6d 3d 2s 5h", @flush.sort_using_rank)
19
59
  assert_equal("Qc Jh Ts 9d 8h As", @straight.sort_using_rank)
20
-
60
+
21
61
  assert_equal("As Ah 3d 3c Kd", PokerHand.new("AS AH KD 3D 3C").sort_using_rank)
22
62
  assert_equal("As Ah 3d 3c 2d", PokerHand.new("2D AS AH 3D 3C").sort_using_rank)
23
63
  end
@@ -33,13 +73,13 @@ class TestPokerHand < Test::Unit::TestCase
33
73
  should "return just the face values of the cards" do
34
74
  assert_equal([1, 8, 13, 13, 13], @trips.face_values)
35
75
  end
36
-
76
+
37
77
  should "recognize a straight flush" do
38
78
  assert !@flush.straight_flush?
39
79
  assert !@straight.straight_flush?
40
80
  assert PokerHand.new("8H 9H TH JH QH AS").straight_flush?
41
81
  end
42
-
82
+
43
83
  should "recognize a royal flush" do
44
84
  assert !@flush.royal_flush?
45
85
  assert PokerHand.new("AD KD QD JD TD").royal_flush?
@@ -59,10 +99,13 @@ class TestPokerHand < Test::Unit::TestCase
59
99
  assert !@trips.full_house?
60
100
  assert @full_boat.full_house?
61
101
  end
62
-
102
+
63
103
  should "recognize a straight" do
64
104
  assert @straight.straight?
105
+ # ace low straight
65
106
  assert PokerHand.new("AH 2S 3D 4H 5D").straight?
107
+ # ace high straight
108
+ assert PokerHand.new("AH KS QD JH TD").straight?
66
109
  end
67
110
 
68
111
  should "recognize a three of a kind" do
@@ -73,12 +116,12 @@ class TestPokerHand < Test::Unit::TestCase
73
116
  assert PokerHand.new("2S 2D TH TD 4S").two_pair?
74
117
  assert !PokerHand.new("6D 7C 5D 5H 3S").two_pair?
75
118
  end
76
-
119
+
77
120
  should "recognize a pair" do
78
121
  assert !PokerHand.new("5C JC 2H 7S 3D").pair?
79
122
  assert PokerHand.new("6D 7C 5D 5H 3S").pair?
80
123
  end
81
-
124
+
82
125
  should "recognize a hand with the rank highest_card" do
83
126
  # hard to test, make sure it does not return null
84
127
  assert PokerHand.new("2D 4S 6C 8C TH").highest_card?
@@ -110,42 +153,42 @@ class TestPokerHand < Test::Unit::TestCase
110
153
  assert_match(/9c/, @trips.to_s)
111
154
  assert_no_match(/AD/, @trips.to_s)
112
155
  end
113
-
156
+
114
157
  should "return the correct number of cards in the hand" do
115
158
  assert_equal(0, PokerHand.new.size)
116
159
  assert_equal(1, PokerHand.new("2c").size)
117
160
  assert_equal(2, PokerHand.new("2c 3d").size)
118
161
  end
119
-
162
+
120
163
  should "be comparable to other PokerHands" do
121
164
  hand1 = PokerHand.new("5C JC 2H 5S 3D")
122
165
  hand2 = PokerHand.new("6D 7C 5D 5H 3S")
123
166
  assert_equal(1, hand1 <=> hand2)
124
167
  assert_equal(-1, hand2 <=> hand1)
125
168
  end
126
-
169
+
127
170
  should "be considered equal to other poker hands that contain the same cards" do
128
171
  assert_equal(0, @trips <=> @trips)
129
-
172
+
130
173
  hand1 = PokerHand.new("Ac Qc Ks Kd 9d 3c")
131
174
  hand2 = PokerHand.new("Ah Qs 9h Kh Kc 3s")
132
175
  assert_equal(0, hand1 <=> hand2)
133
176
  end
134
-
135
- should "be able to add a Card to itself" do
177
+
178
+ should "be able to insert new cards into the hand" do
136
179
  ph = PokerHand.new()
137
180
  ph << "Qd"
138
181
  ph << Card.new("2D")
139
182
  ph << ["3d", "4d"]
140
183
  assert_equal("Qd 2d 3d 4d", ph.just_cards)
141
184
  end
142
-
185
+
143
186
  should "be able to delete a card" do
144
187
  ph = PokerHand.new("Ac")
145
188
  ph.delete("Ac")
146
189
  assert_equal(Array.new, ph.hand)
147
190
  end
148
-
191
+
149
192
  should "detect the two highest pairs when there are more than two" do
150
193
  ph = PokerHand.new("7d 7s 4d 4c 2h 2d")
151
194
  assert_equal([3, 6, 3, 1], ph.two_pair?[0])
@@ -155,66 +198,333 @@ class TestPokerHand < Test::Unit::TestCase
155
198
  # 3: second highest pair is two 4's
156
199
  # 1: kicker is a 2
157
200
  end
158
-
201
+
159
202
  context "when duplicates are allowed" do
160
203
  setup do
161
204
  PokerHand.allow_duplicates = true
162
205
  end
163
-
206
+
164
207
  should "create a PokerHand of unique cards" do
165
208
  uniq_ph = PokerHand.new("3s 4s 3s").uniq
166
209
  assert_instance_of(PokerHand, uniq_ph) # want to be sure uniq hands back a PokerHand
167
210
  assert_contains(uniq_ph.hand, Card.new('3s'))
168
211
  assert_contains(uniq_ph.hand, Card.new('4s'))
169
212
  end
170
-
213
+
171
214
  should "allow five of a kind" do
172
215
  # there is no five of a kind. This just tests to make sure
173
216
  # that ruby-poker doesn't crash if given 5 of the same card
174
217
  ph = PokerHand.new("KS KS KS KS KS")
175
218
  assert_equal("Four of a kind", ph.rank)
176
219
  end
177
-
220
+
178
221
  should "allow duplicates on initialize" do
179
222
  assert_nothing_raised RuntimeError do
180
223
  PokerHand.new("3s 3s")
181
224
  end
182
225
  end
183
-
226
+
184
227
  should "allow duplicate card to be added after initialize" do
185
228
  ph = PokerHand.new("2d")
186
229
  ph << "2d"
187
230
  assert_equal("2d 2d", ph.just_cards)
188
231
  end
189
232
  end
190
-
233
+
191
234
  context "when duplicates are not allowed" do
192
235
  setup do
193
236
  PokerHand.allow_duplicates = false
194
237
  end
195
-
238
+
196
239
  should "not allow duplicates on initialize" do
197
240
  PokerHand.allow_duplicates = false
198
-
241
+
199
242
  assert_raise RuntimeError do
200
243
  PokerHand.new("3s 3s")
201
244
  end
202
-
245
+
203
246
  PokerHand.allow_duplicates = true
204
247
  end
205
-
248
+
206
249
  should "not allow duplicates after initialize" do
207
250
  PokerHand.allow_duplicates = false
208
-
209
- ph = PokerHand.new("2d")
251
+
252
+ ph = PokerHand.new("2d")
210
253
  assert_raise RuntimeError do
211
254
  ph << "2d"
212
255
  end
213
-
256
+
214
257
  PokerHand.allow_duplicates = true
215
258
  end
216
259
  end
217
-
260
+
261
+ should "have an each method" do
262
+ cards = []
263
+ @straight.each do |card|
264
+ cards << card
265
+ end
266
+ assert_equal @straight.to_a, cards
267
+ end
268
+
269
+ should "be Enumerable" do
270
+ assert PokerHand.include?(Enumerable)
271
+ end
218
272
  end
219
- end
220
273
 
274
+ context "addition" do
275
+ setup do
276
+ @base = PokerHand.new('Ac Kc')
277
+ end
278
+
279
+ should "work with a string" do
280
+ assert_equal PokerHand.new('Ac Kc Qc'), @base + 'Qc'
281
+ end
282
+
283
+ should "work with a card" do
284
+ assert_equal PokerHand.new('Ac Kc Qc'), @base + Card.new('Qc')
285
+ end
286
+
287
+ should "work with a hand" do
288
+ assert_equal PokerHand.new('Ac Kc Qc'), @base + PokerHand.new('Qc')
289
+ end
290
+
291
+ should "not modify the receiver hand" do
292
+ result = @base + 'Qc'
293
+ assert_not_equal result, @base
294
+ end
295
+
296
+ should "not affect receiver cards" do
297
+ result = @base + 'Qc'
298
+ result.to_a.first.instance_eval { @face = Card.face_value('2') }
299
+ assert_equal PokerHand.new('Ac Kc'), @base
300
+ end
301
+ end
302
+
303
+ context "PokerHand#pair?" do
304
+
305
+ should "return false with one card" do
306
+ assert !PokerHand.new("2h").pair?
307
+ end
308
+
309
+ context "with a pair" do
310
+
311
+ should "return 2, followed by the pair value" do
312
+ assert_equal [2, 5-1], PokerHand.new("5h 5s").pair?[0]
313
+ end
314
+
315
+ context "with a two card hand" do
316
+ setup do
317
+ @ph = PokerHand.new("5h 5s")
318
+ @scoring = @ph.pair?[0]
319
+ end
320
+
321
+ should "return scoring with 2 entries" do
322
+ assert_equal 2, @scoring.size
323
+ end
324
+ end
325
+
326
+ context "with a three card hand" do
327
+ setup do
328
+ @ph = PokerHand.new("5h 5s 8s")
329
+ @scoring = @ph.pair?[0]
330
+ end
331
+
332
+ should "return scoring with 3 entries" do
333
+ assert_equal 3, @scoring.size
334
+ end
335
+
336
+ should "return the value of the kicker" do
337
+ assert_equal 8-1, @scoring[2]
338
+ end
339
+ end
340
+
341
+ context "with a four card hand" do
342
+ setup do
343
+ @ph = PokerHand.new("5h 5s 8s 7s")
344
+ @scoring = @ph.pair?[0]
345
+ end
346
+
347
+ should "return scoring with 4 entries" do
348
+ assert_equal 4, @scoring.size
349
+ end
350
+
351
+ should "return the values of the kickers" do
352
+ assert_equal 8-1, @scoring[2]
353
+ assert_equal 7-1, @scoring[3]
354
+ end
355
+ end
356
+
357
+ context "with a five (or more) card hand" do
358
+ setup do
359
+ @ph = PokerHand.new("5h 5s 8s 7s 6s 2h")
360
+ @scoring = @ph.pair?[0]
361
+ end
362
+
363
+ should "return scoring with 5 entries" do
364
+ assert_equal 5, @scoring.size
365
+ end
366
+
367
+ should "return the values of the kickers" do
368
+ assert_equal 8-1, @scoring[2]
369
+ assert_equal 7-1, @scoring[3]
370
+ assert_equal 6-1, @scoring[4]
371
+ end
372
+ end
373
+ end
374
+
375
+ context "without a pair" do
376
+ should "return false" do
377
+ assert !PokerHand.new("2h 3h").pair?
378
+ end
379
+ end
380
+ end
381
+
382
+
383
+ def assert_hand_match(expression, cards)
384
+ hand = PokerHand.new(cards)
385
+ assert hand.match?(expression), "#{cards} didn't match #{expression}"
386
+ end
387
+
388
+ def assert_hand_not_match(expression, cards)
389
+ hand = PokerHand.new(cards)
390
+ assert !hand.match?(expression), "#{cards} did match #{expression}"
391
+ end
392
+
393
+ context "matching expression" do
394
+ should "match two faces" do
395
+ assert_hand_match 'AA', 'Ah Ad'
396
+ assert_hand_match 'Q8', 'Qc 8d'
397
+ end
398
+
399
+ should "not match two faces" do
400
+ assert_hand_not_match 'T9', 'Tc 8s'
401
+ assert_hand_not_match 'QQ', 'Tc 8s'
402
+ end
403
+
404
+ should "match unordered faces" do
405
+ assert_hand_match 'K7', '7c Ks'
406
+ end
407
+
408
+ should "match suited when suited" do
409
+ assert_hand_match 'Q8s', 'Qc 8c'
410
+ assert_hand_match '56s', '5h 6h'
411
+ end
412
+
413
+ should "not match suited when offsuit" do
414
+ assert_hand_not_match 'Q8s', 'Qc 8d'
415
+ assert_hand_not_match '56s', '5h 6c'
416
+ end
417
+
418
+ should "match offsuit when offsuited" do
419
+ assert_hand_match 'Q8o', 'Qc 8h'
420
+ assert_hand_match '56o', '5h 6s'
421
+ end
422
+
423
+ should "not match offsuit when suited" do
424
+ assert_hand_not_match 'Q8o', 'Qc 8c'
425
+ assert_hand_not_match '56o', '5h 6h'
426
+ end
427
+
428
+ should "match pair min" do
429
+ assert_hand_match 'JJ+', 'Jc Js'
430
+ assert_hand_match '66+', 'Qc Qh'
431
+ assert_hand_match 'JJ+', 'Ad Ac'
432
+ end
433
+
434
+ should "not match pair min" do
435
+ assert_hand_not_match 'JJ+', 'Tc Ts'
436
+ assert_hand_not_match '66+', 'Qc Kh'
437
+ assert_hand_not_match 'AA+', '2d 2c'
438
+ end
439
+
440
+ should "match face min" do
441
+ assert_hand_match 'AJ+', 'Ac Js'
442
+ assert_hand_match 'AQ+', 'Ac Kc'
443
+ assert_hand_match 'AJ+', 'Ac As'
444
+ assert_hand_match 'QT+', 'Qc Ts'
445
+ assert_hand_match 'QT+', 'Qc Qs'
446
+ assert_hand_not_match 'QT+', 'Qc Ks' # sure? should be matched with KQ+?
447
+ assert_hand_not_match 'AJ+', 'Ac Ts'
448
+ assert_hand_not_match 'AJ+', 'Tc Ts'
449
+ end
450
+
451
+ should "match suited face min" do
452
+ assert_hand_match 'AJs+', 'Ac Jc'
453
+ assert_hand_match 'AQs+', 'Ac Kc'
454
+ assert_hand_not_match 'AJs+', 'Ac As'
455
+ assert_hand_match 'QTs+', 'Qc Tc'
456
+ assert_hand_not_match 'QTs+', 'Qc Ts'
457
+ assert_hand_not_match 'AJs+', 'Ac Qs'
458
+ end
459
+
460
+ should "match offsuit face min" do
461
+ assert_hand_match 'AJo+', 'Ac Jd'
462
+ assert_hand_match 'AQo+', 'Ac Kh'
463
+ assert_hand_match 'AJo+', 'Ac As'
464
+ assert_hand_match 'QTo+', 'Qc Td'
465
+ assert_hand_not_match 'QTo+', 'Qc Tc'
466
+ assert_hand_not_match 'AJo+', 'Ac Qc'
467
+ end
468
+
469
+ should "match face with 1 gap" do
470
+ assert_hand_match '89+', '8c 9d'
471
+ assert_hand_match '89+', '9c Td'
472
+ assert_hand_match '89+', 'Tc Jd'
473
+ assert_hand_match '89+', 'Ac Kd'
474
+ assert_hand_not_match '89+', '8c Td'
475
+ assert_hand_not_match '89+', 'Tc Td'
476
+ assert_hand_not_match '89+', '7c 8d'
477
+ end
478
+
479
+ should "match face with 2 gaps" do
480
+ assert_hand_match '8T+', '8c Td'
481
+ assert_hand_match '8T+', 'Tc 8d'
482
+ assert_hand_match '24+', '9c Jd'
483
+ assert_hand_match '79+', 'Ac Qd'
484
+ assert_hand_not_match '8T+', '8c 9d'
485
+ assert_hand_not_match '8T+', 'Tc Td'
486
+ assert_hand_not_match '8T+', 'Jc Ad'
487
+ assert_hand_not_match '8T+', '7c 9d'
488
+ end
489
+
490
+ should "match face with many gaps" do
491
+ assert_hand_match '8J+', '9c Qd'
492
+ assert_hand_match '8Q+', '9c Kd'
493
+ assert_hand_match '8K+', 'Ac 9d'
494
+ assert_hand_not_match '8J+', '7c Td'
495
+ end
496
+
497
+ should "match face gap with suit" do
498
+ assert_hand_match '89s+', '9c Tc'
499
+ assert_hand_not_match '89s+', '9c Td'
500
+ assert_hand_match '89o+', '9c Th'
501
+ assert_hand_not_match '89o+', '9d Td'
502
+ end
503
+
504
+ [
505
+ %w(),
506
+ %w(Ac),
507
+ %w(Ac Kc Qc),
508
+ %w(Ac Kc Qc Jc Tc),
509
+ ].each do |cards|
510
+ should "raise an error if the number of cards is #{cards.size}" do
511
+ hand = PokerHand.new(cards)
512
+ assert_raises RuntimeError do
513
+ hand.match?('AA')
514
+ end
515
+ end
516
+ end
517
+
518
+ should "raise an error with invalid expression" do
519
+ hand = PokerHand.new("Ac Kc")
520
+ assert_raises ArgumentError do
521
+ hand.match? "foo"
522
+ end
523
+
524
+ assert_raises ArgumentError do
525
+ hand.match? ""
526
+ end
527
+ end
528
+ end
529
+
530
+ end