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