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 +5 -0
- data/LICENSE +27 -0
- data/README +40 -0
- data/lib/array_helper.rb +25 -0
- data/lib/card.rb +22 -0
- data/lib/poker_hand.rb +161 -0
- data/lib/rank.rb +48 -0
- data/lib/ruby-poker.rb +1 -0
- metadata +62 -0
data/CHANGELOG
ADDED
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
|
data/lib/array_helper.rb
ADDED
|
@@ -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
|
+
|