rpoker 0.1.0
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.
- checksums.yaml +7 -0
- data/lib/rpoker/card.rb +28 -0
- data/lib/rpoker/hand.rb +115 -0
- data/lib/rpoker/matchup.rb +54 -0
- data/lib/rpoker.rb +3 -0
- metadata +48 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 14c1fe8bbdb62e78f7cf12668b8c4c96392fb18c
|
4
|
+
data.tar.gz: c09fbd0fa370841e8fa10bb54308b5f1a6e0975f
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 1804d821324d68dec6fcc5604991244505bf18dbb1120cdbae2c585df6b1f9b99c9d8926aa24d2ee8ceb4a2a2a11ae9be0ad3f667a86b06a19274d1f5ef23d34
|
7
|
+
data.tar.gz: 92bec40a278e09dc0916ceb590bda945f9921e61c75551c036033db9a6334297685bc2e950fc317bc39fb632553dfe85c3a91a0b0645383c4340d865fd215a98
|
data/lib/rpoker/card.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
class Card
|
2
|
+
attr_reader :value, :suit
|
3
|
+
|
4
|
+
FACE_VALUES = {
|
5
|
+
"T" => 10,
|
6
|
+
"J" => 11,
|
7
|
+
"Q" => 12,
|
8
|
+
"K" => 13,
|
9
|
+
"A" => 14
|
10
|
+
}
|
11
|
+
|
12
|
+
def initialize(string)
|
13
|
+
chars = string.split("")
|
14
|
+
@value, @suit = [chars.first.upcase, chars.last.downcase]
|
15
|
+
end
|
16
|
+
|
17
|
+
def to_s
|
18
|
+
"#{@value}#{@suit}"
|
19
|
+
end
|
20
|
+
|
21
|
+
def face_card?
|
22
|
+
value.to_i.to_s != value
|
23
|
+
end
|
24
|
+
|
25
|
+
def num_value
|
26
|
+
face_card? ? FACE_VALUES[value] : value.to_i
|
27
|
+
end
|
28
|
+
end
|
data/lib/rpoker/hand.rb
ADDED
@@ -0,0 +1,115 @@
|
|
1
|
+
class Hand
|
2
|
+
include Comparable
|
3
|
+
attr_reader :cards
|
4
|
+
|
5
|
+
TYPES = %w(
|
6
|
+
straight_flush
|
7
|
+
four_of_a_kind
|
8
|
+
full_house
|
9
|
+
flush
|
10
|
+
straight
|
11
|
+
three_of_a_kind
|
12
|
+
two_pair
|
13
|
+
pair
|
14
|
+
)
|
15
|
+
|
16
|
+
def initialize(cards)
|
17
|
+
@cards =
|
18
|
+
case cards
|
19
|
+
when Array
|
20
|
+
cards.map { |card| card.is_a?(Card) ? card : Card.new(card) }
|
21
|
+
when String
|
22
|
+
cards.split(" ").map {|s| Card.new(s)}
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def <=>(other_hand)
|
27
|
+
winner = Matchup.new(self, other_hand).winner
|
28
|
+
return 1 if winner == self
|
29
|
+
return 0 if winner == nil
|
30
|
+
return -1 if winner == other_hand
|
31
|
+
end
|
32
|
+
|
33
|
+
def display
|
34
|
+
print cards.map { |card| card.to_s }.join(" ")
|
35
|
+
end
|
36
|
+
|
37
|
+
def suits
|
38
|
+
@suits ||= cards.map(&:suit)
|
39
|
+
end
|
40
|
+
|
41
|
+
def values
|
42
|
+
@values ||= cards.map(&:value)
|
43
|
+
end
|
44
|
+
|
45
|
+
def num_values
|
46
|
+
@num_values ||= cards.map(&:num_value)
|
47
|
+
end
|
48
|
+
|
49
|
+
def sorted_values
|
50
|
+
@sorted_values ||= num_values.sort.reverse
|
51
|
+
end
|
52
|
+
|
53
|
+
# sort card values by their multiplicity in descending order
|
54
|
+
# e.g. for the hand Js 2s Jh 4s 2c the method returns [11, 11, 2, 2, 4]
|
55
|
+
def values_sorted_by_count
|
56
|
+
@values_sorted_by_count ||=
|
57
|
+
[4,3,2,1].inject([]) { |sorted, n|
|
58
|
+
sorted += sorted_values.select { |value| sorted_values.count(value) == n } }
|
59
|
+
end
|
60
|
+
|
61
|
+
# sort distinct card values by their multiplicity in descending order
|
62
|
+
# e.g. for the hand Js 2s Jh 4s 2c the method returns [11, 2, 4]
|
63
|
+
def uniq_values_sorted_by_count
|
64
|
+
@uniq_values_sorted_by_count ||= values_sorted_by_count.uniq
|
65
|
+
end
|
66
|
+
|
67
|
+
def num_uniq_values
|
68
|
+
@num_uniq_values ||= values.uniq.size
|
69
|
+
end
|
70
|
+
|
71
|
+
def same_values_in_sorted?(start, stop)
|
72
|
+
values_slice = values_sorted_by_count[start..stop]
|
73
|
+
values_slice.all? { |value| value == values_slice.first }
|
74
|
+
end
|
75
|
+
|
76
|
+
def wheel?
|
77
|
+
sorted_values == [14, 5, 4, 3, 2]
|
78
|
+
end
|
79
|
+
|
80
|
+
def flush?
|
81
|
+
suits.all? { |suit| suit == suits.first }
|
82
|
+
end
|
83
|
+
|
84
|
+
def straight?
|
85
|
+
wheel? || (sorted_values.first == sorted_values.last + 4 && num_uniq_values == 5)
|
86
|
+
end
|
87
|
+
|
88
|
+
def straight_flush?
|
89
|
+
flush? && straight?
|
90
|
+
end
|
91
|
+
|
92
|
+
def full_house?
|
93
|
+
same_values_in_sorted?(0, 2) && same_values_in_sorted?(3, 4)
|
94
|
+
end
|
95
|
+
|
96
|
+
def four_of_a_kind?
|
97
|
+
same_values_in_sorted?(0, 3)
|
98
|
+
end
|
99
|
+
|
100
|
+
def three_of_a_kind?
|
101
|
+
same_values_in_sorted?(0, 2) && num_uniq_values == 3
|
102
|
+
end
|
103
|
+
|
104
|
+
def two_pair?
|
105
|
+
same_values_in_sorted?(0, 1) && same_values_in_sorted?(2, 3) && num_uniq_values == 3
|
106
|
+
end
|
107
|
+
|
108
|
+
def pair?
|
109
|
+
same_values_in_sorted?(0, 1) && num_uniq_values == 4
|
110
|
+
end
|
111
|
+
|
112
|
+
def rank
|
113
|
+
(TYPES.find { |type| send("#{type}?".to_sym) } || "high_card").gsub('_', ' ')
|
114
|
+
end
|
115
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
class Matchup
|
2
|
+
attr_reader :hand1, :hand2
|
3
|
+
|
4
|
+
def initialize(hand1, hand2)
|
5
|
+
@hand1, @hand2 = hand1, hand2
|
6
|
+
end
|
7
|
+
|
8
|
+
def winner
|
9
|
+
Hand::TYPES.each do |type|
|
10
|
+
# build the boolean type check method
|
11
|
+
is_type = "#{type}?".to_sym
|
12
|
+
|
13
|
+
# check whether either hand is of the type
|
14
|
+
if hand1.send(is_type) && hand2.send(is_type)
|
15
|
+
return same_type_winner
|
16
|
+
elsif hand1.send(is_type)
|
17
|
+
return hand1
|
18
|
+
elsif hand2.send(is_type)
|
19
|
+
return hand2
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# both hands are high card rank and can be compared by
|
24
|
+
# comparing values
|
25
|
+
return same_type_winner
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
# for two hands of the same type (straight, flush, etc):
|
30
|
+
# returns the winner by sorting the hands' numeric values
|
31
|
+
# and then comparing value pairs in descending order
|
32
|
+
def same_type_winner
|
33
|
+
|
34
|
+
# check for the special case where one hand is a wheel
|
35
|
+
if hand1.wheel? && hand2.wheel?
|
36
|
+
return nil
|
37
|
+
elsif hand1.wheel?
|
38
|
+
return hand1
|
39
|
+
elsif hand2.wheel?
|
40
|
+
return hand2
|
41
|
+
end
|
42
|
+
|
43
|
+
# compare the numeric value pairs
|
44
|
+
values1, values2 = [hand1, hand2].map(&:uniq_values_sorted_by_count)
|
45
|
+
values1.zip(values2).each do |v1, v2|
|
46
|
+
if v1 > v2
|
47
|
+
return hand1
|
48
|
+
elsif v2 > v1
|
49
|
+
return hand2
|
50
|
+
end
|
51
|
+
end
|
52
|
+
return nil
|
53
|
+
end
|
54
|
+
end
|
data/lib/rpoker.rb
ADDED
metadata
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rpoker
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Ben Cornelis
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-09-17 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description:
|
14
|
+
email: bencornelis02@gmail.com
|
15
|
+
executables: []
|
16
|
+
extensions: []
|
17
|
+
extra_rdoc_files: []
|
18
|
+
files:
|
19
|
+
- lib/rpoker.rb
|
20
|
+
- lib/rpoker/card.rb
|
21
|
+
- lib/rpoker/hand.rb
|
22
|
+
- lib/rpoker/matchup.rb
|
23
|
+
homepage: http://rubygems.org/gems/rpoker
|
24
|
+
licenses:
|
25
|
+
- MIT
|
26
|
+
metadata: {}
|
27
|
+
post_install_message:
|
28
|
+
rdoc_options: []
|
29
|
+
require_paths:
|
30
|
+
- lib
|
31
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
32
|
+
requirements:
|
33
|
+
- - ">="
|
34
|
+
- !ruby/object:Gem::Version
|
35
|
+
version: '0'
|
36
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
requirements: []
|
42
|
+
rubyforge_project:
|
43
|
+
rubygems_version: 2.4.8
|
44
|
+
signing_key:
|
45
|
+
specification_version: 4
|
46
|
+
summary: Ruby library for comparing and ranking poker hands
|
47
|
+
test_files: []
|
48
|
+
has_rdoc:
|