ruby-poker 0.2.4 → 0.3.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/CHANGELOG CHANGED
@@ -1,24 +1,45 @@
1
- 2008-01-10 (0.1.0)
2
- * Initial version
3
- 2008-01-12 (0.1.1)
4
- * Ranks are now a class.
5
- * Extracted card, rank, and arrays methods to individual files
6
- * Added gem packaging
7
- 2008-01-12 (0.1.2)
8
- * Fixed critical bug that was stopping the whole program to not work
9
- * Added some test cases as a result
10
- * More test cases coming soon
1
+ 2008-05-17 (0.3.0)
2
+ * Changed Card#== to compare based on card suit and face value. Before it only compared the face value of two cards. Warning: This change may potentially break your program if you were comparing Card objects directly.
3
+ * Replaced `PokerHand#arranged_hand` with `PokerHand#sort_using_rank` which is more descriptive. This loosely corresponds to bug #20194.
4
+ * Bug [#20196] 'rank' goes into an infinite loop.
5
+ * Bug [#20195] Allows the same card to be entered into the hand.
6
+ * Bug [#20344] sort_using_rank does not return expected results
7
+
8
+ 2008-04-20 (0.2.4)
9
+ * Modernized the Rakefile
10
+ * Updated to be compatible with Ruby 1.9
11
+
12
+ 2008-04-06 (0.2.2)
13
+ * Fixed bug where two hands that had the same values but different suits returned not equal
14
+
15
+ 2008-02-08 (0.2.1)
16
+ * Cards can be added to a hand after it is created by using (<<) on a PokerHand
17
+ * Cards can be deleted from a hand with PokerHand.delete()
18
+
11
19
  2008-01-21 (0.2.0)
12
20
  * Merged Patrick Hurley's poker solver
13
21
  * Added support for hands with >5 cards
14
22
  * Straights with a low Ace count now
15
23
  * to_s on a PokerHand now includes the rank after the card list
16
- * Finally wrote the Unit Tests suite
17
- 2008-02-08 (0.2.1)
18
- * Cards can be added to a hand after it is created by using (<<) on a PokerHand
19
- * Cards can be deleted from a hand with PokerHand.delete()
20
- 2008-04-06 (0.2.2)
21
- * Fixed bug where two hands that had the same values but different suits returned not equal
22
- 2008-04-20 (0.2.4)
23
- * Modernized the Rakefile
24
- * Updated to be compatible with Ruby 1.9
24
+ * Finally wrote the Unit Tests suite
25
+
26
+ 2008-01-12 (0.1.2)
27
+ * Fixed critical bug that was stopping the whole program to not work
28
+ * Added some test cases as a result
29
+ * More test cases coming soon
30
+
31
+ 2008-01-12 (0.1.1)
32
+ * Ranks are now a class.
33
+ * Extracted card, rank, and arrays methods to individual files
34
+ * Added gem packaging
35
+
36
+ 2008-01-10 (0.1.0)
37
+ * Initial version
38
+
39
+
40
+
41
+
42
+
43
+
44
+
45
+
data/README CHANGED
@@ -41,6 +41,21 @@ In this section some examples show what can be done with this class.
41
41
  puts hand2.rank => Three of a kind
42
42
  puts hand1 > hand2 => true
43
43
 
44
+ == Duplicates
45
+
46
+ By default ruby-poker will not raise an exception if you add the same card to a hand
47
+ twice. You can tell ruby-poker to not allow duplicates by doing the following
48
+
49
+ PokerHand.allow_duplicates = false
50
+
51
+ Place that line near the beginning of your program. The change is program wide so
52
+ once allow_duplicates is set to false, _all_ poker hands will raise an exception
53
+ if a duplicate card is added to the hand.
54
+
55
+ == Compatibility
56
+
57
+ Ruby-Poker is compatible with Ruby 1.8 and Ruby 1.9.
58
+
44
59
  == Background
45
60
 
46
61
  The original version of ruby-poker was written entirely by myself (Robert Olson).
data/Rakefile CHANGED
@@ -11,7 +11,7 @@ rescue LoadError
11
11
  nil
12
12
  end
13
13
 
14
- RUBYPOKER_VERSION = "0.2.4"
14
+ RUBYPOKER_VERSION = "0.3.0"
15
15
 
16
16
  task :default => [:test]
17
17
 
@@ -41,6 +41,7 @@ end
41
41
 
42
42
  Rake::GemPackageTask.new(spec) do |pkg|
43
43
  pkg.need_tar = true
44
+ pkg.need_zip = true
44
45
  end
45
46
 
46
47
  Rake::TestTask.new do |test|
@@ -54,16 +55,10 @@ task :autotest do
54
55
  ruby "-I lib -w /usr/bin/autotest"
55
56
  end
56
57
 
57
- desc "Create Zentest tests"
58
- task :zentest do
59
- `zentest card.rb test_card.rb > test_card_2.rb`
60
- `zentest ruby-poker.rb test_poker_hand.rb > test_poker_hand_2.rb`
61
- end
62
-
63
58
  Rake::RDocTask.new(:rdoc) do |rdoc|
64
59
  rdoc.rdoc_files.include('README', 'CHANGELOG', 'LICENSE', 'lib/')
65
60
  rdoc.main = 'README'
66
61
  rdoc.rdoc_dir = 'doc/html'
67
62
  rdoc.title = 'Ruby Poker Documentation'
68
- rdoc.options << '--all' << '--inline-source'
63
+ rdoc.options << '--inline-source'
69
64
  end
@@ -1,3 +1,4 @@
1
+ # This is a sample Deck implementation.
1
2
  class Deck
2
3
  def shuffle
3
4
  deck_size = @cards.size
@@ -109,4 +109,10 @@ class Card
109
109
  def <=> card2
110
110
  @face <=> card2.face
111
111
  end
112
+
113
+ # Returns true if the cards are the same card. Meaning they
114
+ # have the same suit and the same face value.
115
+ def == card2
116
+ @value == card2.value
117
+ end
112
118
  end
@@ -4,6 +4,10 @@ class PokerHand
4
4
  include Comparable
5
5
  attr_reader :hand
6
6
 
7
+ @@allow_duplicates = true # true by default
8
+ def self.allow_duplicates; @@allow_duplicates; end
9
+ def self.allow_duplicates=(v); @@allow_duplicates = v; end
10
+
7
11
  # Returns a new PokerHand object. Accepts the cards represented
8
12
  # in a string or an array
9
13
  #
@@ -47,6 +51,7 @@ class PokerHand
47
51
  def just_cards
48
52
  @hand.join(" ")
49
53
  end
54
+ alias :cards :just_cards
50
55
 
51
56
  # Returns an array of the card values in the hand.
52
57
  # The values returned are 1 less than the value on the card.
@@ -57,6 +62,12 @@ class PokerHand
57
62
  @hand.map { |c| c.face }
58
63
  end
59
64
 
65
+ # The =~ method does a regular expression match on the cards in this hand.
66
+ # This can be useful for many purposes. A common use is the check if a card
67
+ # exists in a hand.
68
+ #
69
+ # PokerHand.new("3d 4d 5d") =~ /8h/ # => nil
70
+ # PokerHand.new("3d 4d 5d") =~ /4d/ # => #<MatchData:0x615e18>
60
71
  def =~ (re)
61
72
  re.match(just_cards)
62
73
  end
@@ -134,13 +145,16 @@ class PokerHand
134
145
  transform = delta_transform
135
146
  # note we can have more than one delta 0 that we
136
147
  # need to shuffle to the back of the hand
137
- until transform.match(/^\S{3}( [1-9x]\S\S)+( 0\S\S)*$/) do
138
- transform.gsub!(/(\s0\S\S)(.*)/, "\\2\\1")
148
+ i = 0
149
+ until transform.match(/^\S{3}( [1-9x]\S\S)+( 0\S\S)*$/) or i >= hand.size do
150
+ # only do this once per card in the hand to avoid entering an
151
+ # infinite loop if all of the cards in the hand are the same
152
+ transform.gsub!(/(\s0\S\S)(.*)/, "\\2\\1") # moves the front card to the back of the string
153
+ i += 1
139
154
  end
140
155
  if (md = (/.(.). 1.. 1.. 1.. 1../.match(transform)))
141
156
  high_card = Card::face_value(md[1])
142
- arranged_hand = fix_low_ace_display(md[0] + ' ' +
143
- md.pre_match + ' ' + md.post_match)
157
+ arranged_hand = fix_low_ace_display(md[0] + ' ' + md.pre_match + ' ' + md.post_match)
144
158
  result = [[5, high_card], arranged_hand]
145
159
  end
146
160
  end
@@ -166,17 +180,24 @@ class PokerHand
166
180
  end
167
181
 
168
182
  def two_pair?
183
+ # \1 is the face value of the first pair
184
+ # \2 is the card in between the first pair and the second pair
185
+ # \3 is the face value of the second pair
169
186
  if (md = (by_face =~ /(.). \1.(.*) (.). \3./))
170
- # get kicker
171
- arranged_hand = arrange_hand(md[0] + ' ' +
187
+ # to get the kicker this does the following
188
+ # md[0] is the regex matched above which includes the first pair and
189
+ # the second pair but also some cards in the middle so we sub them out
190
+ # then we add on the cards that came before the first pair, the cards that
191
+ # we in between, and the cards that came after.
192
+ arranged_hand = arrange_hand(md[0].sub(md[2], '') + ' ' +
172
193
  md.pre_match + ' ' + md[2] + ' ' + md.post_match)
173
194
  arranged_hand.match(/(?:\S\S ){4}(\S)/)
174
195
  [
175
196
  [
176
197
  3,
177
- Card::face_value(md[1]),
178
- Card::face_value(md[3]),
179
- Card::face_value($1)
198
+ Card::face_value(md[1]), # face value of the first pair
199
+ Card::face_value(md[3]), # face value of the second pair
200
+ Card::face_value($1) # face value of the kicker
180
201
  ],
181
202
  arranged_hand
182
203
  ]
@@ -240,8 +261,14 @@ class PokerHand
240
261
  }.find([0]) { |score| score }
241
262
  end
242
263
 
243
- def arranged_hand
244
- score[1] + " (#{hand_rating})"
264
+ # Returns a string of the hand arranged based on its rank. Usually this will be the
265
+ # same as `by_face` but there are some cases where it makes a difference.
266
+ #
267
+ # ph = PokerHand.new("AS 3S 5S 2S 4S")
268
+ # ph.sort_using_rank # => "5s 4s 3s 2s As"
269
+ # ph.by_face.just_cards # => "As 5s 4s 3s 2s"
270
+ def sort_using_rank
271
+ score[1]
245
272
  end
246
273
 
247
274
  # Returns string with a listing of the cards in the hand followed by the hand's rank.
@@ -274,6 +301,10 @@ class PokerHand
274
301
  end
275
302
 
276
303
  new_cards.each do |nc|
304
+ unless @@allow_duplicates
305
+ raise "A card with the value #{nc} already exists in this hand. Set PokerHand.allow_duplicates to true if you want to be able to add a card more than once." if self =~ /#{nc}/
306
+ end
307
+
277
308
  @hand << Card.new(nc)
278
309
  end
279
310
  end
@@ -296,16 +327,18 @@ class PokerHand
296
327
  }
297
328
  end
298
329
 
299
- protected
330
+ # protected
300
331
 
332
+ # if md is a string, arrange_hand will remove extra white space
333
+ # if md is a MatchData, arrange_hand returns the matched segment
334
+ # followed by the pre_match and the post_match
301
335
  def arrange_hand(md)
302
336
  hand = if (md.respond_to?(:to_str))
303
337
  md
304
338
  else
305
339
  md[0] + ' ' + md.pre_match + md.post_match
306
340
  end
307
- hand.gsub!(/\s+/, ' ')
308
- hand.gsub(/\s+$/,'')
341
+ hand.strip.squeeze(" ") # remove extra whitespace
309
342
  end
310
343
 
311
344
  def delta_transform(use_suit = false)
@@ -1,8 +1,4 @@
1
- # Code Generated by ZenTest v. 3.8.0
2
- # classname: asrt / meth = ratio%
3
- # Card: 0 / 4 = 0.00%
4
-
5
- require 'test/unit' unless defined? $ZENTEST and $ZENTEST
1
+ require 'test/unit'
6
2
  require 'card.rb'
7
3
 
8
4
  class TestCard < Test::Unit::TestCase
@@ -45,6 +41,15 @@ class TestCard < Test::Unit::TestCase
45
41
  assert_equal(37, @c3.value)
46
42
  assert_equal(52, @c4.value)
47
43
  end
48
- end
49
-
50
- # Number of errors detected: 9
44
+
45
+ def test_comparison
46
+ assert(@c1 < @c2)
47
+ assert(@c3 > @c2)
48
+ end
49
+
50
+ def test_equals
51
+ c = Card.new("9h")
52
+ assert_not_equal(@c1, c)
53
+ assert_equal(@c1, @c1)
54
+ end
55
+ end
@@ -1,8 +1,4 @@
1
- # Code Generated by ZenTest v. 3.8.0
2
- # classname: asrt / meth = ratio%
3
- # PokerHand: 0 / 24 = 0.00%
4
-
5
- require 'test/unit' unless defined? $ZENTEST and $ZENTEST
1
+ require 'test/unit'
6
2
  require 'ruby-poker.rb'
7
3
 
8
4
  class TestPokerHand < Test::Unit::TestCase
@@ -13,8 +9,16 @@ class TestPokerHand < Test::Unit::TestCase
13
9
  @straight = PokerHand.new("8H 9D TS JH QC AS")
14
10
  end
15
11
 
16
- def test_arranged_hand
17
- assert_equal("As Ah Ac 9c 2d (Three of a kind)", @trips.arranged_hand)
12
+ # there are a lot of combinations that should be tested here. I will add more
13
+ # troublesome cases as I think of them.
14
+ def test_sort_using_rank
15
+ assert_equal("As Ah Ac 9c 2d", @trips.sort_using_rank)
16
+ assert_equal("4s 4d 4c 2h 2d", @full_boat.sort_using_rank)
17
+ assert_equal("Qd Td 7d 6d 3d 2s 5h", @flush.sort_using_rank)
18
+ assert_equal("Qc Jh Ts 9d 8h As", @straight.sort_using_rank)
19
+
20
+ assert_equal("As Ah 3d 3c Kd", PokerHand.new("AS AH KD 3D 3C").sort_using_rank)
21
+ assert_equal("As Ah 3d 3c 2d", PokerHand.new("2D AS AH 3D 3C").sort_using_rank)
18
22
  end
19
23
 
20
24
  def test_by_face
@@ -29,17 +33,17 @@ class TestPokerHand < Test::Unit::TestCase
29
33
  assert_equal([1, 8, 13, 13, 13], @trips.face_values)
30
34
  end
31
35
 
32
- def test_flush_eh
36
+ def test_flush
33
37
  assert @flush.flush?
34
38
  assert !@trips.flush?
35
39
  end
36
40
 
37
- def test_four_of_a_kind_eh
41
+ def test_four_of_a_kind
38
42
  assert !@trips.four_of_a_kind?
39
43
  assert PokerHand.new("AD 9C AS AH AC")
40
44
  end
41
45
 
42
- def test_full_house_eh
46
+ def test_full_house
43
47
  assert !@trips.full_house?
44
48
  assert @full_boat.full_house?
45
49
  end
@@ -59,7 +63,7 @@ class TestPokerHand < Test::Unit::TestCase
59
63
  assert_not_nil @trips.rank
60
64
  end
61
65
 
62
- def test_highest_card_eh
66
+ def test_highest_card
63
67
  # hard to test, make sure it does not return null
64
68
  assert PokerHand.new("2D 4S 6C 8C TH").highest_card?
65
69
  end
@@ -68,12 +72,12 @@ class TestPokerHand < Test::Unit::TestCase
68
72
  assert_equal("2d 9c As Ah Ac", @trips.just_cards)
69
73
  end
70
74
 
71
- def test_pair_eh
75
+ def test_pair
72
76
  assert !PokerHand.new("5C JC 2H 7S 3D").pair?
73
77
  assert PokerHand.new("6D 7C 5D 5H 3S").pair?
74
78
  end
75
79
 
76
- def test_royal_flush_eh
80
+ def test_royal_flush
77
81
  assert !@flush.royal_flush?
78
82
  assert PokerHand.new("AD KD QD JD TD").royal_flush?
79
83
  end
@@ -82,22 +86,22 @@ class TestPokerHand < Test::Unit::TestCase
82
86
  assert_equal([4, 13, 8, 1], @trips.score[0])
83
87
  end
84
88
 
85
- def test_straight_eh
89
+ def test_straight
86
90
  assert @straight.straight?
87
91
  assert PokerHand.new("AH 2S 3D 4H 5D").straight?
88
92
  end
89
93
 
90
- def test_straight_flush_eh
94
+ def test_straight_flush
91
95
  assert !@flush.straight_flush?
92
96
  assert !@straight.straight_flush?
93
97
  assert PokerHand.new("8H 9H TH JH QH AS").straight_flush?
94
98
  end
95
99
 
96
- def test_three_of_a_kind_eh
100
+ def test_three_of_a_kind
97
101
  assert @trips.three_of_a_kind?
98
102
  end
99
103
 
100
- def test_two_pair_eh
104
+ def test_two_pair
101
105
  assert PokerHand.new("2S 2D TH TD 4S").two_pair?
102
106
  assert !PokerHand.new("6D 7C 5D 5H 3S").two_pair?
103
107
  end
@@ -138,5 +142,24 @@ class TestPokerHand < Test::Unit::TestCase
138
142
  ph.delete("Ac")
139
143
  assert_equal(Array.new, ph.hand)
140
144
  end
145
+
146
+ def test_five_of_a_kind
147
+ # there is no five of a kind. This just tests to make sure
148
+ # that ruby-poker doesn't crash if given 5 of the same card
149
+ ph = PokerHand.new("KS KS KS KS KS")
150
+ assert_equal("Four of a kind", ph.rank)
151
+ end
152
+
153
+ def test_duplicates
154
+ ph = PokerHand.new("2d")
155
+ PokerHand.allow_duplicates = true
156
+ ph << "2d"
157
+ assert_equal("2d 2d", ph.just_cards)
158
+
159
+ PokerHand.allow_duplicates = false
160
+ assert_raise RuntimeError do
161
+ ph << "2d"
162
+ end
163
+ end
141
164
  end
142
165
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby-poker
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.4
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Robert Olson
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-04-20 00:00:00 -07:00
12
+ date: 2008-05-26 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies: []
15
15