rpoker 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 837799d0168ceccf52c989c3b0c4133af13967d5
4
- data.tar.gz: 7f8c046ce3fe08e926c7f6000b1a77743f937dc3
3
+ metadata.gz: 59b9ef52714d62177bd664c67c4d2364d689a25c
4
+ data.tar.gz: 46884f0610f8cbb5bd184ca2b97a1ee8868ba21b
5
5
  SHA512:
6
- metadata.gz: 4d72492401a71f9802a157f5b11aea9ab91604cec64f0ff6d3ad631efa8e9df1453d6d29cd6d5c900e7f91b8aebd01d01fbc055b77cc83680faeb81d8bc82ea5
7
- data.tar.gz: 08f668889a8267825ea742a4e3aaa87d5d1dc5e4301318486a0412794c46b396d225299145c3173642d1169d6889ab46d79766ca8a399fa99f41d12244e86ce5
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 num_value
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
- print cards.map { |card| card.to_s }.join(" ")
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 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
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
- sorted_values == [14, 5, 4, 3, 2]
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? || (sorted_values.first == sorted_values.last + 4 && num_uniq_values == 5)
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
- same_values_in_sorted?(0, 2) && same_values_in_sorted?(3, 4)
75
+ same_values?(0, 2) && same_values?(3, 4)
94
76
  end
95
77
 
96
78
  def four_of_a_kind?
97
- same_values_in_sorted?(0, 3)
79
+ same_values?(0, 3)
98
80
  end
99
81
 
100
82
  def three_of_a_kind?
101
- same_values_in_sorted?(0, 2) && num_uniq_values == 3
83
+ same_values?(0, 2) && num_uniq_values == 3
102
84
  end
103
85
 
104
86
  def two_pair?
105
- same_values_in_sorted?(0, 1) && same_values_in_sorted?(2, 3) && num_uniq_values == 3
87
+ same_values?(0, 1) && same_values?(2, 3) && num_uniq_values == 3
106
88
  end
107
89
 
108
90
  def pair?
109
- same_values_in_sorted?(0, 1) && num_uniq_values == 4
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
@@ -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
- return same_type_winner
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' numeric values
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
- values1, values2 = [hand1, hand2].map(&:uniq_values_sorted_by_count)
45
- values1.zip(values2).each do |v1, v2|
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
- return nil
51
+ nil
53
52
  end
54
53
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rpoker
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ben Cornelis