ruby-poker 0.1.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 ADDED
@@ -0,0 +1,5 @@
1
+ 2008-01-10 (0.1.0)
2
+ * Initial version
3
+ 2008-01-11 (0.1.1)
4
+ * Ranks are now a class.
5
+ * Added gem packaging
data/LICENSE ADDED
@@ -0,0 +1,27 @@
1
+ Copyright (c) 2008, Robert Olson
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without
5
+ modification, are permitted provided that the following conditions
6
+ are met:
7
+
8
+ * Redistributions of source code must retain the above copyright
9
+ notice, this list of conditions and the following disclaimer.
10
+ * Redistributions in binary form must reproduce the above copyright
11
+ notice, this list of conditions and the following disclaimer in
12
+ the documentation and/or other materials provided with the distribution.
13
+ * Neither the name of the author nor the names of its
14
+ contributors may be used to endorse or promote products derived
15
+ from this software without specific prior written permission.
16
+
17
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
+ POSSIBILITY OF SUCH DAMAGE.
data/README ADDED
@@ -0,0 +1,40 @@
1
+ = Poker hand evaluator for Ruby
2
+
3
+ == Author
4
+
5
+ Robert Olson mailto:rko618@gmail.com
6
+
7
+ == License
8
+
9
+ This is free software; you can redistribute it and/or modify it under the
10
+ terms of the BSD license. See LICENSE for more details.
11
+
12
+ == Download
13
+
14
+ The latest version of <b>ruby poker</b> can be found at
15
+
16
+ * http://rubyforge.org/frs/?group_id=5257
17
+
18
+ The homepage of this project is located at
19
+
20
+ * http://rubyforge.org/projects/rubypoker
21
+
22
+ == Description
23
+
24
+ This class handles poker logic for 5 card poker hands.
25
+
26
+ Card representations can be passed to the PokerHand constructor as a string or an array.
27
+ Face cards (cards ten, jack, queen, king, and ace) can be created using their
28
+ value (10, 11, 12, 13, 14) or letter representation (T, J, Q, K, A)
29
+
30
+ == Examples
31
+
32
+ In this section some examples show what can be done with this class.
33
+
34
+ hand1 = PokerHand.new("8H 9C TC JD QH")
35
+ hand2 = PokerHand.new(["3D", "3C", "3S", "13D", "14H"])
36
+ puts hand1 => 8H 9C 10C 11D 12H
37
+ puts hand1.rank => Straight
38
+ puts hand2 => 3D 3C 3S 13D 14H
39
+ puts hand2.rank => Three of a Kind
40
+ puts hand1 > hand2 => true
@@ -0,0 +1,25 @@
1
+ module ArrayHelper
2
+ class Array < ::Array
3
+ # Returns array of elements that only occur once
4
+ # [1, 1, 2, 3] => [2, 3]
5
+ def singles
6
+ counts = Hash.new(0)
7
+ self.each do |value|
8
+ counts[value] += 1
9
+ end
10
+
11
+ return counts.collect {|key,value| value == 1 ? key : nil }.compact.sort
12
+ end
13
+
14
+ # Returns an array containing values that we duplicated in the original array
15
+ # [1, 2, 3, 1] => [1]
16
+ def duplicates
17
+ counts = Hash.new(0)
18
+ self.each do |value|
19
+ counts[value] += 1
20
+ end
21
+
22
+ return counts.collect {|key,value| value > 1 ? key : nil }.compact.sort
23
+ end
24
+ end # class Array
25
+ end # module ArrayHelper
data/lib/card.rb ADDED
@@ -0,0 +1,22 @@
1
+ class PokerHand
2
+
3
+ class Card
4
+ include Comparable
5
+ attr_reader :suit, :value
6
+
7
+ def initialize card_str
8
+ card_str = card_str.gsub("T","10").gsub("J","11").gsub("Q","12").gsub("K","13").gsub("A","14")
9
+ @value = card_str[0, card_str.length-1].to_i
10
+ @suit = card_str[-1,1]
11
+ end
12
+
13
+ def <=> card2
14
+ @value <=> card2.value
15
+ end
16
+
17
+ def to_s
18
+ @value.to_s + @suit
19
+ end
20
+ end # class Card
21
+
22
+ end # class PokerHand
data/lib/poker_hand.rb ADDED
@@ -0,0 +1,161 @@
1
+ # poker_hand.rb
2
+
3
+ require 'array_helper.rb'
4
+ require 'rank.rb'
5
+ require 'card.rb'
6
+
7
+ class PokerHand
8
+
9
+ include ArrayHelper
10
+ include Comparable
11
+ attr_reader :cards, :values_hash
12
+
13
+ def initialize cards
14
+ @cards = Array.new
15
+ @values_hash = Hash.new(0)
16
+
17
+ begin
18
+ if cards.class == String
19
+ cards = cards.split
20
+ end
21
+
22
+ cards.each {|c| @cards << Card.new(c)}
23
+
24
+ @cards.each {|c| @values_hash[c.value] += 1}
25
+ rescue
26
+ raise "Unable to process cards input. Please check the documentation for acceptable input formats"
27
+ end
28
+ end
29
+
30
+ def rank
31
+ @rank ||= self.determine_rank
32
+ end
33
+
34
+ # Returns an array of all the values in the hand. Does not
35
+ # sort the values before returning them so Array#sort should
36
+ # be called on the return value if sorting is desired.
37
+ def values
38
+ @cards.collect {|c| c.value}
39
+ end
40
+
41
+ # Flush if the cards are all the same suit.
42
+ def flush?
43
+ @cards.collect {|c| c.suit}.uniq.size == 1
44
+ end
45
+
46
+ # Straight if all cards are consecutive values.
47
+ def straight?
48
+ straight = true # innocent until proven guilty
49
+ c_values = self.values.sort
50
+ i = c_values.first
51
+ c_values.each do |v|
52
+ straight &&= (v == i)
53
+ i += 1
54
+ end
55
+ return straight
56
+ end
57
+
58
+ # Royal Flush: Ten, Jack, Queen, King, Ace, in same suit.
59
+ def royal_flush?
60
+ self.flush? and self.values.sort == [10,11,12,13,14]
61
+ end
62
+
63
+ # Straight Flush: All cards are consecutive values of same suit.
64
+ def straight_flush?
65
+ self.flush? and self.straight?
66
+ end
67
+
68
+ # Full House: Three of a kind and a pair.
69
+ def full_house?
70
+ @values_hash.has_value?(3) and @values_hash.has_value?(2)
71
+ end
72
+
73
+ # Three of a Kind: Three cards of the same value.
74
+ def three_of_a_kind?
75
+ @values_hash.has_value?(3) and not full_house?
76
+ end
77
+
78
+ # Four of a Kind: Four cards of the same value.
79
+ def four_of_a_kind?
80
+ @values_hash.has_value?(4)
81
+ end
82
+
83
+ # Two Pair: Two different pairs.
84
+ def two_pair?
85
+ @values_hash.select {|k, v| v == 2}.size == 2 # check if two seperate values have two occurances
86
+ end
87
+
88
+ # One Pair: Two cards of the same value.
89
+ def one_pair?
90
+ @values_hash.select {|k, v| v == 2}.size == 1
91
+ end
92
+
93
+ def <=> hand2
94
+ if self.rank != hand2.rank
95
+ self.rank <=> hand2.rank
96
+ else # we have a tie... do a tie breaker
97
+ case self.rank.value # both hands have the same rank
98
+ when 0, 4, 5, 8 # highest card, straight, flush, straight flush
99
+ # check who has the highest card, if same move to the next card, etc
100
+ self.values.sort.reverse <=> hand2.values.sort.reverse
101
+ when 1 # two people with one pair
102
+ # check which pair is higher, if the pairs are the same then remove the pairs and check
103
+ # for highest card
104
+ hand1_pair = @values_hash.index(2) # get key(card value) of the duplicate pair
105
+ hand2_pair = hand2.values_hash.index(2)
106
+ if hand1_pair == hand2_pair
107
+ return self.values.singles.reverse <=> hand2.values.singles.reverse
108
+ else
109
+ return hand1_pair <=> hand2_pair
110
+ end
111
+ when 2 # two people with two pairs
112
+ # check who has the higher pair, if the pairs are the same
113
+ # then remove the pairs and check for highest card
114
+ hand1_pairs = self.values.duplicates.reverse
115
+ hand2_pairs = hand2.values.duplicates.reverse
116
+ if hand1_pairs == hand2_pairs
117
+ return self.values.singles <=> hand2.values.singles # there will be only one card remaining
118
+ else
119
+ return hand1_pairs <=> hand2_pairs
120
+ end
121
+ when 3, 6 # three_of_a_kind, full house
122
+ @values_hash.index(3) <=> hand2.values_hash.index(3)
123
+ when 7 # four of a kind
124
+ @values_hash.index(4) <=> hand2.values_hash.index(4)
125
+ when 9 # royal flush
126
+ return 0 # royal flushes always tie
127
+ end
128
+ end
129
+ end
130
+
131
+ def to_s
132
+ @cards.inject("") {|str, c| str << "#{c.to_s} "}.rstrip
133
+ end
134
+
135
+ protected
136
+
137
+ def determine_rank
138
+ if royal_flush?
139
+ r = Rank::ROYAL_FLUSH
140
+ elsif straight_flush?
141
+ r = Rank::STRAIGHT_FLUSH
142
+ elsif four_of_a_kind?
143
+ r = Rank::FOUR_OF_A_KIND
144
+ elsif full_house?
145
+ r = Rank::FULL_HOUSE
146
+ elsif flush?
147
+ r = Rank::FLUSH
148
+ elsif straight?
149
+ r = Rank::STRAIGHT
150
+ elsif three_of_a_kind?
151
+ r = Rank::THREE_OF_A_KIND
152
+ elsif two_pair?
153
+ r = Rank::TWO_PAIR
154
+ elsif one_pair?
155
+ r = Rank::PAIR
156
+ else
157
+ r = Rank::HIGH_CARD
158
+ end
159
+ return Rank.new(r)
160
+ end
161
+ end # class PokerHand
data/lib/rank.rb ADDED
@@ -0,0 +1,48 @@
1
+ class PokerHand
2
+
3
+ # Rank objects maintain the poker value of the hand. Ex. Full House
4
+ class Rank
5
+ include Comparable
6
+ attr_accessor :value
7
+
8
+ HIGH_CARD = 0
9
+ PAIR = 1
10
+ TWO_PAIR = 2
11
+ THREE_OF_A_KIND = 3
12
+ STRAIGHT = 4
13
+ FLUSH = 5
14
+ FULL_HOUSE = 6
15
+ FOUR_OF_A_KIND = 7
16
+ STRAIGHT_FLUSH = 8
17
+ ROYAL_FLUSH = 9
18
+
19
+ # Creates a new Rank instance of <code>value</code>
20
+ # Values can be 0-9. Consider using the Rank constants
21
+ # for the hand values.
22
+ def initialize value
23
+ @value = value
24
+ end
25
+
26
+ # Returns the text representation of the poker rank. Ex. "Two Pair"
27
+ def to_s
28
+ case @value
29
+ when 0: "High Card"
30
+ when 1: "Pair"
31
+ when 2: "Two Pair"
32
+ when 3: "Three of a Kind"
33
+ when 4: "Straight"
34
+ when 5: "Flush"
35
+ when 6: "Full House"
36
+ when 7: "Four of a Kind"
37
+ when 8: "Straight Flush"
38
+ when 9: "Royal Flush"
39
+ else "Unknown"
40
+ end
41
+ end
42
+
43
+ def <=> other
44
+ @value <=> other.value
45
+ end
46
+ end # class Rank
47
+
48
+ end
data/lib/ruby-poker.rb ADDED
@@ -0,0 +1 @@
1
+ require 'poker_hand'
metadata ADDED
@@ -0,0 +1,62 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ruby-poker
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ platform: ruby
6
+ authors:
7
+ - Robert Olson
8
+ autorequire: ruby-poker
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2008-01-12 00:00:00 -08:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description:
17
+ email: rko618@gmail.com
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files:
23
+ - README
24
+ - CHANGELOG
25
+ - LICENSE
26
+ files:
27
+ - lib/array_helper.rb
28
+ - lib/card.rb
29
+ - lib/poker_hand.rb
30
+ - lib/rank.rb
31
+ - lib/ruby-poker.rb
32
+ - README
33
+ - CHANGELOG
34
+ - LICENSE
35
+ has_rdoc: true
36
+ homepage: http://rubyforge.org/projects/rubypoker/
37
+ post_install_message:
38
+ rdoc_options: []
39
+
40
+ require_paths:
41
+ - lib
42
+ required_ruby_version: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: "0"
47
+ version:
48
+ required_rubygems_version: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: "0"
53
+ version:
54
+ requirements: []
55
+
56
+ rubyforge_project: rubypoker
57
+ rubygems_version: 1.0.1
58
+ signing_key:
59
+ specification_version: 2
60
+ summary: Ruby library for determining the winner in a game of poker.
61
+ test_files: []
62
+