ruby-poker 0.2.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG CHANGED
@@ -13,4 +13,7 @@
13
13
  * Added support for hands with >5 cards
14
14
  * Straights with a low Ace count now
15
15
  * to_s on a PokerHand now includes the rank after the card list
16
- * Finally wrote the Unit Tests suite
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()
data/README CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  == Author
4
4
 
5
- Robert Olson mailto:rko618 [at] gmail.com
5
+ Robert Olson (rko618 [at] gmail [dot] com)
6
6
 
7
7
  == License
8
8
 
@@ -21,7 +21,8 @@ The homepage of this project is located at
21
21
 
22
22
  == Description
23
23
 
24
- Ruby-Poker handles the logic for poker hands.
24
+ Ruby-Poker handles the logic for getting the rank of a poker hand. It can also be used
25
+ to compare two or more hands to determine which hand has the highest poker value.
25
26
 
26
27
  Card representations can be passed to the PokerHand constructor as a string or an array.
27
28
  Face cards (cards ten, jack, queen, king, and ace) are created using their
@@ -42,7 +43,6 @@ In this section some examples show what can be done with this class.
42
43
 
43
44
  == Background
44
45
 
45
- I (Robert Olson) wrote all of the code in the original version of ruby-poker which only
46
- allowed for hands of 5 cards. I later discovered the amazing poker solving code written by
47
- Patrick Hurley for http://rubyquiz.com/quiz24.html and merged it into
48
- ruby-poker 0.2.0.
46
+ I (Robert Olson) wrote all of the code in the original version of ruby-poker which limited
47
+ hands to only 5 cards. As of the 0.2.0 release ruby-poker is based on Patrick Hurley's
48
+ Texas Holdem code from http://rubyquiz.com/quiz24.html which I merged into ruby-poker.
@@ -58,12 +58,20 @@ class Card
58
58
  build_from_value((face - 1) + (suit * FACES.size()))
59
59
  end
60
60
 
61
+ # Constructs this card object from another card object
62
+ def build_from_card(card)
63
+ @value = card.value
64
+ @suit = card.suit
65
+ @face = card.face
66
+ end
67
+
61
68
  public
62
69
 
63
- # got a little carried away with this constructor ;-)
64
70
  def initialize(*value)
65
71
  if (value.size == 1)
66
- if (value[0].respond_to?(:to_str))
72
+ if (value[0].respond_to?(:to_card))
73
+ build_from_card(value[0])
74
+ elsif (value[0].respond_to?(:to_str))
67
75
  build_from_string(value[0])
68
76
  elsif (value[0].respond_to?(:to_int))
69
77
  build_from_value(value[0])
@@ -82,10 +90,22 @@ class Card
82
90
  attr_reader :suit, :face, :value
83
91
  include Comparable
84
92
 
93
+ # Returns a string containing the representation of Card
94
+ #
95
+ # Card.new("7c").to_s # => "7c"
85
96
  def to_s
86
97
  FACES[@face].chr + SUITS[@suit].chr
87
98
  end
88
-
99
+
100
+ # If to_card is called on a `Card` it should return itself
101
+ def to_card
102
+ self
103
+ end
104
+
105
+ # Compare the face value of this card with another card. Returns:
106
+ # -1 if self is less than card2
107
+ # 0 if self is the same face value of card2
108
+ # 1 if self is greater than card2
89
109
  def <=> card2
90
110
  @face <=> card2.face
91
111
  end
@@ -4,9 +4,20 @@ class PokerHand
4
4
  include Comparable
5
5
  attr_reader :hand
6
6
 
7
+ # Returns a new PokerHand object. Accepts the cards represented
8
+ # in a string or an array
9
+ #
10
+ # PokerHand.new("3d 5c 8h Ks") # => #<PokerHand:0x5c673c ...
11
+ # PokerHand.new(["3d", "5c", "8h", "Ks"]) # => #<PokerHand:0x5c2d6c ...
7
12
  def initialize(cards = [])
8
13
  if cards.is_a? Array
9
- @hand = cards.map { |str| Card.new(str.to_s) }
14
+ @hand = cards.map do |card|
15
+ if card.is_a? Card
16
+ card
17
+ else
18
+ Card.new(card.to_s)
19
+ end
20
+ end
10
21
  elsif cards.respond_to?(:to_str)
11
22
  @hand = cards.scan(/\S{2,3}/).map { |str| Card.new(str) }
12
23
  else
@@ -14,20 +25,40 @@ class PokerHand
14
25
  end
15
26
  end
16
27
 
17
- def face_values
18
- @hand.map { |c| c.face }
19
- end
20
-
28
+ # Returns a new PokerHand object with the cards sorted by suit
29
+ # The suit order is spades, hearts, diamonds, clubs
30
+ #
31
+ # PokerHand.new("3d 5c 8h Ks").by_suit.just_cards # => "Ks 8h 3d 5c"
21
32
  def by_suit
22
33
  PokerHand.new(@hand.sort_by { |c| [c.suit, c.face] }.reverse)
23
34
  end
24
35
 
36
+ # Returns a new PokerHand object with the cards sorted by value
37
+ # with the highest value first.
38
+ #
39
+ # PokerHand.new("3d 5c 8h Ks").by_face.just_cards # => "Ks 8h 5c 3d"
25
40
  def by_face
26
41
  PokerHand.new(@hand.sort_by { |c| [c.face, c.suit] }.reverse)
27
42
  end
43
+
44
+ # Returns string representation of the hand without the rank
45
+ #
46
+ # PokerHand.new(["3c", "Kh"]).just_cards # => "3c Kh"
47
+ def just_cards
48
+ @hand.join(" ")
49
+ end
50
+
51
+ # Returns an array of the card values in the hand.
52
+ # The values returned are 1 less than the value on the card.
53
+ # For example: 2's will be shown as 1.
54
+ #
55
+ # PokerHand.new(["3c", "Kh"]).face_values # => [2, 12]
56
+ def face_values
57
+ @hand.map { |c| c.face }
58
+ end
28
59
 
