ruby-poker 0.2.0 → 0.2.1

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
@@ -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