rpoker 0.1.1 → 0.1.2
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 +4 -4
- data/lib/rpoker/card.rb +15 -1
- data/lib/rpoker/hand.rb +44 -33
- data/lib/rpoker/matchup.rb +6 -7
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 59b9ef52714d62177bd664c67c4d2364d689a25c
|
|
4
|
+
data.tar.gz: 46884f0610f8cbb5bd184ca2b97a1ee8868ba21b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 33a3401c1f6272b60b2f8dadc28af9f3ec26070ec67afc0500cdefd1d7f15dc7fa164d4a204670bad1c9f2f8f0b68cb4b6990520150e71a9e31c151b6be42996
|
|
7
|
+
data.tar.gz: 16e3413647dedf0457e538ed7aaef29066ae891706b92b11a769a0239cf95766a97e3c8d3f641207b2e5cfecf09c6dadcf62bb7c141392c7346f9c859fc78c10
|
data/lib/rpoker/card.rb
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
class Card
|
|
2
2
|
attr_reader :value, :suit
|
|
3
3
|
|
|
4
|
+
FACES = %w(T J Q K A)
|
|
5
|
+
SUITS = %w(h d c s)
|
|
6
|
+
VALUES = %w(2 3 4 5 6 7 8 9) + FACES
|
|
7
|
+
|
|
4
8
|
FACE_VALUES = {
|
|
5
9
|
"T" => 10,
|
|
6
10
|
"J" => 11,
|
|
@@ -11,7 +15,10 @@ class Card
|
|
|
11
15
|
|
|
12
16
|
def initialize(string)
|
|
13
17
|
chars = string.split("")
|
|
18
|
+
raise ArgumentError.new("Too many characters") if chars.size > 2
|
|
19
|
+
|
|
14
20
|
@value, @suit = [chars.first.upcase, chars.last.downcase]
|
|
21
|
+
validate!
|
|
15
22
|
end
|
|
16
23
|
|
|
17
24
|
def to_s
|
|
@@ -22,7 +29,14 @@ class Card
|
|
|
22
29
|
value.to_i.to_s != value
|
|
23
30
|
end
|
|
24
31
|
|
|
25
|
-
def
|
|
32
|
+
def to_i
|
|
26
33
|
face_card? ? FACE_VALUES[value] : value.to_i
|
|
27
34
|
end
|
|
35
|
+
|
|
36
|
+
private
|
|
37
|
+
|
|
38
|
+
def validate!
|
|
39
|
+
raise ArgumentError.new("The first character must be a card value") unless VALUES.include?(value)
|
|
40
|
+
raise ArgumentError.new("The second character must be a suit") unless SUITS.include?(suit)
|
|
41
|
+
end
|
|
28
42
|
end
|
data/lib/rpoker/hand.rb
CHANGED
|
@@ -20,7 +20,12 @@ class Hand
|
|
|
20
20
|
cards.map { |card| card.is_a?(Card) ? card : Card.new(card) }
|
|
21
21
|
when String
|
|
22
22
|
cards.split(" ").map {|s| Card.new(s)}
|
|
23
|
+
else
|
|
24
|
+
raise ArgumentError.new("Input must be a string or array")
|
|
23
25
|
end
|
|
26
|
+
|
|
27
|
+
validate!
|
|
28
|
+
sort_cards!
|
|
24
29
|
end
|
|
25
30
|
|
|
26
31
|
def <=>(other_hand)
|
|
@@ -31,7 +36,7 @@ class Hand
|
|
|
31
36
|
end
|
|
32
37
|
|
|
33
38
|
def display
|
|
34
|
-
|
|
39
|
+
puts cards.join(" ")
|
|
35
40
|
end
|
|
36
41
|
|
|
37
42
|
def suits
|
|
@@ -42,39 +47,16 @@ class Hand
|
|
|
42
47
|
@values ||= cards.map(&:value)
|
|
43
48
|
end
|
|
44
49
|
|
|
45
|
-
def
|
|
46
|
-
@
|
|
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
|
|
50
|
+
def int_values
|
|
51
|
+
@int_values ||= cards.map(&:to_i)
|
|
65
52
|
end
|
|
66
53
|
|
|
67
54
|
def num_uniq_values
|
|
68
55
|
@num_uniq_values ||= values.uniq.size
|
|
69
56
|
end
|
|
70
57
|
|
|
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
58
|
def wheel?
|
|
77
|
-
|
|
59
|
+
values == %w(A 5 4 3 2)
|
|
78
60
|
end
|
|
79
61
|
|
|
80
62
|
def flush?
|
|
@@ -82,7 +64,7 @@ class Hand
|
|
|
82
64
|
end
|
|
83
65
|
|
|
84
66
|
def straight?
|
|
85
|
-
wheel? || (
|
|
67
|
+
wheel? || (int_values.first == int_values.last + 4 && num_uniq_values == 5)
|
|
86
68
|
end
|
|
87
69
|
|
|
88
70
|
def straight_flush?
|
|
@@ -90,26 +72,55 @@ class Hand
|
|
|
90
72
|
end
|
|
91
73
|
|
|
92
74
|
def full_house?
|
|
93
|
-
|
|
75
|
+
same_values?(0, 2) && same_values?(3, 4)
|
|
94
76
|
end
|
|
95
77
|
|
|
96
78
|
def four_of_a_kind?
|
|
97
|
-
|
|
79
|
+
same_values?(0, 3)
|
|
98
80
|
end
|
|
99
81
|
|
|
100
82
|
def three_of_a_kind?
|
|
101
|
-
|
|
83
|
+
same_values?(0, 2) && num_uniq_values == 3
|
|
102
84
|
end
|
|
103
85
|
|
|
104
86
|
def two_pair?
|
|
105
|
-
|
|
87
|
+
same_values?(0, 1) && same_values?(2, 3) && num_uniq_values == 3
|
|
106
88
|
end
|
|
107
89
|
|
|
108
90
|
def pair?
|
|
109
|
-
|
|
91
|
+
same_values?(0, 1) && num_uniq_values == 4
|
|
110
92
|
end
|
|
111
93
|
|
|
112
94
|
def rank
|
|
113
95
|
(TYPES.find { |type| send("#{type}?".to_sym) } || "high_card").gsub('_', ' ')
|
|
114
96
|
end
|
|
97
|
+
|
|
98
|
+
private
|
|
99
|
+
# sort cards by their value multiplicity in descending order
|
|
100
|
+
# e.g. sort Js 2s Jh 4s 2c as Js Jh 2s 2c 4s
|
|
101
|
+
def sort_cards!
|
|
102
|
+
vals = cards.map(&:to_i)
|
|
103
|
+
counts = Hash[vals.map { |val| [val, vals.count(val)] }]
|
|
104
|
+
@cards.sort_by! { |card| [-counts[card.to_i], -card.to_i] }
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def same_values?(start, stop)
|
|
108
|
+
vals = values[start..stop]
|
|
109
|
+
vals.all? { |value| value == vals.first }
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def validate!
|
|
113
|
+
validate_length!
|
|
114
|
+
check_for_duplicates!
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def validate_length!
|
|
118
|
+
raise ArgumentError.new("A hand must contain 5 cards") unless cards.size == 5
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def check_for_duplicates!
|
|
122
|
+
unless cards.map(&:to_s).uniq.size == 5
|
|
123
|
+
raise ArgumentError.new("A hand cannot contain duplicate cards")
|
|
124
|
+
end
|
|
125
|
+
end
|
|
115
126
|
end
|
data/lib/rpoker/matchup.rb
CHANGED
|
@@ -22,16 +22,15 @@ class Matchup
|
|
|
22
22
|
|
|
23
23
|
# both hands are high card rank and can be compared by
|
|
24
24
|
# comparing values
|
|
25
|
-
|
|
25
|
+
same_type_winner
|
|
26
26
|
end
|
|
27
27
|
|
|
28
28
|
private
|
|
29
29
|
# for two hands of the same type (straight, flush, etc):
|
|
30
|
-
# returns the winner by sorting the hands'
|
|
30
|
+
# returns the winner by sorting the hands' integer values
|
|
31
31
|
# and then comparing value pairs in descending order
|
|
32
32
|
def same_type_winner
|
|
33
|
-
|
|
34
|
-
# check for the special case where one hand is a wheel
|
|
33
|
+
# check for the special case where either hand is a wheel
|
|
35
34
|
if hand1.wheel? && hand2.wheel?
|
|
36
35
|
return nil
|
|
37
36
|
elsif hand1.wheel?
|
|
@@ -41,14 +40,14 @@ class Matchup
|
|
|
41
40
|
end
|
|
42
41
|
|
|
43
42
|
# compare the numeric value pairs
|
|
44
|
-
|
|
45
|
-
|
|
43
|
+
value_pairs = hand1.int_values.zip(hand2.int_values)
|
|
44
|
+
value_pairs.each do |v1, v2|
|
|
46
45
|
if v1 > v2
|
|
47
46
|
return hand1
|
|
48
47
|
elsif v2 > v1
|
|
49
48
|
return hand2
|
|
50
49
|
end
|
|
51
50
|
end
|
|
52
|
-
|
|
51
|
+
nil
|
|
53
52
|
end
|
|
54
53
|
end
|