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 +40 -19
- data/README +15 -0
- data/Rakefile +3 -8
- data/examples/deck.rb +1 -0
- data/lib/card.rb +6 -0
- data/lib/ruby-poker.rb +47 -14
- data/test/test_card.rb +13 -8
- data/test/test_poker_hand.rb +40 -17
- metadata +2 -2
data/CHANGELOG
CHANGED
@@ -1,24 +1,45 @@
|
|
1
|
-
2008-
|
2
|
-
*
|
3
|
-
|
4
|
-
*
|
5
|
-
*
|
6
|
-
*
|
7
|
-
|
8
|
-
|
9
|
-
*
|
10
|
-
*
|
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
|
-
|
18
|
-
|
19
|
-
*
|
20
|
-
|
21
|
-
*
|
22
|
-
|
23
|
-
|
24
|
-
*
|
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.
|
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 << '--
|
63
|
+
rdoc.options << '--inline-source'
|
69
64
|
end
|
data/examples/deck.rb
CHANGED
data/lib/card.rb
CHANGED
data/lib/ruby-poker.rb
CHANGED
@@ -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
|
-
|
138
|
-
|
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
|
-
|
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
|
-
|
244
|
-
|
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.
|
308
|
-
hand.gsub(/\s+$/,'')
|
341
|
+
hand.strip.squeeze(" ") # remove extra whitespace
|
309
342
|
end
|
310
343
|
|
311
344
|
def delta_transform(use_suit = false)
|
data/test/test_card.rb
CHANGED
@@ -1,8 +1,4 @@
|
|
1
|
-
|
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
|
-
|
49
|
-
|
50
|
-
|
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
|
data/test/test_poker_hand.rb
CHANGED
@@ -1,8 +1,4 @@
|
|
1
|
-
|
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
|
-
|
17
|
-
|
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
|
36
|
+
def test_flush
|
33
37
|
assert @flush.flush?
|
34
38
|
assert !@trips.flush?
|
35
39
|
end
|
36
40
|
|
37
|
-
def
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
100
|
+
def test_three_of_a_kind
|
97
101
|
assert @trips.three_of_a_kind?
|
98
102
|
end
|
99
103
|
|
100
|
-
def
|
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.
|
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-
|
12
|
+
date: 2008-05-26 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|