ruby-poker 0.2.4 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
|