29
60
  def =~ (re)
30
- re.match(@hand.join(' '))
61
+ re.match(just_cards)
31
62
  end
32
63
 
33
64
  def royal_flush?
@@ -192,6 +223,9 @@ class PokerHand
192
223
  ['Highest Card', :highest_card? ],
193
224
  ]
194
225
 
226
+ # Returns the verbose hand rating
227
+ #
228
+ # PokerHand.new("4s 5h 6c 7d 8s").hand_rating # => "Straight"
195
229
  def hand_rating
196
230
  OPS.map { |op|
197
231
  (method(op[1]).call()) ? op[0] : false
@@ -199,7 +233,7 @@ class PokerHand
199
233
  end
200
234
 
201
235
  alias :rank :hand_rating
202
-
236
+
203
237
  def score
204
238
  OPS.map { |op|
205
239
  method(op[1]).call()
@@ -209,19 +243,59 @@ class PokerHand
209
243
  def arranged_hand
210
244
  score[1] + " (#{hand_rating})"
211
245
  end
212
-
213
- def just_cards
214
- @hand.join(" ")
215
- end
216
246
 
247
+ # Returns string with a listing of the cards in the hand followed by the hand's rank.
248
+ #
249
+ # h = PokerHand.new("8c 8s")
250
+ # h.to_s # => "8c 8s (Pair)"
217
251
  def to_s
218
252
  just_cards + " (" + hand_rating + ")"
219
253
  end
220
254
 
255
+ # Returns an array of `Card` objects that make up the `PokerHand`.
256
+ def to_a
257
+ @hand
258
+ end
259
+
260
+ alias :to_ary :to_a
261
+
221
262
  def <=> other_hand
222
263
  self.score <=> other_hand.score
223
264
  end
224
265
 
266
+ # Add a card to the hand
267
+ #
268
+ # hand = PokerHand.new("5d")
269
+ # hand << "6s" # => Add a six of spades to the hand by passing a string
270
+ # hand << ["7h", "8d"] # => Add multiple cards to the hand using an array
271
+ def << new_cards
272
+ # If they only passed one card we need to place it in an array for processing
273
+ new_cards = [new_cards] if new_cards.is_a?(Card)
274
+
275
+ # luckily .each behaves nicely regardless of whether new_cards is a string or array
276
+ new_cards.each do |nc|
277
+ @hand << Card.new(nc)
278
+ end
279
+ end
280
+
281
+ # Remove a card from the hand.
282
+ #
283
+ # hand = PokerHand.new("5d Jd")
284
+ # hand.delete("Jd") # => #<Card:0x5d0674 @value=23, @face=10, @suit=1>
285
+ # hand.just_cards # => "5d"
286
+ def delete card
287
+ @hand.delete(Card.new(card))
288
+ end
289
+
290
+ RESOLVING_METHODS = ['size', '+', '-']
291
+ RESOLVING_METHODS.each do |method|
292
+ class_eval %{
293
+ def #{method}(*args, &block)
294
+ @hand.#{method}(*args, &block)
295
+ end
296
+ }
297
+ end
298
+
225
299
  protected
226
300
 
227
301
  def arrange_hand(md)
@@ -14,6 +14,12 @@ class TestCard < Test::Unit::TestCase
14
14
  @c4 = Card.new("qS")
15
15
  end
16
16
 
17
+ def test_build_from_card
18
+ c1 = Card.new("2c")
19
+ c2 = Card.new(c1)
20
+ assert_equal("2c", c2.to_s)
21
+ end
22
+
17
23
  def test_class_face_value
18
24
  assert_equal(0, Card.face_value('L'))
19
25
  assert_equal(13, Card.face_value('A'))
@@ -102,11 +102,32 @@ class TestPokerHand < Test::Unit::TestCase
102
102
  assert !PokerHand.new("6D 7C 5D 5H 3S").two_pair?
103
103
  end
104
104
 
105
+ def test_matching
106
+ assert_match(/9c/, @trips)
107
+ end
108
+
109
+ def test_size
110
+ assert_equal(2, PokerHand.new("2c 3d").size)
111
+ end
112
+
105
113
  def test_comparisons
106
114
  assert_equal(0, @trips <=> @trips)
107
- assert_equal(1, PokerHand.new("5C JC 2H 5S 3D") <=> PokerHand.new("6D 7C 5D 5H 3S"))
108
- assert_equal(-1, PokerHand.new("6D 7C 5D 5H 3S") <=> PokerHand.new("5C JC 2H 5S 3D"))
115
+ hand1 = PokerHand.new("5C JC 2H 5S 3D")
116
+ hand2 = PokerHand.new("6D 7C 5D 5H 3S")
117
+ assert_equal(1, hand1 <=> hand2)
118
+ assert_equal(-1, hand2 <=> hand1)
119
+ end
120
+
121
+ def test_appending
122
+ ph = PokerHand.new()
123
+ ph << "Qd"
124
+ assert_equal("Qd", ph.just_cards)
125
+ end
126
+
127
+ def test_delete
128
+ ph = PokerHand.new("Ac")
129
+ ph.delete("Ac")
130
+ assert_equal(Array.new, ph.hand)
109
131
  end
110
132
  end
111
133
 
112
- # Number of errors detected: 20
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.0
4
+ version: 0.2.1
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-01-21 00:00:00 -08:00
12
+ date: 2008-02-08 00:00:00 -08:00
13
13
  default_executable:
14
14
  dependencies: []
15
15