rora 0.0.6 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +59 -15
- data/Rakefile +0 -1
- data/lib/rora.rb +4 -0
- data/lib/rora/{hands.csv → 5-card-hands.csv} +0 -0
- data/lib/rora/7-card-hands.csv +323765 -0
- data/lib/rora/cards.csv +52 -0
- data/lib/rora/flushes.csv +40 -0
- data/lib/rora/model/board.rb +2 -2
- data/lib/rora/model/card.rb +17 -14
- data/lib/rora/model/deck.rb +23 -0
- data/lib/rora/model/equity.rb +18 -0
- data/lib/rora/model/hand.rb +12 -27
- data/lib/rora/model/hand_type.rb +1 -1
- data/lib/rora/model/pot.rb +1 -1
- data/lib/rora/model/rank.rb +34 -16
- data/lib/rora/model/starting_hand.rb +22 -18
- data/lib/rora/model/suit.rb +26 -11
- data/lib/rora/model/table.rb +0 -3
- data/lib/rora/repository/card_repository.rb +17 -0
- data/lib/rora/repository/hand_repository.rb +60 -20
- data/lib/rora/repository/starting_hand_repository.rb +2 -1
- data/lib/rora/utils/equity_calculator.rb +47 -0
- data/lib/rora/utils/hand_ranking_generator.rb +135 -0
- data/test/rora/model/board_test.rb +19 -20
- data/test/rora/model/card_test.rb +45 -15
- data/test/rora/model/deck_test.rb +24 -0
- data/test/rora/model/hand_test.rb +5 -29
- data/test/rora/model/hand_type_test.rb +3 -3
- data/test/rora/model/pot_test.rb +2 -2
- data/test/rora/model/rank_test.rb +10 -2
- data/test/rora/model/seat_test.rb +1 -1
- data/test/rora/model/starting_hand_test.rb +8 -16
- data/test/rora/model/suit_test.rb +3 -3
- data/test/rora/model/table_test.rb +8 -8
- data/test/rora/repository/hand_repository_test.rb +14 -16
- data/test/rora/utils/equity_calculator_test.rb +53 -0
- data/test/rora_test.rb +1 -1
- metadata +13 -6
- data/test/rora/model/game_test.rb +0 -23
data/lib/rora/model/suit.rb
CHANGED
@@ -5,12 +5,15 @@
|
|
5
5
|
# of cards has four suits: hearts, clubs, spades, and diamonds.
|
6
6
|
#
|
7
7
|
class Suit
|
8
|
-
|
9
|
-
|
10
|
-
|
8
|
+
include Comparable
|
9
|
+
|
10
|
+
attr_reader :id, :key, :value, :order
|
11
|
+
|
12
|
+
def initialize(id, key, value, order)
|
11
13
|
@id = id
|
12
14
|
@key = key
|
13
15
|
@value = value
|
16
|
+
@order = order
|
14
17
|
end
|
15
18
|
|
16
19
|
def self.values
|
@@ -21,23 +24,35 @@ class Suit
|
|
21
24
|
self.values.each do |suit|
|
22
25
|
return suit if suit.key.casecmp(key) == 0
|
23
26
|
end
|
24
|
-
raise ArgumentError, "No suit exists for key "
|
27
|
+
raise ArgumentError, "No suit exists for key '#{key}'"
|
25
28
|
end
|
26
29
|
|
27
|
-
def
|
28
|
-
|
30
|
+
def <=>(suit)
|
31
|
+
self.order <=> suit.order
|
32
|
+
end
|
33
|
+
|
34
|
+
def eql? suit
|
35
|
+
self == suit
|
29
36
|
end
|
30
37
|
|
31
38
|
def == suit
|
32
|
-
self.
|
39
|
+
self.key == suit.key
|
40
|
+
end
|
41
|
+
|
42
|
+
def hash
|
43
|
+
return self.key.ord
|
44
|
+
end
|
45
|
+
|
46
|
+
def to_s
|
47
|
+
"#{@value}s"
|
33
48
|
end
|
34
49
|
|
35
50
|
class << self
|
36
51
|
private :new
|
37
52
|
end
|
38
53
|
|
39
|
-
HEART = new(
|
40
|
-
|
41
|
-
|
42
|
-
|
54
|
+
HEART = new(2, "H", "Heart", 1)
|
55
|
+
DIAMOND = new(3, "D", "Diamond", 2)
|
56
|
+
SPADE = new(5, "S", "Spade", 3)
|
57
|
+
CLUB = new(7, "C", "Club", 4)
|
43
58
|
end
|
data/lib/rora/model/table.rb
CHANGED
@@ -36,17 +36,14 @@ class Table
|
|
36
36
|
end
|
37
37
|
|
38
38
|
def the_small_blind
|
39
|
-
raise RuntimeError, "There are fewer than two players at the table" if players.size < 2
|
40
39
|
players.size == 2 ? the_button : the_seat_after(the_button)
|
41
40
|
end
|
42
41
|
|
43
42
|
def the_big_blind
|
44
|
-
raise RuntimeError, "There are fewer than two players at the table" if players.size < 2
|
45
43
|
the_seat_after the_small_blind
|
46
44
|
end
|
47
45
|
|
48
46
|
def under_the_gun
|
49
|
-
raise RuntimeError, "There are fewer than two players at the table" if players.size < 2
|
50
47
|
the_seat_after(the_big_blind)
|
51
48
|
end
|
52
49
|
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'csv'
|
2
|
+
require 'singleton'
|
3
|
+
|
4
|
+
class CardRepository
|
5
|
+
include Singleton
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@card_table = Hash.new
|
9
|
+
CSV.foreach("lib/rora/cards.csv") do |row|
|
10
|
+
@card_table[row[0]] = row[1].to_i
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def get(key)
|
15
|
+
@card_table.fetch(key)
|
16
|
+
end
|
17
|
+
end
|
@@ -4,16 +4,43 @@ require 'singleton'
|
|
4
4
|
class HandRepository
|
5
5
|
include Singleton
|
6
6
|
|
7
|
+
HEART_FLUSH=32
|
8
|
+
DIAMOND_FLUSH=243
|
9
|
+
SPADE_FLUSH=3125
|
10
|
+
CLUB_FLUSH=16807
|
11
|
+
|
7
12
|
def initialize
|
8
13
|
@hands = Array.new
|
9
|
-
|
10
|
-
|
11
|
-
|
14
|
+
|
15
|
+
@five_card_table = Hash.new
|
16
|
+
CSV.foreach("lib/rora/5-card-hands.csv") do |row|
|
17
|
+
@five_card_table[row[1].to_i] = [row[0].to_i, row[3], row[4]]
|
18
|
+
end
|
19
|
+
|
20
|
+
@seven_card_table = Hash.new
|
21
|
+
CSV.foreach("lib/rora/7-card-hands.csv") do |row|
|
22
|
+
@seven_card_table[row[1].to_i] = [row[0].to_i, row[4], row[5]]
|
23
|
+
end
|
24
|
+
|
25
|
+
@flushes_table = Hash.new
|
26
|
+
CSV.foreach("lib/rora/flushes.csv") do |row|
|
27
|
+
@flushes_table[row[0].to_i] = [row[1].to_i, row[2]]
|
12
28
|
end
|
13
29
|
end
|
14
30
|
|
15
|
-
def
|
16
|
-
|
31
|
+
def evaluate_5_card_hand(cards)
|
32
|
+
flush = Hand.new(cards).flush?
|
33
|
+
@five_card_table.fetch(cards.inject(1) {|product, card| product * card.rank.id} * (flush ? 67 : 1))
|
34
|
+
end
|
35
|
+
|
36
|
+
def evaluate_7_card_hand(cards)
|
37
|
+
key = generate_suit_key(cards)
|
38
|
+
flush = has_flush?(key)
|
39
|
+
flush ? get_best_hand(cards, key) : @seven_card_table.fetch(cards[0].rank.id * cards[1].rank.id * cards[2].rank.id * cards[3].rank.id * cards[4].rank.id * cards[5].rank.id * cards[6].rank.id)
|
40
|
+
end
|
41
|
+
|
42
|
+
def has_flush?(key)
|
43
|
+
key % HEART_FLUSH == 0 || key % DIAMOND_FLUSH == 0 || key % SPADE_FLUSH == 0 || key % CLUB_FLUSH == 0
|
17
44
|
end
|
18
45
|
|
19
46
|
# Returns all possible poker hands.
|
@@ -58,29 +85,28 @@ class HandRepository
|
|
58
85
|
# Starting Hand, Board and Deck
|
59
86
|
# This method will return all poker hands that can be made with the given starting
|
60
87
|
# hand and cards that remain in the deck.
|
61
|
-
def list
|
62
|
-
return
|
88
|
+
def list(arguments=nil)
|
89
|
+
return all_hands if arguments.nil? || arguments[:starting_hand].nil?
|
63
90
|
|
64
91
|
starting_hand = arguments[:starting_hand]
|
65
92
|
deck = arguments[:deck].nil? ? Deck.new : arguments[:deck]
|
66
93
|
board = arguments[:board]
|
67
|
-
|
94
|
+
spec_hands = Array.new
|
68
95
|
|
69
96
|
if !board.nil?
|
70
97
|
raise RuntimeError if board.contains_any? starting_hand.cards
|
71
98
|
if board.cards.size == 5
|
72
|
-
(board.cards + starting_hand.cards).combination(5).to_a.each { |cards|
|
73
|
-
return hands
|
99
|
+
(board.cards + starting_hand.cards).combination(5).to_a.each { |cards| spec_hands << Hand.new(cards) }
|
74
100
|
else
|
75
101
|
deck.remove(starting_hand).remove(board).combination(5 - board.cards.size).to_a.each do |cards|
|
76
|
-
(starting_hand.cards + board.cards + cards).combination(5).to_a.each { |cds|
|
102
|
+
(starting_hand.cards + board.cards + cards).combination(5).to_a.each { |cds| spec_hands << Hand.new(cds) }
|
77
103
|
end
|
78
|
-
return hands
|
79
104
|
end
|
105
|
+
return spec_hands
|
80
106
|
end
|
81
107
|
|
82
|
-
deck.remove(starting_hand).combination(3).each { |cards|
|
83
|
-
|
108
|
+
deck.remove(starting_hand).combination(3).each { |cards| spec_hands << Hand.new(cards + starting_hand.cards) }
|
109
|
+
spec_hands
|
84
110
|
end
|
85
111
|
|
86
112
|
# Returns unique poker hands.
|
@@ -110,20 +136,34 @@ class HandRepository
|
|
110
136
|
#
|
111
137
|
# This method carries the same semantics as the list method, but returns unique hands instead of
|
112
138
|
# every possible hand.
|
113
|
-
def
|
114
|
-
|
115
|
-
return
|
139
|
+
def list_and_group_by_hand_score(arguments=nil)
|
140
|
+
spec_hands = list(arguments)
|
141
|
+
return spec_hands if spec_hands.nil? || spec_hands.size == 0
|
116
142
|
|
117
143
|
hash = Hash.new
|
118
|
-
|
119
|
-
hash[
|
144
|
+
spec_hands.each do |hand|
|
145
|
+
hash[(hand.cards.inject(1) {|product, card| product * card.rank.id } * (hand.flush? ? 67 : 1))] = hand
|
120
146
|
end
|
121
147
|
hash.values
|
122
148
|
end
|
123
149
|
|
124
150
|
private
|
125
151
|
|
126
|
-
def
|
152
|
+
def get_best_hand(cards, key)
|
153
|
+
flush = @flushes_table.fetch(key)
|
154
|
+
if(flush[0] != 5)
|
155
|
+
return @seven_card_table.fetch(cards[0].uid * cards[1].uid * cards[2].uid * cards[3].uid * cards[4].uid * cards[5].uid * cards[6].uid)
|
156
|
+
end
|
157
|
+
@five_card_table.fetch(cards.inject(1) {|product, card| product * ((card.suit.key == flush[1]) ? card.rank.id : 1)} * 67)
|
158
|
+
end
|
159
|
+
|
160
|
+
def generate_suit_key(cards)
|
161
|
+
key = 1
|
162
|
+
cards.each {|card| key = key * card.suit.id}
|
163
|
+
key
|
164
|
+
end
|
165
|
+
|
166
|
+
def all_hands
|
127
167
|
if @hands.empty?
|
128
168
|
Deck.new.combination(5).each {|cards| @hands << Hand.new(cards)}
|
129
169
|
end
|
@@ -8,7 +8,8 @@ class StartingHandRepository
|
|
8
8
|
Deck.new.cards.combination(2) do |combination|
|
9
9
|
starting_hand = StartingHand.new(combination)
|
10
10
|
@all << starting_hand
|
11
|
-
|
11
|
+
hash_key = starting_hand.cards.inject(1) {|product, card| product * card.rank.id } * (starting_hand.suited? ? 67 : 1)
|
12
|
+
@distinct[hash_key] = starting_hand
|
12
13
|
end
|
13
14
|
end
|
14
15
|
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'date'
|
2
|
+
|
3
|
+
class EquityCalculator
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@hand_repository = HandRepository.instance
|
7
|
+
@best_scores = Hash.new
|
8
|
+
end
|
9
|
+
|
10
|
+
def calculate_equity(starting_hands, board = Board.new)
|
11
|
+
raise ArgumentError, "Must have at least two starting hands for equity comparison" if (starting_hands.nil? || starting_hands.size < 2)
|
12
|
+
raise ArgumentError, "There are duplicate cards" if duplicates?(starting_hands, board)
|
13
|
+
|
14
|
+
equity_map = Hash[starting_hands.map{|starting_hand| [starting_hand, 0]}]
|
15
|
+
game = Deck.new.remove(merge(starting_hands, board)).combination(5 - board.cards.size)
|
16
|
+
|
17
|
+
game.each do |cards|
|
18
|
+
showdown(equity_map, starting_hands, board.cards + cards)
|
19
|
+
end
|
20
|
+
|
21
|
+
total_winning_hands = equity_map.inject(0) {|total, result| total += result[1]}
|
22
|
+
equity_map.inject(Hash.new) { |hash, result| hash[result[0]] = Equity.new(game.size, total_winning_hands, result); hash}
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def showdown(results, starting_hands, board_cards)
|
28
|
+
@best_scores.clear
|
29
|
+
|
30
|
+
starting_hands.each do |starting_hand|
|
31
|
+
@best_scores[starting_hand] = @hand_repository.evaluate_7_card_hand((board_cards + starting_hand.cards))[0]
|
32
|
+
end
|
33
|
+
|
34
|
+
winner = @best_scores.min_by{|key,value| value}
|
35
|
+
results[winner[0]] += 1 if(@best_scores.select {|k,v| v == winner[1]}.size == 1)
|
36
|
+
end
|
37
|
+
|
38
|
+
def duplicates?(starting_hands, board)
|
39
|
+
cards = merge(starting_hands, board)
|
40
|
+
cards.uniq.length != cards.length
|
41
|
+
end
|
42
|
+
|
43
|
+
def merge(starting_hands, board)
|
44
|
+
starting_hands.inject(board.cards) {|cards, starting_hand| cards.concat(starting_hand.cards)}
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
@@ -0,0 +1,135 @@
|
|
1
|
+
require 'date'
|
2
|
+
|
3
|
+
class HandRankingGenerator
|
4
|
+
|
5
|
+
HEART_FLUSH=32
|
6
|
+
DIAMOND_FLUSH=243
|
7
|
+
SPADE_FLUSH=3125
|
8
|
+
CLUB_FLUSH=16807
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
@total = 133784560
|
12
|
+
@count = 0
|
13
|
+
@scores = {}
|
14
|
+
end
|
15
|
+
|
16
|
+
def generate_flush_map
|
17
|
+
file = File.new("flushes.csv", "w")
|
18
|
+
|
19
|
+
Suit.values().each do |suit_1|
|
20
|
+
Suit.values().each do |suit_2|
|
21
|
+
Suit.values().each do |suit_3|
|
22
|
+
Suit.values().each do |suit_4|
|
23
|
+
Suit.values().each do |suit_5|
|
24
|
+
Suit.values().each do |suit_6|
|
25
|
+
Suit.values().each do |suit_7|
|
26
|
+
key = suit_1.id * suit_2.id * suit_3.id * suit_4.id * suit_5.id * suit_6.id * suit_7.id
|
27
|
+
if(!@scores.has_key?(key))
|
28
|
+
@scores[key] = key
|
29
|
+
suit = flush_suit(key)
|
30
|
+
if(!suit.nil?)
|
31
|
+
count = flush_count([suit_1, suit_2, suit_3, suit_4, suit_5, suit_6, suit_7], suit)
|
32
|
+
file.write("#{key},#{count},#{suit}\n")
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
file.close
|
44
|
+
end
|
45
|
+
|
46
|
+
def generate_non_flush_hand_rankings
|
47
|
+
file = File.new("7_card_non_flush_hands.csv", "w")
|
48
|
+
cds = Deck.new.cards
|
49
|
+
|
50
|
+
(0..45).each do |index_1|
|
51
|
+
((index_1 + 1)..46).each do |index_2|
|
52
|
+
((index_2 + 1)..47).each do |index_3|
|
53
|
+
((index_3 + 1)..48).each do |index_4|
|
54
|
+
((index_4 + 1)..49).each do |index_5|
|
55
|
+
((index_5 + 1)..50).each do |index_6|
|
56
|
+
((index_6 + 1)..51).each do |index_7|
|
57
|
+
cards = [cds[index_1], cds[index_2], cds[index_3], cds[index_4], cds[index_5], cds[index_6], cds[index_7]].sort
|
58
|
+
hand = get_best_hand(cards)
|
59
|
+
key = get_key(cards, hand)
|
60
|
+
if(!@scores.has_key?(key) && !hand.flush?)
|
61
|
+
@scores[key] = hand.score
|
62
|
+
file.write("#{hand.score},#{key}\n")
|
63
|
+
end
|
64
|
+
@count = @count + 1
|
65
|
+
if(@count % 1000 == 0)
|
66
|
+
puts "#{DateTime.now.strftime('%Y-%m-%d %H:%M:%S')} :: #{@count} records processed #{sprintf("%05.3f", (Float(@count)/Float(@total)) * 100.0)}% complete, #{@scores.size} records captured"
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
file.close
|
77
|
+
end
|
78
|
+
|
79
|
+
def generate_flush_hand_rankings
|
80
|
+
file = File.new("7_card_flush_hands.csv", "w")
|
81
|
+
Suit.values().each do |suit|
|
82
|
+
generate_hand_rankings(suit, 6, 1, file)
|
83
|
+
generate_hand_rankings(suit, 7, 0, file)
|
84
|
+
end
|
85
|
+
file.close
|
86
|
+
end
|
87
|
+
|
88
|
+
private
|
89
|
+
|
90
|
+
def generate_hand_rankings(suit, i, j, file)
|
91
|
+
Deck.new.retain_all(suit).combination(i).each do |suited|
|
92
|
+
Deck.new.remove_all(suit).combination(j).each do |remainder|
|
93
|
+
cards = suited + remainder
|
94
|
+
hand = get_best_hand(cards)
|
95
|
+
key = get_key(cards, hand)
|
96
|
+
if(!@scores.has_key?(key))
|
97
|
+
@scores[key] = hand.score
|
98
|
+
file.write("#{hand.score},#{key}")
|
99
|
+
end
|
100
|
+
@count = @count + 1
|
101
|
+
if(@count % 1000 == 0)
|
102
|
+
puts "#{DateTime.now.strftime('%Y-%m-%d %H:%M:%S')} :: #{@count} records processed, #{@scores.size} records captured"
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def flush_count(suits, suit)
|
109
|
+
count = 0
|
110
|
+
suits.each do |s|
|
111
|
+
count = count + 1 if s.key == suit
|
112
|
+
end
|
113
|
+
count
|
114
|
+
end
|
115
|
+
|
116
|
+
def flush_suit(key)
|
117
|
+
return "H" if(key % HEART_FLUSH == 0)
|
118
|
+
return "D" if(key % DIAMOND_FLUSH == 0)
|
119
|
+
return "S" if(key % SPADE_FLUSH == 0)
|
120
|
+
return "C" if(key % CLUB_FLUSH == 0)
|
121
|
+
end
|
122
|
+
|
123
|
+
def get_key(cards, hand)
|
124
|
+
cards.inject(1) {|product, card| product * (hand.flush? ? card.uid : card.rank.id) }
|
125
|
+
end
|
126
|
+
|
127
|
+
def ranks(cards)
|
128
|
+
cards.inject('') { |string, card| string << card.rank.key }
|
129
|
+
end
|
130
|
+
|
131
|
+
def get_best_hand(cards)
|
132
|
+
cards.combination(5).to_a.each.collect { |selection| Hand.new(selection) }.sort {|x,y| x.score <=> y.score }[0]
|
133
|
+
end
|
134
|
+
|
135
|
+
end
|
@@ -7,19 +7,19 @@ class BoardTest < ActiveSupport::TestCase
|
|
7
7
|
end
|
8
8
|
|
9
9
|
test "should raise an error when a board is created with less than 3 cards" do
|
10
|
-
|
10
|
+
assert_raise_message "3 to 5 cards are required to create a board, 2 cards provided", ArgumentError do
|
11
11
|
Board.new "AS,KS"
|
12
12
|
end
|
13
13
|
end
|
14
14
|
|
15
15
|
test "should raise an error when a board is created with more than 5 cards" do
|
16
|
-
|
16
|
+
assert_raise_message "3 to 5 cards are required to create a board, 6 cards provided", ArgumentError do
|
17
17
|
Board.new "AS,KS,QS,JS,TS,9S"
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|
21
21
|
test "should raise an error when a board is created with duplicate cards" do
|
22
|
-
|
22
|
+
assert_raise_message "The board contains duplicate cards", ArgumentError do
|
23
23
|
Board.new "AS KS JS AS KS"
|
24
24
|
end
|
25
25
|
end
|
@@ -30,8 +30,6 @@ class BoardTest < ActiveSupport::TestCase
|
|
30
30
|
|
31
31
|
test "the board should have three cards if the board was initialized with the flop" do
|
32
32
|
assert_equal 3, Board.new("AS,KS,QS").cards.size
|
33
|
-
b = Board.new("AS,KS,QS")
|
34
|
-
puts b.flop
|
35
33
|
end
|
36
34
|
|
37
35
|
test "the board should have four cards if the board was initialized with the flop and turn" do
|
@@ -43,20 +41,20 @@ class BoardTest < ActiveSupport::TestCase
|
|
43
41
|
end
|
44
42
|
|
45
43
|
test "should raise an error when a flop is not created with 3 cards" do
|
46
|
-
|
47
|
-
Board.new.flop "AS,KS"
|
44
|
+
assert_raise_message "3 cards are required on the flop, 2 cards provided", ArgumentError do
|
45
|
+
Board.new.flop= "AS,KS"
|
48
46
|
end
|
49
47
|
end
|
50
48
|
|
51
49
|
test "should raise an error when a flop is set with duplicate cards" do
|
52
|
-
|
53
|
-
Board.new.flop "AS AS JS"
|
50
|
+
assert_raise_message "The flop contains duplicate cards", ArgumentError do
|
51
|
+
Board.new.flop= "AS AS JS"
|
54
52
|
end
|
55
53
|
end
|
56
54
|
|
57
55
|
test "should raise an error when a flop is set with no cards" do
|
58
|
-
|
59
|
-
Board.new.flop []
|
56
|
+
assert_raise_message "Cannot deal a flop with empty array of cards", ArgumentError do
|
57
|
+
Board.new.flop= []
|
60
58
|
end
|
61
59
|
end
|
62
60
|
|
@@ -68,14 +66,14 @@ class BoardTest < ActiveSupport::TestCase
|
|
68
66
|
end
|
69
67
|
|
70
68
|
test "should raise an error when a turn card is dealt before the flop has been dealt" do
|
71
|
-
|
69
|
+
assert_raise_message "The flop must be dealt before the turn card is dealt", RuntimeError do
|
72
70
|
board = Board.new
|
73
71
|
board.turn = "AS"
|
74
72
|
end
|
75
73
|
end
|
76
74
|
|
77
|
-
test "should raise an error when the turn card has already been dealt" do
|
78
|
-
|
75
|
+
test "should raise an error when the turn card has already been dealt on the flop" do
|
76
|
+
assert_raise_message "The board already contains the Ace of Hearts", ArgumentError do
|
79
77
|
board = Board.new
|
80
78
|
board.flop= "AS,AH,AD"
|
81
79
|
board.turn= "AH"
|
@@ -91,15 +89,15 @@ class BoardTest < ActiveSupport::TestCase
|
|
91
89
|
end
|
92
90
|
|
93
91
|
test "should raise an error when the river card is dealt before the turn card has been dealt" do
|
94
|
-
|
92
|
+
assert_raise_message "The turn card must be dealt before the river card is dealt", RuntimeError do
|
95
93
|
board = Board.new
|
96
94
|
board.flop = "AS KS QS"
|
97
95
|
board.river = "JS"
|
98
96
|
end
|
99
97
|
end
|
100
98
|
|
101
|
-
test "should raise an error when the river card
|
102
|
-
|
99
|
+
test "should raise an error when the river card was dealt on a previous street" do
|
100
|
+
assert_raise_message "The board already contains the Ace of Spades", ArgumentError do
|
103
101
|
board = Board.new
|
104
102
|
board.flop = "AS,KS,QS"
|
105
103
|
board.turn = "JS"
|
@@ -121,9 +119,10 @@ class BoardTest < ActiveSupport::TestCase
|
|
121
119
|
assert_equal false, @board.contains?(Card.new("3D"))
|
122
120
|
end
|
123
121
|
|
124
|
-
test "should return true if the
|
125
|
-
|
126
|
-
assert_equal true,
|
122
|
+
test "should return true if the board contains the given card" do
|
123
|
+
b = Board.new "AS,KS,QS,JS,TS"
|
124
|
+
assert_equal true, b.contains?("TS")
|
125
|
+
assert_equal true, b.contains?(Card.new("AS"))
|
127
126
|
end
|
128
127
|
|
129
128
|
test "should return false if the board does not contain any of the given cards" do
|