ruby_holdem 0.0.1 → 0.0.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/README.md +10 -6
- data/lib/ruby_holdem.rb +7 -1
- data/lib/ruby_holdem/errors.rb +2 -2
- data/lib/ruby_holdem/round.rb +31 -125
- data/lib/ruby_holdem/round/move_factory.rb +51 -0
- data/lib/ruby_holdem/round/move_history.rb +28 -0
- data/lib/ruby_holdem/round/move_history_computations.rb +105 -0
- data/lib/ruby_holdem/round/move_validator.rb +110 -0
- data/lib/ruby_holdem/round/player.rb +13 -0
- data/lib/ruby_holdem/version.rb +1 -1
- data/spec/round/move_factory_spec.rb +59 -0
- data/spec/round/move_history_computations_spec.rb +274 -0
- data/spec/round/move_history_spec.rb +42 -0
- data/spec/round/move_validator_spec.rb +25 -0
- metadata +15 -6
- data/.rspec +0 -1
- data/lib/ruby_holdem/round_player.rb +0 -11
- data/spec/round_spec.rb +0 -249
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1dd48e6184eca19ac256511789c5effc59d11afb
|
4
|
+
data.tar.gz: 2a199bdde72d3903b13453f8743889fa83a5b0f7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 77f78e0b36c92cd26b9dda7ef221044b6ad18bef2d0798870633d31a5617dc2136d4e5943cf829c78de1b0a97b7ee157b7da1ab277b4788b36902576c4f5c4f7
|
7
|
+
data.tar.gz: e3d0e79ae799214fbafbe318abdb276d3d95c247ebffd6efdc7093ca8f7a9d40d28014a92b37f02e913dd4b8ea8463436e852dc2f63137ec06670a33f02307b6
|
data/README.md
CHANGED
@@ -3,8 +3,6 @@ RubyHoldem is a set of classes which track the game state of a texas holdem poke
|
|
3
3
|
|
4
4
|
### Installation
|
5
5
|
```
|
6
|
-
git clone git@github.com:evanrolfe/ruby-holdem.git
|
7
|
-
cd ruby-holdem/
|
8
6
|
gem install ruby_holdem
|
9
7
|
```
|
10
8
|
|
@@ -15,11 +13,11 @@ require 'ruby_holdem'
|
|
15
13
|
players = ["Jack", "Joe", "Jil"]
|
16
14
|
poker_round = RubyHoldem::Round.new(players, 2, 4)
|
17
15
|
|
18
|
-
poker_round.make_move('
|
19
|
-
poker_round.make_move('
|
16
|
+
poker_round.make_move('raise', 2) # Jack raises small blinds
|
17
|
+
poker_round.make_move('raise', 4) # Joe raises big blinds
|
20
18
|
poker_round.make_move('fold') # Jil folds
|
21
19
|
poker_round.make_move('call') # Jack calls
|
22
|
-
poker_round.make_move('
|
20
|
+
poker_round.make_move('check') # Joe calls
|
23
21
|
poker_round.next_stage
|
24
22
|
|
25
23
|
puts poker_round.community_cards.join(' ')
|
@@ -28,13 +26,19 @@ puts poker_round.community_cards.join(' ')
|
|
28
26
|
puts poker_round.pot_amount
|
29
27
|
# => 8
|
30
28
|
|
31
|
-
poker_round.make_move('
|
29
|
+
poker_round.make_move('raise', 3) # Jack raises 3
|
32
30
|
poker_round.make_move('fold') # Joe folds
|
33
31
|
|
34
32
|
puts poker_round.winner
|
35
33
|
# => Jack
|
36
34
|
```
|
37
35
|
|
36
|
+
### TODO
|
37
|
+
- Break monolithic ```Round``` class into smaller classes, i.e. ```Round```, ```RoundState``` and ```RoundPlayerMove```
|
38
|
+
- Use rspec 3 style (subjects, expects etc.)
|
39
|
+
- Get rid of the stubbing of action_history instance var in round_spec.rb
|
40
|
+
- Have ```Game``` keep track of an entire poker game consisting of multiple rounds
|
41
|
+
|
38
42
|
### License
|
39
43
|
|
40
44
|
RubyHoldem uses the MIT license. Please check the [LICENSE](https://github.com/evanrolfe/ruby-holdem/blob/master/LICENSE) file for more details.
|
data/lib/ruby_holdem.rb
CHANGED
@@ -4,4 +4,10 @@ require 'ruby_holdem/errors'
|
|
4
4
|
|
5
5
|
require 'ruby_holdem/dealer'
|
6
6
|
require 'ruby_holdem/round'
|
7
|
-
require 'ruby_holdem/
|
7
|
+
require 'ruby_holdem/round/move_factory'
|
8
|
+
require 'ruby_holdem/round/move_history'
|
9
|
+
require 'ruby_holdem/round/move_history_computations'
|
10
|
+
require 'ruby_holdem/round/move_validator'
|
11
|
+
require 'ruby_holdem/round/player'
|
12
|
+
|
13
|
+
require 'pry'
|
data/lib/ruby_holdem/errors.rb
CHANGED
data/lib/ruby_holdem/round.rb
CHANGED
@@ -4,151 +4,57 @@ module RubyHoldem
|
|
4
4
|
class Round
|
5
5
|
extend Forwardable
|
6
6
|
|
7
|
-
attr_reader :
|
8
|
-
:small_blinds,
|
7
|
+
attr_reader :small_blinds,
|
9
8
|
:big_blinds,
|
10
9
|
:pot_amount,
|
11
|
-
:
|
12
|
-
:
|
13
|
-
:dealer,
|
14
|
-
:turns_played
|
10
|
+
:players,
|
11
|
+
:state
|
15
12
|
|
16
13
|
def_delegator :@dealer, :community_cards
|
17
14
|
|
15
|
+
def_delegators :@move_history_computations, :ready_for_next_stage?,
|
16
|
+
:has_winner?,
|
17
|
+
:winner,
|
18
|
+
:player_in_turn,
|
19
|
+
:players_still_in_round,
|
20
|
+
:highest_bet_placed
|
21
|
+
|
22
|
+
def_delegators :@move_history, :stage,
|
23
|
+
:last_move,
|
24
|
+
:turns_played,
|
25
|
+
:moves
|
26
|
+
|
18
27
|
STAGES = %w(pre_flop flop turn river show_down)
|
19
28
|
|
20
29
|
def initialize(players, small_blinds, big_blinds)
|
21
|
-
@small_blinds
|
22
|
-
@
|
30
|
+
@small_blinds = small_blinds
|
31
|
+
@big_blinds = big_blinds
|
23
32
|
@pot_amount = 0
|
24
|
-
@action_history = []
|
25
33
|
|
26
|
-
@players = players.map { |player|
|
34
|
+
@players = players.map { |player| Player.new(player) }
|
35
|
+
@move_history = MoveHistory.new
|
36
|
+
@move_history_computations = MoveHistoryComputations.new(@players, @move_history)
|
37
|
+
|
27
38
|
@dealer = Dealer.new
|
28
39
|
@dealer.deal_hole_cards(@players)
|
29
40
|
end
|
30
41
|
|
31
|
-
|
32
|
-
|
33
|
-
def make_move(move, amount=nil)
|
34
|
-
if turns_played == 0
|
35
|
-
apply_bet(small_blinds)
|
36
|
-
elsif turns_played == 1
|
37
|
-
apply_bet(big_blinds)
|
38
|
-
elsif move == 'bet'
|
39
|
-
apply_bet(amount)
|
40
|
-
elsif move == 'call'
|
41
|
-
apply_call
|
42
|
-
elsif move == 'fold'
|
43
|
-
apply_fold
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
def next_stage
|
48
|
-
raise StandardError unless ready_for_next_stage? && @current_stage != 'show_down'
|
49
|
-
|
50
|
-
@current_stage = STAGES[STAGES.index(@current_stage)+1]
|
51
|
-
@dealer.deal_community_cards(@current_stage)
|
52
|
-
end
|
53
|
-
|
54
|
-
def ready_for_next_stage?
|
55
|
-
return false unless every_player_has_called? && turns_played_in_stage > 0
|
56
|
-
|
57
|
-
players_still_in_round.map { |player| (player.current_bet_amount == highest_bet_placed) }.all?
|
58
|
-
end
|
59
|
-
|
60
|
-
def has_winner?
|
61
|
-
(current_stage == 'show_down' || players_still_in_round.count == 1)
|
62
|
-
end
|
63
|
-
|
64
|
-
def winner
|
65
|
-
return players_still_in_round[0] if players_still_in_round.count == 1
|
66
|
-
return players_still_in_round[2]
|
67
|
-
end
|
68
|
-
|
69
|
-
# TODO: Refactor this method to make it more readable
|
70
|
-
def player_in_turn #The player whose turn it is to make a move
|
71
|
-
return players[0] if action_history.length == 0
|
72
|
-
|
73
|
-
last_player_index = players.index(action_history.last[:player])
|
74
|
-
player_found = false
|
75
|
-
increment=1
|
76
|
-
|
77
|
-
until player_found
|
78
|
-
next_player = players[(last_player_index + increment) % players.length] #Wrap around the array once end reached
|
79
|
-
player_found = true if players_still_in_round.include?(next_player)
|
80
|
-
increment += 1
|
81
|
-
end
|
82
|
-
|
83
|
-
next_player
|
84
|
-
end
|
85
|
-
|
86
|
-
def players_still_in_round
|
87
|
-
players.select do |round_player|
|
88
|
-
folds = action_history.select { |action| action[:move] == 'fold' && action[:player] == round_player }
|
89
|
-
(folds.length == 0)
|
90
|
-
end
|
91
|
-
end
|
92
|
-
|
93
|
-
def highest_bet_placed
|
94
|
-
players_still_in_round.max_by(&:current_bet_amount).current_bet_amount
|
95
|
-
end
|
96
|
-
|
97
|
-
def last_move
|
98
|
-
action_history.last
|
99
|
-
end
|
42
|
+
def make_move(move_type, amount=nil)
|
43
|
+
move = MoveFactory.new(self, player_in_turn, move_type, amount).build
|
100
44
|
|
101
|
-
|
45
|
+
MoveValidator.new(self, move).validate
|
102
46
|
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
def turns_played_in_stage
|
108
|
-
action_history.select { |action| action[:stage] == @current_stage }.length
|
109
|
-
end
|
110
|
-
|
111
|
-
def every_player_has_called?
|
112
|
-
players_num_calls = players_still_in_round.map do |round_player|
|
113
|
-
calls = action_history.select { |action| action[:stage] == @current_stage && action[:move] == 'call' && action[:player] == round_player }
|
114
|
-
calls.length
|
47
|
+
unless move[:amount].nil?
|
48
|
+
player_in_turn.current_bet_amount += move[:amount]
|
49
|
+
@pot_amount += move[:amount]
|
115
50
|
end
|
116
51
|
|
117
|
-
|
52
|
+
@move_history.add_move(move)
|
118
53
|
end
|
119
54
|
|
120
|
-
def
|
121
|
-
|
122
|
-
|
123
|
-
#TODO: Go all in instead of raising an error
|
124
|
-
raise NotEnoughMoney unless player_can_afford_bet?(player_in_turn, amount)
|
125
|
-
|
126
|
-
@pot_amount += amount
|
127
|
-
player_in_turn.current_bet_amount += amount
|
128
|
-
action_history << { player: player_in_turn, stage: current_stage, move: 'bet', amount: amount}
|
129
|
-
end
|
130
|
-
|
131
|
-
def apply_call
|
132
|
-
amount = min_bet_amount_for_player(player_in_turn)
|
133
|
-
raise NotEnoughMoney unless player_can_afford_bet?(player_in_turn, amount)
|
134
|
-
|
135
|
-
@pot_amount += amount
|
136
|
-
player_in_turn.current_bet_amount += amount
|
137
|
-
|
138
|
-
action_history << { player: player_in_turn, stage: current_stage, move: 'call', amount: amount}
|
139
|
-
end
|
140
|
-
|
141
|
-
def apply_fold
|
142
|
-
action_history << { player: player_in_turn, stage: current_stage, move: 'fold', amount: 0}
|
143
|
-
end
|
144
|
-
|
145
|
-
def min_bet_amount_for_player(player)
|
146
|
-
highest_bet_placed - player.current_bet_amount
|
147
|
-
end
|
148
|
-
|
149
|
-
# TODO:
|
150
|
-
def player_can_afford_bet?(player, bet_amount)
|
151
|
-
true
|
55
|
+
def next_stage
|
56
|
+
@move_history.next_stage
|
57
|
+
@dealer.deal_community_cards(@move_history.stage)
|
152
58
|
end
|
153
59
|
end
|
154
60
|
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module RubyHoldem
|
2
|
+
class Round
|
3
|
+
class MoveFactory
|
4
|
+
attr_reader :round, :player, :move_type, :amount
|
5
|
+
|
6
|
+
def initialize(round, player, move_type, amount)
|
7
|
+
@round = round
|
8
|
+
@player = player
|
9
|
+
@move_type = move_type
|
10
|
+
@amount = amount
|
11
|
+
end
|
12
|
+
|
13
|
+
def build
|
14
|
+
{
|
15
|
+
player: player,
|
16
|
+
stage: stage,
|
17
|
+
move_type: move_type,
|
18
|
+
amount: actual_amount
|
19
|
+
}
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def actual_amount
|
25
|
+
if move_type == "call"
|
26
|
+
highest_bet_placed - current_bet_amount
|
27
|
+
else
|
28
|
+
amount
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
#
|
33
|
+
# Dependencies on Round class
|
34
|
+
#
|
35
|
+
def stage
|
36
|
+
round.stage
|
37
|
+
end
|
38
|
+
|
39
|
+
def highest_bet_placed
|
40
|
+
@highest_bet_placed ||= round.highest_bet_placed
|
41
|
+
end
|
42
|
+
|
43
|
+
#
|
44
|
+
# Dependencies on Player class
|
45
|
+
#
|
46
|
+
def current_bet_amount
|
47
|
+
@current_bet_amount ||= player.current_bet_amount
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module RubyHoldem
|
2
|
+
class Round
|
3
|
+
class MoveHistory
|
4
|
+
attr_reader :moves, :stage
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@moves = []
|
8
|
+
@stage = STAGES.first
|
9
|
+
end
|
10
|
+
|
11
|
+
def add_move(move)
|
12
|
+
moves << move
|
13
|
+
end
|
14
|
+
|
15
|
+
def last_move
|
16
|
+
moves.last
|
17
|
+
end
|
18
|
+
|
19
|
+
def turns_played
|
20
|
+
moves.count
|
21
|
+
end
|
22
|
+
|
23
|
+
def next_stage
|
24
|
+
@stage = STAGES[STAGES.index(stage)+1]
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
module RubyHoldem
|
2
|
+
class Round
|
3
|
+
class MoveHistoryComputations
|
4
|
+
attr_reader :players, :move_history
|
5
|
+
|
6
|
+
def initialize(players, move_history)
|
7
|
+
@players = players
|
8
|
+
@move_history = move_history
|
9
|
+
end
|
10
|
+
|
11
|
+
def highest_bet_placed
|
12
|
+
get_current_bet_amount_for_player(
|
13
|
+
players_still_in_round.max_by(&:current_bet_amount)
|
14
|
+
)
|
15
|
+
end
|
16
|
+
|
17
|
+
def ready_for_next_stage?
|
18
|
+
every_player_has_checked? && turns_played_in_stage > 0
|
19
|
+
end
|
20
|
+
|
21
|
+
def has_winner?
|
22
|
+
(stage == 'show_down' || players_still_in_round.count == 1)
|
23
|
+
end
|
24
|
+
|
25
|
+
# TODO: Compare the hands of the two players
|
26
|
+
def winner
|
27
|
+
return players_still_in_round[0] if players_still_in_round.count == 1
|
28
|
+
end
|
29
|
+
|
30
|
+
def turns_played_in_stage
|
31
|
+
moves.select { |move| move[:stage] == stage }.length
|
32
|
+
end
|
33
|
+
|
34
|
+
def player_in_turn #The player whose turn it is to make a move
|
35
|
+
return players[0] if moves.length == 0
|
36
|
+
|
37
|
+
last_player = moves.last[:player]
|
38
|
+
i = (players.index(last_player) + 1) % players.length
|
39
|
+
|
40
|
+
player_found = false
|
41
|
+
until player_found
|
42
|
+
at_end_of_array = (i == (players.length - 1))
|
43
|
+
|
44
|
+
if player_is_folded?(players[i]) && !at_end_of_array
|
45
|
+
i += 1
|
46
|
+
elsif player_is_folded?(players[i]) && at_end_of_array
|
47
|
+
i = 0
|
48
|
+
else
|
49
|
+
player_found = true
|
50
|
+
end
|
51
|
+
end
|
52
|
+
players[i]
|
53
|
+
end
|
54
|
+
|
55
|
+
def every_player_has_checked?
|
56
|
+
players_num_checks = players_still_in_round.map do |round_player|
|
57
|
+
checks = moves.select do |move|
|
58
|
+
move[:stage] == stage &&
|
59
|
+
move[:move_type] == 'check' &&
|
60
|
+
move[:player] == round_player
|
61
|
+
end
|
62
|
+
checks.length
|
63
|
+
end
|
64
|
+
|
65
|
+
players_num_checks.map { |num_checks| num_checks >= 1 }.all?
|
66
|
+
end
|
67
|
+
|
68
|
+
def players_still_in_round
|
69
|
+
players.select do |round_player|
|
70
|
+
folds = moves.select do |move|
|
71
|
+
move[:move_type] == 'fold' && move[:player] == round_player
|
72
|
+
end
|
73
|
+
|
74
|
+
folds.length == 0
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
private
|
79
|
+
|
80
|
+
def player_is_folded?(player)
|
81
|
+
moves.select do |move|
|
82
|
+
move[:move_type] == 'fold' && move[:player] == player
|
83
|
+
end.any?
|
84
|
+
end
|
85
|
+
|
86
|
+
#
|
87
|
+
# Dependencies on MoveHistory class
|
88
|
+
#
|
89
|
+
def moves
|
90
|
+
move_history.moves
|
91
|
+
end
|
92
|
+
|
93
|
+
def stage
|
94
|
+
move_history.stage
|
95
|
+
end
|
96
|
+
|
97
|
+
#
|
98
|
+
# Dependencies on Player class
|
99
|
+
#
|
100
|
+
def get_current_bet_amount_for_player(player)
|
101
|
+
player.current_bet_amount
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
module RubyHoldem
|
2
|
+
class Round
|
3
|
+
class MoveValidator
|
4
|
+
attr_reader :round, :move
|
5
|
+
|
6
|
+
def initialize(round, move)
|
7
|
+
@round = round
|
8
|
+
@move = move
|
9
|
+
end
|
10
|
+
|
11
|
+
def validate
|
12
|
+
if blinds_turn? && blinds_not_met?
|
13
|
+
raise MinRaiseNotMeet, "You must bet blinds."
|
14
|
+
end
|
15
|
+
|
16
|
+
send("validate_#{move_type}")
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def validate_raise
|
22
|
+
if amount < min_raise_amount
|
23
|
+
raise MinRaiseNotMeet
|
24
|
+
end
|
25
|
+
|
26
|
+
if !player_can_afford_raise?
|
27
|
+
raise InsufficientFunds
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def validate_call
|
32
|
+
if !player_can_afford_raise?
|
33
|
+
raise InsufficientFunds
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def validate_check
|
38
|
+
if min_raise_amount > 0
|
39
|
+
raise MinRaiseNotMeet
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def validate_fold
|
44
|
+
true # NOTE: You can always fold as long as its not a blinds turn
|
45
|
+
end
|
46
|
+
|
47
|
+
def min_raise_amount
|
48
|
+
@min_raise_amount ||= highest_bet_placed - current_bet_amount
|
49
|
+
end
|
50
|
+
|
51
|
+
# TODO:
|
52
|
+
def player_can_afford_raise?
|
53
|
+
true
|
54
|
+
end
|
55
|
+
|
56
|
+
def blinds_turn?
|
57
|
+
turns_played == 0 || turns_played == 1
|
58
|
+
end
|
59
|
+
|
60
|
+
def blinds_not_met?
|
61
|
+
if turns_played == 0
|
62
|
+
amount < small_blinds
|
63
|
+
elsif turns_played == 1
|
64
|
+
amount < big_blinds
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
#
|
69
|
+
# Dependencies on Round class
|
70
|
+
#
|
71
|
+
def highest_bet_placed
|
72
|
+
@highest_bet_placed ||= round.highest_bet_placed
|
73
|
+
end
|
74
|
+
|
75
|
+
def turns_played
|
76
|
+
@turns_played ||= round.turns_played
|
77
|
+
end
|
78
|
+
|
79
|
+
def small_blinds
|
80
|
+
@small_blinds ||= round.small_blinds
|
81
|
+
end
|
82
|
+
|
83
|
+
def big_blinds
|
84
|
+
@big_blinds ||= round.big_blinds
|
85
|
+
end
|
86
|
+
|
87
|
+
#
|
88
|
+
# Dependencies on Player class
|
89
|
+
#
|
90
|
+
def current_bet_amount
|
91
|
+
@current_bet_amount ||= player.current_bet_amount
|
92
|
+
end
|
93
|
+
|
94
|
+
#
|
95
|
+
# Dependencies on MoveFactory
|
96
|
+
#
|
97
|
+
def amount
|
98
|
+
move[:amount]
|
99
|
+
end
|
100
|
+
|
101
|
+
def move_type
|
102
|
+
move[:move_type]
|
103
|
+
end
|
104
|
+
|
105
|
+
def player
|
106
|
+
move[:player]
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
data/lib/ruby_holdem/version.rb
CHANGED
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
|
4
|
+
describe RubyHoldem::Round::MoveFactory do
|
5
|
+
describe "#build" do
|
6
|
+
let(:round) { double(RubyHoldem::Round) }
|
7
|
+
let(:stage) { RubyHoldem::Round::STAGES.first }
|
8
|
+
let(:player) { double(RubyHoldem::Round::Player) }
|
9
|
+
|
10
|
+
subject { move_factory.build }
|
11
|
+
|
12
|
+
context "with a move_type of call" do
|
13
|
+
let(:move_type) { "call" }
|
14
|
+
let(:amount) { nil }
|
15
|
+
let(:move_factory) { RubyHoldem::Round::MoveFactory.new(round, player, move_type, amount) }
|
16
|
+
let(:highest_bet_placed) { 100 }
|
17
|
+
let(:current_bet_amount) { 90 }
|
18
|
+
let(:expected_amount) { highest_bet_placed - current_bet_amount }
|
19
|
+
|
20
|
+
before do
|
21
|
+
allow(round).to receive(:stage).and_return(stage)
|
22
|
+
allow(round).to receive(:highest_bet_placed).and_return(highest_bet_placed)
|
23
|
+
allow(player).to receive(:current_bet_amount).and_return(current_bet_amount)
|
24
|
+
end
|
25
|
+
|
26
|
+
it do
|
27
|
+
is_expected.to eq(
|
28
|
+
player: player,
|
29
|
+
stage: stage,
|
30
|
+
move_type: move_type,
|
31
|
+
amount: expected_amount
|
32
|
+
)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
{
|
37
|
+
"raise" => 10,
|
38
|
+
"check" => nil,
|
39
|
+
"fold" => nil
|
40
|
+
}.each do |move_type, amount|
|
41
|
+
context "with a move_type of #{move_type}" do
|
42
|
+
let(:move_factory) { RubyHoldem::Round::MoveFactory.new(round, player, move_type, amount) }
|
43
|
+
|
44
|
+
before do
|
45
|
+
allow(round).to receive(:stage).and_return(stage)
|
46
|
+
end
|
47
|
+
|
48
|
+
it do
|
49
|
+
is_expected.to eq(
|
50
|
+
player: player,
|
51
|
+
stage: stage,
|
52
|
+
move_type: move_type,
|
53
|
+
amount: amount
|
54
|
+
)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,274 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe RubyHoldem::Round::MoveHistoryComputations do
|
4
|
+
let(:player1) { RubyHoldem::Round::Player.new("Jack") }
|
5
|
+
let(:player2) { RubyHoldem::Round::Player.new("Joe") }
|
6
|
+
let(:player3) { RubyHoldem::Round::Player.new("Jil") }
|
7
|
+
let(:players) { [player1, player2, player3] }
|
8
|
+
|
9
|
+
let(:moves) { [] }
|
10
|
+
let(:stage) { RubyHoldem::Round::STAGES.first }
|
11
|
+
let(:move_history) { RubyHoldem::Round::MoveHistory.new }
|
12
|
+
let(:move_history_computations) do
|
13
|
+
RubyHoldem::Round::MoveHistoryComputations.new(players, move_history)
|
14
|
+
end
|
15
|
+
|
16
|
+
before do
|
17
|
+
allow(move_history).to receive(:moves).and_return(moves)
|
18
|
+
allow(move_history).to receive(:stage).and_return(stage)
|
19
|
+
end
|
20
|
+
|
21
|
+
describe "#highest_bet_placed" do
|
22
|
+
before do
|
23
|
+
allow(player1).to receive(:current_bet_amount).and_return(0)
|
24
|
+
allow(player2).to receive(:current_bet_amount).and_return(5)
|
25
|
+
allow(player3).to receive(:current_bet_amount).and_return(10)
|
26
|
+
end
|
27
|
+
|
28
|
+
subject { move_history_computations.highest_bet_placed }
|
29
|
+
|
30
|
+
it { is_expected.to eq(10) }
|
31
|
+
end
|
32
|
+
|
33
|
+
describe "#ready_for_next_stage?" do
|
34
|
+
context "not every player has checked yet" do
|
35
|
+
let(:moves) do
|
36
|
+
[
|
37
|
+
{ stage: 'pre_flop', player: players[0], amount: 10, move_type: 'raise' },
|
38
|
+
{ stage: 'pre_flop', player: players[1], amount: nil, move_type: 'fold' },
|
39
|
+
{ stage: 'pre_flop', player: players[2], amount: nil, move_type: 'check' },
|
40
|
+
{ stage: 'pre_flop', player: players[0], amount: nil, move_type: 'check' },
|
41
|
+
]
|
42
|
+
end
|
43
|
+
|
44
|
+
subject { move_history_computations.ready_for_next_stage? }
|
45
|
+
|
46
|
+
it { is_expected.to be_truthy }
|
47
|
+
end
|
48
|
+
|
49
|
+
context "no turns have been played yet in this stage" do
|
50
|
+
let(:moves) { [] }
|
51
|
+
|
52
|
+
subject { move_history_computations.ready_for_next_stage? }
|
53
|
+
|
54
|
+
it { is_expected.to be_falsey }
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe "#has_winner?" do
|
59
|
+
context "round won after every other player folds" do
|
60
|
+
let(:moves) do
|
61
|
+
[
|
62
|
+
{ stage: 'pre_flop', player: players[0], amount: 1, move_type: 'raise' },
|
63
|
+
{ stage: 'pre_flop', player: players[1], amount: 4, move_type: 'raise' },
|
64
|
+
{ stage: 'pre_flop', player: players[2], amount: 0, move_type: 'fold'},
|
65
|
+
{ stage: 'pre_flop', player: players[0], amount: 3, move_type: 'check' },
|
66
|
+
{ stage: 'flop', player: players[1], amount: 0, move_type: 'check' },
|
67
|
+
{ stage: 'flop', player: players[0], amount: 0, move_type: 'fold' }
|
68
|
+
]
|
69
|
+
end
|
70
|
+
|
71
|
+
subject { move_history_computations.has_winner? }
|
72
|
+
|
73
|
+
it { is_expected.to be_truthy }
|
74
|
+
end
|
75
|
+
|
76
|
+
context "in stage showdown" do
|
77
|
+
let(:stage) { RubyHoldem::Round::STAGES.last }
|
78
|
+
|
79
|
+
subject { move_history_computations.has_winner? }
|
80
|
+
|
81
|
+
it { is_expected.to be_truthy }
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
describe "#winner" do
|
86
|
+
context "round won after every other player folds" do
|
87
|
+
let(:moves) do
|
88
|
+
[
|
89
|
+
{ stage: 'pre_flop', player: players[0], amount: 1, move_type: 'raise' },
|
90
|
+
{ stage: 'pre_flop', player: players[1], amount: 4, move_type: 'raise' },
|
91
|
+
{ stage: 'pre_flop', player: players[2], amount: 0, move_type: 'fold'},
|
92
|
+
{ stage: 'pre_flop', player: players[0], amount: 3, move_type: 'check' },
|
93
|
+
{ stage: 'flop', player: players[1], amount: 0, move_type: 'check' },
|
94
|
+
{ stage: 'flop', player: players[0], amount: 0, move_type: 'fold' }
|
95
|
+
]
|
96
|
+
end
|
97
|
+
|
98
|
+
subject { move_history_computations.winner }
|
99
|
+
|
100
|
+
it "returns the only player who hasn't folded" do
|
101
|
+
is_expected.to eq(players[1])
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
context "in stage showdown" do
|
106
|
+
let(:stage) { RubyHoldem::Round::STAGES.last }
|
107
|
+
|
108
|
+
subject { move_history_computations.winner }
|
109
|
+
|
110
|
+
xit "returns the player with the better hand" do
|
111
|
+
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
describe "#turns_played_in_stage" do
|
117
|
+
context "no turns played" do
|
118
|
+
let(:moves) { [] }
|
119
|
+
|
120
|
+
subject { move_history_computations.turns_played_in_stage }
|
121
|
+
|
122
|
+
it { is_expected.to eq(0) }
|
123
|
+
end
|
124
|
+
|
125
|
+
context "turns played in pre_flop" do
|
126
|
+
let(:moves) do
|
127
|
+
[
|
128
|
+
{ stage: 'pre_flop', player: players[0], amount: 1, move_type: 'raise' },
|
129
|
+
{ stage: 'pre_flop', player: players[1], amount: 4, move_type: 'raise' },
|
130
|
+
{ stage: 'pre_flop', player: players[2], amount: 0, move_type: 'fold'},
|
131
|
+
]
|
132
|
+
end
|
133
|
+
|
134
|
+
subject { move_history_computations.turns_played_in_stage }
|
135
|
+
|
136
|
+
it { is_expected.to eq(3) }
|
137
|
+
end
|
138
|
+
|
139
|
+
context "turns played in pre_flop but no turns played in flop" do
|
140
|
+
let(:stage) { 'flop' }
|
141
|
+
let(:moves) do
|
142
|
+
[
|
143
|
+
{ stage: 'pre_flop', player: players[0], amount: 1, move_type: 'raise' },
|
144
|
+
{ stage: 'pre_flop', player: players[1], amount: 4, move_type: 'raise' },
|
145
|
+
{ stage: 'pre_flop', player: players[2], amount: 0, move_type: 'fold'},
|
146
|
+
{ stage: 'pre_flop', player: players[0], amount: 3, move_type: 'check' }
|
147
|
+
]
|
148
|
+
end
|
149
|
+
|
150
|
+
subject { move_history_computations.turns_played_in_stage }
|
151
|
+
|
152
|
+
it { is_expected.to eq(0) }
|
153
|
+
end
|
154
|
+
|
155
|
+
context "turns played in pre_flop and turns played in flop" do
|
156
|
+
let(:stage) { 'flop' }
|
157
|
+
let(:moves) do
|
158
|
+
[
|
159
|
+
{ stage: 'pre_flop', player: players[0], amount: 1, move_type: 'raise' },
|
160
|
+
{ stage: 'pre_flop', player: players[1], amount: 4, move_type: 'raise' },
|
161
|
+
{ stage: 'pre_flop', player: players[2], amount: 0, move_type: 'fold'},
|
162
|
+
{ stage: 'pre_flop', player: players[0], amount: 3, move_type: 'check' },
|
163
|
+
{ stage: 'flop', player: players[1], amount: 0, move_type: 'check' },
|
164
|
+
{ stage: 'flop', player: players[0], amount: 0, move_type: 'fold' }
|
165
|
+
]
|
166
|
+
end
|
167
|
+
|
168
|
+
subject { move_history_computations.turns_played_in_stage }
|
169
|
+
|
170
|
+
it { is_expected.to eq(2) }
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
describe "#player_in_turn" do
|
175
|
+
context "no turns played" do
|
176
|
+
let(:moves) { [] }
|
177
|
+
|
178
|
+
subject { move_history_computations.player_in_turn }
|
179
|
+
|
180
|
+
it { is_expected.to eq(player1) }
|
181
|
+
end
|
182
|
+
|
183
|
+
context "two turns played" do
|
184
|
+
let(:moves) do
|
185
|
+
[
|
186
|
+
{ stage: 'pre_flop', player: players[0], amount: 2, move_type: 'raise' },
|
187
|
+
{ stage: 'pre_flop', player: players[1], amount: 4, move_type: 'raise' },
|
188
|
+
{ stage: 'pre_flop', player: players[2], move_type: 'fold' }
|
189
|
+
]
|
190
|
+
end
|
191
|
+
|
192
|
+
subject { move_history_computations.player_in_turn }
|
193
|
+
|
194
|
+
it { is_expected.to eq(player1) }
|
195
|
+
end
|
196
|
+
|
197
|
+
context "many turns played" do
|
198
|
+
let(:moves) do
|
199
|
+
[
|
200
|
+
{ stage: 'pre_flop', player: players[0], amount: 2, move_type: 'raise' },
|
201
|
+
{ stage: 'pre_flop', player: players[1], amount: 4, move_type: 'raise' },
|
202
|
+
{ stage: 'pre_flop', player: players[2], move_type: 'fold' },
|
203
|
+
{ stage: 'pre_flop', player: players[0], move_type: 'call' },
|
204
|
+
{ stage: 'pre_flop', player: players[1], move_type: 'check' }
|
205
|
+
]
|
206
|
+
end
|
207
|
+
|
208
|
+
subject { move_history_computations.player_in_turn }
|
209
|
+
|
210
|
+
it { is_expected.to eq(player1) }
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
describe "#every_player_has_checked?" do
|
215
|
+
context "every player has checked yet" do
|
216
|
+
let(:moves) do
|
217
|
+
[
|
218
|
+
{ stage: 'pre_flop', player: players[0], amount: 10, move_type: 'raise' },
|
219
|
+
{ stage: 'pre_flop', player: players[1], amount: nil, move_type: 'fold' },
|
220
|
+
{ stage: 'pre_flop', player: players[2], amount: nil, move_type: 'check' },
|
221
|
+
{ stage: 'pre_flop', player: players[0], amount: nil, move_type: 'check' },
|
222
|
+
]
|
223
|
+
end
|
224
|
+
|
225
|
+
subject { move_history_computations.every_player_has_checked? }
|
226
|
+
|
227
|
+
it { is_expected.to be_truthy }
|
228
|
+
end
|
229
|
+
|
230
|
+
context "not every player has checked yet" do
|
231
|
+
let(:moves) do
|
232
|
+
[
|
233
|
+
{ stage: 'pre_flop', player: players[0], amount: 10, move_type: 'raise' },
|
234
|
+
{ stage: 'pre_flop', player: players[1], amount: nil, move_type: 'fold' },
|
235
|
+
{ stage: 'pre_flop', player: players[2], amount: nil, move_type: 'check' }
|
236
|
+
]
|
237
|
+
end
|
238
|
+
|
239
|
+
subject { move_history_computations.every_player_has_checked? }
|
240
|
+
|
241
|
+
it { is_expected.to be_falsey }
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
describe "#players_still_in_round" do
|
246
|
+
context "no players have folded" do
|
247
|
+
let(:moves) do
|
248
|
+
[
|
249
|
+
{ stage: 'pre_flop', player: players[0], amount: 10, move_type: 'raise' },
|
250
|
+
{ stage: 'pre_flop', player: players[1], amount: 10, move_type: 'raise' },
|
251
|
+
{ stage: 'pre_flop', player: players[2], amount: 10, move_type: 'raise' }
|
252
|
+
]
|
253
|
+
end
|
254
|
+
|
255
|
+
subject { move_history_computations.players_still_in_round }
|
256
|
+
|
257
|
+
it { is_expected.to eq([player1, player2, player3]) }
|
258
|
+
end
|
259
|
+
|
260
|
+
context "a player has folded" do
|
261
|
+
let(:moves) do
|
262
|
+
[
|
263
|
+
{ stage: 'pre_flop', player: players[0], amount: 10, move_type: 'raise' },
|
264
|
+
{ stage: 'pre_flop', player: players[1], amount: nil, move_type: 'fold' },
|
265
|
+
{ stage: 'pre_flop', player: players[2], amount: nil, move_type: 'check' }
|
266
|
+
]
|
267
|
+
end
|
268
|
+
|
269
|
+
subject { move_history_computations.players_still_in_round }
|
270
|
+
|
271
|
+
it { is_expected.to eq([player1, player3]) }
|
272
|
+
end
|
273
|
+
end
|
274
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe RubyHoldem::Round::MoveHistory do
|
4
|
+
let(:player1) { RubyHoldem::Round::Player.new("Jack") }
|
5
|
+
let(:player2) { RubyHoldem::Round::Player.new("Joe") }
|
6
|
+
let(:player3) { RubyHoldem::Round::Player.new("Jil") }
|
7
|
+
let(:players) { [player1, player2, player3] }
|
8
|
+
|
9
|
+
let(:move_history) { RubyHoldem::Round::MoveHistory.new }
|
10
|
+
|
11
|
+
describe "#add_move" do
|
12
|
+
let(:move) { double }
|
13
|
+
|
14
|
+
subject! { move_history.add_move(move) }
|
15
|
+
|
16
|
+
it { expect(move_history.moves.last).to eq(move) }
|
17
|
+
end
|
18
|
+
|
19
|
+
describe "#last_move" do
|
20
|
+
let(:move) { double }
|
21
|
+
|
22
|
+
before do
|
23
|
+
move_history.add_move(move)
|
24
|
+
end
|
25
|
+
|
26
|
+
subject { move_history.last_move }
|
27
|
+
|
28
|
+
it { is_expected.to eq(move) }
|
29
|
+
end
|
30
|
+
|
31
|
+
describe "#turns_played" do
|
32
|
+
subject { move_history.turns_played }
|
33
|
+
|
34
|
+
it { is_expected.to eq(0) }
|
35
|
+
end
|
36
|
+
|
37
|
+
describe "#next_stage" do
|
38
|
+
subject! { move_history.next_stage }
|
39
|
+
|
40
|
+
it { expect(move_history.stage).to eq(RubyHoldem::Round::STAGES[1]) }
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
|
4
|
+
describe RubyHoldem::Round::MoveValidator do
|
5
|
+
describe "#validate" do
|
6
|
+
let(:round) { double(RubyHoldem::Round) }
|
7
|
+
let(:player) { double(RubyHoldem::Round::Player) }
|
8
|
+
|
9
|
+
context "with a move_type of raise" do
|
10
|
+
pending
|
11
|
+
end
|
12
|
+
|
13
|
+
context "with a move_type of call" do
|
14
|
+
pending
|
15
|
+
end
|
16
|
+
|
17
|
+
context "with a move_type of check" do
|
18
|
+
pending
|
19
|
+
end
|
20
|
+
|
21
|
+
context "with a move_type of fold" do
|
22
|
+
pending
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby_holdem
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Evan Rolfe
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-09-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ruby-poker
|
@@ -101,7 +101,6 @@ executables: []
|
|
101
101
|
extensions: []
|
102
102
|
extra_rdoc_files: []
|
103
103
|
files:
|
104
|
-
- ".rspec"
|
105
104
|
- Gemfile
|
106
105
|
- Gemfile.lock
|
107
106
|
- LICENSE
|
@@ -114,11 +113,18 @@ files:
|
|
114
113
|
- lib/ruby_holdem/errors.rb
|
115
114
|
- lib/ruby_holdem/game.rb
|
116
115
|
- lib/ruby_holdem/round.rb
|
117
|
-
- lib/ruby_holdem/
|
116
|
+
- lib/ruby_holdem/round/move_factory.rb
|
117
|
+
- lib/ruby_holdem/round/move_history.rb
|
118
|
+
- lib/ruby_holdem/round/move_history_computations.rb
|
119
|
+
- lib/ruby_holdem/round/move_validator.rb
|
120
|
+
- lib/ruby_holdem/round/player.rb
|
118
121
|
- lib/ruby_holdem/version.rb
|
119
122
|
- ruby_holdem.gemspec
|
120
123
|
- spec/dealer_spec.rb
|
121
|
-
- spec/
|
124
|
+
- spec/round/move_factory_spec.rb
|
125
|
+
- spec/round/move_history_computations_spec.rb
|
126
|
+
- spec/round/move_history_spec.rb
|
127
|
+
- spec/round/move_validator_spec.rb
|
122
128
|
- spec/spec_helper.rb
|
123
129
|
homepage: https://github.com/evanrolfe/ruby-holdem
|
124
130
|
licenses:
|
@@ -146,5 +152,8 @@ specification_version: 4
|
|
146
152
|
summary: A gem for playing texas-holdem poker
|
147
153
|
test_files:
|
148
154
|
- spec/dealer_spec.rb
|
149
|
-
- spec/
|
155
|
+
- spec/round/move_factory_spec.rb
|
156
|
+
- spec/round/move_history_computations_spec.rb
|
157
|
+
- spec/round/move_history_spec.rb
|
158
|
+
- spec/round/move_validator_spec.rb
|
150
159
|
- spec/spec_helper.rb
|
data/.rspec
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
--require spec_helper
|
data/spec/round_spec.rb
DELETED
@@ -1,249 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
require 'ostruct'
|
3
|
-
|
4
|
-
describe RubyHoldem::Round do
|
5
|
-
let(:player1) { OpenStruct.new(name: "Player #1") }
|
6
|
-
let(:player2) { OpenStruct.new(name: "Player #2") }
|
7
|
-
let(:player3) { OpenStruct.new(name: "Player #3") }
|
8
|
-
let(:players) { [player1, player2, player3] }
|
9
|
-
|
10
|
-
let(:round) { RubyHoldem::Round.new(players, 1, 2) }
|
11
|
-
|
12
|
-
describe '#initialize' do
|
13
|
-
subject { round }
|
14
|
-
|
15
|
-
# TODO: Convert all instances of "should" to "is_expected"
|
16
|
-
its(:small_blinds) { should eq(1) }
|
17
|
-
its(:big_blinds) { should eq(2) }
|
18
|
-
its(:current_stage) { should eq('pre_flop') }
|
19
|
-
its(:action_history) { should eq([]) }
|
20
|
-
end
|
21
|
-
|
22
|
-
describe '#next_stage' do
|
23
|
-
before do
|
24
|
-
allow(round).to receive(:action_history).and_return(action_history)
|
25
|
-
end
|
26
|
-
|
27
|
-
context 'on the pre_flop' do
|
28
|
-
# TODO: Convert the stubbing of the action_history to a sequence of make_move calls in a
|
29
|
-
# before block
|
30
|
-
let(:action_history) do
|
31
|
-
[
|
32
|
-
{ stage: 'pre_flop', player: round.players[0], amount: 1, move: 'bet' },
|
33
|
-
{ stage: 'pre_flop', player: round.players[1], amount: 0, move: 'fold' },
|
34
|
-
{ stage: 'pre_flop', player: round.players[2], amount: 1, move: 'call' },
|
35
|
-
{ stage: 'pre_flop', player: round.players[0], amount: 0, move: 'call' }
|
36
|
-
]
|
37
|
-
end
|
38
|
-
|
39
|
-
before do
|
40
|
-
round.next_stage
|
41
|
-
end
|
42
|
-
|
43
|
-
it { expect(round.current_stage).to eq('flop') }
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
describe '#ready_for_next_stage?' do
|
48
|
-
before do
|
49
|
-
allow(round).to receive(:action_history).and_return(action_history)
|
50
|
-
end
|
51
|
-
|
52
|
-
subject { round.ready_for_next_stage? }
|
53
|
-
|
54
|
-
context 'on game start' do
|
55
|
-
let(:action_history) { [] }
|
56
|
-
|
57
|
-
it { should eq(false) }
|
58
|
-
end
|
59
|
-
|
60
|
-
context 'on the pre_flop' do
|
61
|
-
|
62
|
-
context 'situation 1' do
|
63
|
-
let(:action_history) do
|
64
|
-
[
|
65
|
-
{ stage: 'pre_flop', player: round.players[0], amount: 1, move: 'bet' },
|
66
|
-
{ stage: 'pre_flop', player: round.players[1], amount: 0, move: 'fold' }
|
67
|
-
]
|
68
|
-
end
|
69
|
-
it { should eq(false) }
|
70
|
-
end
|
71
|
-
|
72
|
-
context 'situation 2' do
|
73
|
-
let(:action_history) do
|
74
|
-
[
|
75
|
-
{ stage: 'pre_flop', player: round.players[0], amount: 1, move: 'bet' },
|
76
|
-
{ stage: 'pre_flop', player: round.players[1], amount: 0, move: 'fold' },
|
77
|
-
{ stage: 'pre_flop', player: round.players[2], amount: 1, move: 'call' },
|
78
|
-
{ stage: 'pre_flop', player: round.players[0], amount: 0, move: 'call' }
|
79
|
-
]
|
80
|
-
end
|
81
|
-
|
82
|
-
it { should eq(true) }
|
83
|
-
end
|
84
|
-
|
85
|
-
end
|
86
|
-
|
87
|
-
context 'on the flop' do
|
88
|
-
|
89
|
-
context 'situation 1' do
|
90
|
-
let(:action_history) do
|
91
|
-
[
|
92
|
-
{ stage: 'pre_flop', player: round.players[0], amount: 1, move: 'bet' },
|
93
|
-
{ stage: 'pre_flop', player: round.players[1], amount: 0, move: 'fold' },
|
94
|
-
{ stage: 'pre_flop', player: round.players[2], amount: 1, move: 'call' },
|
95
|
-
{ stage: 'flop', player: round.players[0], amount: 1, move: 'bet' }
|
96
|
-
]
|
97
|
-
end
|
98
|
-
|
99
|
-
before do
|
100
|
-
allow(round).to receive(:current_stage).and_return('flop')
|
101
|
-
end
|
102
|
-
|
103
|
-
it { should eq(false) }
|
104
|
-
end
|
105
|
-
|
106
|
-
context 'situation 2' do
|
107
|
-
let(:action_history) do
|
108
|
-
[
|
109
|
-
{ stage: 'pre_flop', player: round.players[0], amount: 1, move: 'bet' },
|
110
|
-
{ stage: 'pre_flop', player: round.players[1], amount: 0, move: 'fold' },
|
111
|
-
{ stage: 'pre_flop', player: round.players[2], amount: 1, move: 'call' },
|
112
|
-
{ stage: 'pre_flop', player: round.players[0], amount: 0, move: 'call' },
|
113
|
-
{ stage: 'flop', player: round.players[0], amount: 3, move: 'bet' },
|
114
|
-
{ stage: 'flop', player: round.players[2], amount: 3, move: 'call' },
|
115
|
-
{ stage: 'flop', player: round.players[0], amount: 0, move: 'call' }
|
116
|
-
]
|
117
|
-
end
|
118
|
-
|
119
|
-
before do
|
120
|
-
allow(round).to receive(:current_stage).and_return('flop')
|
121
|
-
end
|
122
|
-
|
123
|
-
it { should eq(true) }
|
124
|
-
end
|
125
|
-
|
126
|
-
end
|
127
|
-
end
|
128
|
-
|
129
|
-
describe '#player_in_turn' do
|
130
|
-
let(:action_history) do
|
131
|
-
[
|
132
|
-
{ stage: 'pre_flop', player: round.players[0], amount: 1, move: 'bet' },
|
133
|
-
{ stage: 'pre_flop', player: round.players[1], amount: 0, move: 'fold' }
|
134
|
-
]
|
135
|
-
end
|
136
|
-
|
137
|
-
before do
|
138
|
-
allow(round).to receive(:action_history).and_return(action_history)
|
139
|
-
end
|
140
|
-
|
141
|
-
subject { round.send(:player_in_turn) }
|
142
|
-
|
143
|
-
it { should == round.players[2] }
|
144
|
-
end
|
145
|
-
|
146
|
-
describe '#players_still_in_round' do
|
147
|
-
let(:action_history) do
|
148
|
-
[
|
149
|
-
{ stage: 'pre_flop', player: round.players[0], amount: 1, move: 'bet' },
|
150
|
-
{ stage: 'pre_flop', player: round.players[1], amount: 0, move: 'fold' }
|
151
|
-
]
|
152
|
-
end
|
153
|
-
|
154
|
-
before do
|
155
|
-
allow(round).to receive(:action_history).and_return(action_history)
|
156
|
-
end
|
157
|
-
|
158
|
-
subject { round.send(:players_still_in_round) }
|
159
|
-
|
160
|
-
its([0]) { should eq(round.players[0]) }
|
161
|
-
its([1]) { should eq(round.players[2]) }
|
162
|
-
end
|
163
|
-
|
164
|
-
describe '#highest_bet_placed' do
|
165
|
-
before do
|
166
|
-
round.make_move('call')
|
167
|
-
round.make_move('call')
|
168
|
-
round.make_move('bet', 4)
|
169
|
-
end
|
170
|
-
|
171
|
-
subject { round.send(:highest_bet_placed) }
|
172
|
-
|
173
|
-
it { should eq(4) }
|
174
|
-
end
|
175
|
-
|
176
|
-
describe '#has_winner?' do
|
177
|
-
subject { round.has_winner? }
|
178
|
-
|
179
|
-
context 'round won after folds' do
|
180
|
-
let(:action_history) do
|
181
|
-
[
|
182
|
-
{ stage: 'pre_flop', player: round.players[0], amount: 1, move: 'bet' },
|
183
|
-
{ stage: 'pre_flop', player: round.players[1], amount: 4, move: 'bet' },
|
184
|
-
{ stage: 'pre_flop', player: round.players[2], amount: 0, move: 'fold'},
|
185
|
-
{ stage: 'pre_flop', player: round.players[0], amount: 3, move: 'call' },
|
186
|
-
{ stage: 'flop', player: round.players[1], amount: 0, move: 'call' },
|
187
|
-
{ stage: 'flop', player: round.players[0], amount: 0, move: 'fold' }
|
188
|
-
]
|
189
|
-
end
|
190
|
-
|
191
|
-
before do
|
192
|
-
allow(round).to receive(:action_history).and_return(action_history)
|
193
|
-
end
|
194
|
-
|
195
|
-
it { should eq(true) }
|
196
|
-
end
|
197
|
-
|
198
|
-
context 'showdown between remaining players' do
|
199
|
-
before do
|
200
|
-
allow(round).to receive(:current_stage).and_return('show_down')
|
201
|
-
end
|
202
|
-
|
203
|
-
it { should eq(true) }
|
204
|
-
end
|
205
|
-
end
|
206
|
-
|
207
|
-
describe '#winner' do
|
208
|
-
|
209
|
-
end
|
210
|
-
|
211
|
-
describe '#apply_bet' do
|
212
|
-
context 'at the start of the round' do
|
213
|
-
before do
|
214
|
-
round.send(:apply_bet, 1)
|
215
|
-
end
|
216
|
-
|
217
|
-
subject { round }
|
218
|
-
|
219
|
-
its(:action_history) { should eq([{ player: round.players[0], stage: 'pre_flop', move: 'bet', amount: 1 }]) }
|
220
|
-
its(:pot_amount) { should eq(1) }
|
221
|
-
end
|
222
|
-
end
|
223
|
-
|
224
|
-
describe '#apply_call' do
|
225
|
-
context 'at the start of the round' do
|
226
|
-
before do
|
227
|
-
round.send(:apply_call)
|
228
|
-
end
|
229
|
-
|
230
|
-
subject { round }
|
231
|
-
|
232
|
-
its(:action_history) { should eq([{ player: round.players[0], stage: 'pre_flop', move: 'call', amount: 0 }]) }
|
233
|
-
its(:pot_amount) { should eq(0) }
|
234
|
-
end
|
235
|
-
end
|
236
|
-
|
237
|
-
describe '#apply_fold' do
|
238
|
-
context 'at the start of the round' do
|
239
|
-
before do
|
240
|
-
round.send(:apply_fold)
|
241
|
-
end
|
242
|
-
|
243
|
-
subject { round }
|
244
|
-
|
245
|
-
its(:action_history) { should eq([{ player: round.players[0], stage: 'pre_flop', move: 'fold', amount: 0 }]) }
|
246
|
-
its(:pot_amount) { should eq(0) }
|
247
|
-
end
|
248
|
-
end
|
249
|
-
end
|