acpc_poker_match_state 0.0.4 → 1.0.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 +4 -4
- data/acpc_poker_match_state.gemspec +8 -9
- data/lib/acpc_poker_match_state.rb +3 -3
- data/lib/acpc_poker_match_state/match_state_transition.rb +22 -23
- data/lib/acpc_poker_match_state/players_at_the_table.rb +315 -329
- data/lib/acpc_poker_match_state/version.rb +1 -1
- data/spec/coverage/assets/0.7.1/application.css +1110 -0
- data/spec/coverage/assets/0.7.1/application.js +626 -0
- data/spec/coverage/assets/0.7.1/fancybox/blank.gif +0 -0
- data/spec/coverage/assets/0.7.1/fancybox/fancy_close.png +0 -0
- data/spec/coverage/assets/0.7.1/fancybox/fancy_loading.png +0 -0
- data/spec/coverage/assets/0.7.1/fancybox/fancy_nav_left.png +0 -0
- data/spec/coverage/assets/0.7.1/fancybox/fancy_nav_right.png +0 -0
- data/spec/coverage/assets/0.7.1/fancybox/fancy_shadow_e.png +0 -0
- data/spec/coverage/assets/0.7.1/fancybox/fancy_shadow_n.png +0 -0
- data/spec/coverage/assets/0.7.1/fancybox/fancy_shadow_ne.png +0 -0
- data/spec/coverage/assets/0.7.1/fancybox/fancy_shadow_nw.png +0 -0
- data/spec/coverage/assets/0.7.1/fancybox/fancy_shadow_s.png +0 -0
- data/spec/coverage/assets/0.7.1/fancybox/fancy_shadow_se.png +0 -0
- data/spec/coverage/assets/0.7.1/fancybox/fancy_shadow_sw.png +0 -0
- data/spec/coverage/assets/0.7.1/fancybox/fancy_shadow_w.png +0 -0
- data/spec/coverage/assets/0.7.1/fancybox/fancy_title_left.png +0 -0
- data/spec/coverage/assets/0.7.1/fancybox/fancy_title_main.png +0 -0
- data/spec/coverage/assets/0.7.1/fancybox/fancy_title_over.png +0 -0
- data/spec/coverage/assets/0.7.1/fancybox/fancy_title_right.png +0 -0
- data/spec/coverage/assets/0.7.1/fancybox/fancybox-x.png +0 -0
- data/spec/coverage/assets/0.7.1/fancybox/fancybox-y.png +0 -0
- data/spec/coverage/assets/0.7.1/fancybox/fancybox.png +0 -0
- data/spec/coverage/assets/0.7.1/favicon_green.png +0 -0
- data/spec/coverage/assets/0.7.1/favicon_red.png +0 -0
- data/spec/coverage/assets/0.7.1/favicon_yellow.png +0 -0
- data/spec/coverage/assets/0.7.1/loading.gif +0 -0
- data/spec/coverage/assets/0.7.1/magnify.png +0 -0
- data/spec/coverage/assets/0.7.1/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
- data/spec/coverage/assets/0.7.1/smoothness/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
- data/spec/coverage/assets/0.7.1/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
- data/spec/coverage/assets/0.7.1/smoothness/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
- data/spec/coverage/assets/0.7.1/smoothness/images/ui-bg_glass_75_dadada_1x400.png +0 -0
- data/spec/coverage/assets/0.7.1/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
- data/spec/coverage/assets/0.7.1/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
- data/spec/coverage/assets/0.7.1/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
- data/spec/coverage/assets/0.7.1/smoothness/images/ui-icons_222222_256x240.png +0 -0
- data/spec/coverage/assets/0.7.1/smoothness/images/ui-icons_2e83ff_256x240.png +0 -0
- data/spec/coverage/assets/0.7.1/smoothness/images/ui-icons_454545_256x240.png +0 -0
- data/spec/coverage/assets/0.7.1/smoothness/images/ui-icons_888888_256x240.png +0 -0
- data/spec/coverage/assets/0.7.1/smoothness/images/ui-icons_cd0a0a_256x240.png +0 -0
- data/spec/coverage/index.html +72 -0
- data/spec/match_state_transition_spec.rb +5 -5
- data/spec/players_at_the_table_spec.rb +15 -37
- data/spec/support/spec_helper.rb +5 -3
- metadata +134 -66
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b4add49d2c0e5aced134d96916d14060b80cb2ac
|
4
|
+
data.tar.gz: 14ff0c1a37e0277ddd3eba22a6fcd5777ebcf95c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 147975becc5c6ab3abfdb38a449070dfa400fc8c9cce58726df4796f654f49a9704b55aea06b878f04566369eea84adf7e1f0dea03a3d7edfb39c1e1933841fd
|
7
|
+
data.tar.gz: b980f324be2472f5a3be487c490c88dab8d1408e1f29bdd7f3a9020f136287e550340ee59dc6b97c5215eaa99ae35c9dc604eeb2266758a57cd8038bb63ebc77
|
@@ -10,8 +10,8 @@ Gem::Specification.new do |s|
|
|
10
10
|
s.summary = %q{ACPC Poker Match State}
|
11
11
|
s.description = %q{Match state data manager.}
|
12
12
|
|
13
|
-
s.add_dependency 'acpc_poker_types'
|
14
|
-
s.add_dependency 'dmorrill10-utils'
|
13
|
+
s.add_dependency 'acpc_poker_types', '~> 3.0'
|
14
|
+
s.add_dependency 'dmorrill10-utils', '~> 1.0'
|
15
15
|
|
16
16
|
s.rubyforge_project = "acpc_poker_match_state"
|
17
17
|
|
@@ -19,11 +19,10 @@ Gem::Specification.new do |s|
|
|
19
19
|
s.test_files = Dir.glob "spec/**/*"
|
20
20
|
s.require_paths = ["lib"]
|
21
21
|
|
22
|
-
s.add_development_dependency 'turn'
|
23
|
-
s.add_development_dependency 'minitest'
|
24
|
-
s.add_development_dependency '
|
25
|
-
s.add_development_dependency '
|
26
|
-
s.add_development_dependency '
|
27
|
-
s.add_development_dependency '
|
28
|
-
s.add_development_dependency 'pry-rescue'
|
22
|
+
s.add_development_dependency 'turn', '~> 0.9'
|
23
|
+
s.add_development_dependency 'minitest', '~> 4.7'
|
24
|
+
s.add_development_dependency 'acpc_dealer', '~> 0.0'
|
25
|
+
s.add_development_dependency 'awesome_print', '~> 1.0'
|
26
|
+
s.add_development_dependency 'pry-rescue', '~> 1.0'
|
27
|
+
s.add_development_dependency 'simplecov', '~> 0.7'
|
29
28
|
end
|
@@ -1,7 +1,7 @@
|
|
1
|
-
require
|
1
|
+
require 'acpc_poker_match_state/version'
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
3
|
+
require 'acpc_poker_match_state/match_state_transition'
|
4
|
+
require 'acpc_poker_match_state/players_at_the_table'
|
5
5
|
|
6
6
|
module AcpcPokerMatchState
|
7
7
|
end
|
@@ -1,33 +1,32 @@
|
|
1
|
-
|
2
1
|
require 'dmorrill10-utils/class'
|
3
2
|
require 'acpc_poker_types/match_state'
|
4
3
|
|
5
|
-
|
6
|
-
|
7
|
-
|
4
|
+
module AcpcPokerMatchState
|
5
|
+
class MatchStateTransition
|
6
|
+
exceptions :no_state_given
|
8
7
|
|
9
|
-
|
8
|
+
attr_reader :next_state
|
9
|
+
attr_reader :last_state
|
10
10
|
|
11
|
-
|
11
|
+
def set_next_state!(new_state)
|
12
|
+
@last_state = @next_state
|
13
|
+
@next_state = new_state
|
14
|
+
self
|
15
|
+
end
|
12
16
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
17
|
+
# @return [Boolean] +true+ if the next state's round is different from the
|
18
|
+
# last, +false+ otherwise.
|
19
|
+
def new_round?
|
20
|
+
raise NoStateGiven unless @next_state
|
21
|
+
return true unless @last_state
|
18
22
|
|
19
|
-
|
20
|
-
|
21
|
-
def new_round?
|
22
|
-
raise NoStateGiven unless @next_state
|
23
|
-
return true unless @last_state
|
24
|
-
|
25
|
-
@next_state.round != @last_state.round
|
26
|
-
end
|
23
|
+
@next_state.round != @last_state.round
|
24
|
+
end
|
27
25
|
|
28
|
-
|
29
|
-
|
26
|
+
def initial_state?
|
27
|
+
raise NoStateGiven unless @next_state
|
30
28
|
|
31
|
-
|
29
|
+
@next_state.first_state_of_first_round?
|
30
|
+
end
|
32
31
|
end
|
33
|
-
end
|
32
|
+
end
|
@@ -1,433 +1,419 @@
|
|
1
|
-
|
2
|
-
require 'awesome_print'
|
1
|
+
require 'dmorrill10-utils/class'
|
3
2
|
|
4
|
-
require 'dmorrill10-utils'
|
5
3
|
require 'acpc_poker_types'
|
4
|
+
require 'acpc_poker_match_state/match_state_transition'
|
6
5
|
|
7
|
-
|
6
|
+
module AcpcPokerMatchState
|
7
|
+
class PlayersAtTheTable
|
8
8
|
|
9
|
-
|
9
|
+
exceptions :player_acted_before_sitting_at_table,
|
10
|
+
:no_players_to_seat, :users_seat_out_of_bounds,
|
11
|
+
:multiple_players_have_the_same_seat
|
10
12
|
|
11
|
-
|
12
|
-
:no_players_to_seat, :users_seat_out_of_bounds,
|
13
|
-
:multiple_players_have_the_same_seat
|
13
|
+
attr_reader :players
|
14
14
|
|
15
|
-
|
15
|
+
# @return [Array<Array<Integer>>] The sequence of seats that acted,
|
16
|
+
# separated by round.
|
17
|
+
attr_reader :player_acting_sequence
|
16
18
|
|
17
|
-
|
18
|
-
# separated by round.
|
19
|
-
attr_reader :player_acting_sequence
|
19
|
+
attr_reader :transition
|
20
20
|
|
21
|
-
|
21
|
+
attr_reader :number_of_hands
|
22
22
|
|
23
|
-
|
23
|
+
attr_reader :game_def
|
24
24
|
|
25
|
-
|
25
|
+
attr_reader :users_seat
|
26
26
|
|
27
|
-
|
27
|
+
attr_reader :min_wager
|
28
28
|
|
29
|
-
|
29
|
+
attr_reader :player_who_acted_last
|
30
30
|
|
31
|
-
|
31
|
+
alias_new :seat_players
|
32
32
|
|
33
|
-
|
33
|
+
# @param [GameDefinition] game_def The game definition for the
|
34
|
+
# match these players are playing.
|
35
|
+
# @param [Array<String>] player_names The names of the players to seat at the table,
|
36
|
+
# ordered by seat.
|
37
|
+
# @param [Integer] users_seat The user's seat at the table.
|
38
|
+
# players are joining.
|
39
|
+
# @param [Integer] number_of_hands The number of hands in this match.
|
40
|
+
def initialize(game_def, player_names, users_seat, number_of_hands)
|
41
|
+
@players = AcpcPokerTypes::Player.create_players player_names, game_def
|
34
42
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
# players are joining.
|
41
|
-
# @param [Integer] number_of_hands The number of hands in this match.
|
42
|
-
def initialize(game_def, player_names, users_seat, number_of_hands)
|
43
|
-
@players = Player.create_players player_names, game_def
|
44
|
-
|
45
|
-
@users_seat = if users_seat.seat_in_bounds?(number_of_players) && @players.any?{|player| player.seat == users_seat}
|
46
|
-
users_seat
|
47
|
-
else
|
48
|
-
raise UsersSeatOutOfBounds, users_seat
|
49
|
-
end
|
43
|
+
@users_seat = if users_seat.seat_in_bounds?(number_of_players) && @players.any?{|player| player.seat == users_seat}
|
44
|
+
users_seat
|
45
|
+
else
|
46
|
+
raise UsersSeatOutOfBounds, users_seat
|
47
|
+
end
|
50
48
|
|
51
|
-
|
52
|
-
|
49
|
+
@game_def = game_def
|
50
|
+
@min_wager = @game_def.min_wagers.first
|
53
51
|
|
54
|
-
|
52
|
+
@transition = AcpcPokerMatchState::MatchStateTransition.new
|
55
53
|
|
56
|
-
|
54
|
+
@player_acting_sequence = [[]]
|
57
55
|
|
58
|
-
|
59
|
-
|
56
|
+
@number_of_hands = number_of_hands
|
57
|
+
end
|
60
58
|
|
61
|
-
|
62
|
-
|
63
|
-
|
59
|
+
def blinds
|
60
|
+
@game_def.blinds
|
61
|
+
end
|
64
62
|
|
65
|
-
|
66
|
-
|
63
|
+
# @return [Integer] The number of players seated at the table.
|
64
|
+
def number_of_players() @players.length end
|
67
65
|
|
68
|
-
|
69
|
-
|
70
|
-
|
66
|
+
# @param [MatchState] match_state The next match state.
|
67
|
+
def update!(match_state)
|
68
|
+
@transition.set_next_state! match_state
|
71
69
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
70
|
+
if @transition.initial_state?
|
71
|
+
start_new_hand!
|
72
|
+
else
|
73
|
+
@player_acting_sequence.last << next_player_to_act(@transition.last_state).seat
|
76
74
|
|
77
|
-
|
75
|
+
update_state_of_players!
|
78
76
|
|
79
|
-
|
77
|
+
@player_acting_sequence << [] if @transition.new_round?
|
78
|
+
end
|
79
|
+
self
|
80
80
|
end
|
81
|
-
self
|
82
|
-
end
|
83
81
|
|
84
|
-
|
85
|
-
|
82
|
+
def next_player_to_act(state=@transition.next_state)
|
83
|
+
return nil unless state && !hand_ended? && !active_players.empty?
|
86
84
|
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
85
|
+
reference_position = if state.number_of_actions_this_round > 0
|
86
|
+
position_relative_to_dealer player_who_acted_last
|
87
|
+
else
|
88
|
+
@game_def.first_player_positions[state.round] - 1
|
89
|
+
end
|
92
90
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
91
|
+
number_of_players.times.inject(nil) do |player_who_might_act, i|
|
92
|
+
position_relative_to_dealer_to_act = (reference_position + i + 1) % number_of_players
|
93
|
+
player_who_might_act = active_players.find do |player|
|
94
|
+
position_relative_to_dealer(player) == position_relative_to_dealer_to_act
|
95
|
+
end
|
96
|
+
if player_who_might_act then break player_who_might_act else nil end
|
97
97
|
end
|
98
|
-
if player_who_might_act then break player_who_might_act else nil end
|
99
98
|
end
|
100
|
-
end
|
101
99
|
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
100
|
+
def player_who_acted_last
|
101
|
+
unless @transition.next_state && @transition.next_state.round_in_which_last_action_taken
|
102
|
+
nil
|
103
|
+
else
|
104
|
+
@players.find do |player|
|
105
|
+
player.seat == @player_acting_sequence[@transition.next_state.round_in_which_last_action_taken].last
|
106
|
+
end
|
108
107
|
end
|
109
108
|
end
|
110
|
-
end
|
111
109
|
|
112
|
-
|
113
|
-
|
114
|
-
|
110
|
+
def opponents
|
111
|
+
@players.select { |player| player.seat != @users_seat }
|
112
|
+
end
|
115
113
|
|
116
|
-
|
117
|
-
|
118
|
-
|
114
|
+
def user_player
|
115
|
+
@players.find { |player| @users_seat == player.seat }
|
116
|
+
end
|
119
117
|
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
118
|
+
# @return [Array<AcpcPokerTypes::Player>] The players who are active.
|
119
|
+
def active_players
|
120
|
+
@players.select { |player| player.active? }
|
121
|
+
end
|
124
122
|
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
123
|
+
#@return [Array<AcpcPokerTypes::Player>] The players who have not folded.
|
124
|
+
def non_folded_players
|
125
|
+
@players.select { |player| !player.folded? }
|
126
|
+
end
|
129
127
|
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
128
|
+
# @return [Boolean] +true+ if the hand has ended, +false+ otherwise.
|
129
|
+
def hand_ended?
|
130
|
+
less_than_two_non_folded_players? || reached_showdown?
|
131
|
+
end
|
134
132
|
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
133
|
+
# @return [Boolean] +true+ if the match has ended, +false+ otherwise.
|
134
|
+
def match_ended?
|
135
|
+
hand_ended? && last_hand?
|
136
|
+
end
|
139
137
|
|
140
|
-
|
141
|
-
|
142
|
-
|
138
|
+
def less_than_two_non_folded_players?
|
139
|
+
non_folded_players.length < 2
|
140
|
+
end
|
143
141
|
|
144
|
-
|
145
|
-
|
146
|
-
|
142
|
+
def reached_showdown?
|
143
|
+
opponents_cards_visible?
|
144
|
+
end
|
147
145
|
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
146
|
+
# @return [Boolean] +true+ if any opponents cards are visible, +false+ otherwise.
|
147
|
+
def opponents_cards_visible?
|
148
|
+
opponents.any? { |player| player.hole_cards && !player.hole_cards.empty? }
|
149
|
+
end
|
152
150
|
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
151
|
+
# @return [AcpcPokerTypes::Player] The player with the dealer button.
|
152
|
+
def player_with_dealer_button
|
153
|
+
return nil unless @transition.next_state
|
154
|
+
@players.find { |player| position_relative_to_dealer(player) == number_of_players - 1}
|
155
|
+
end
|
158
156
|
|
159
|
-
|
160
|
-
|
161
|
-
|
157
|
+
# @return [Hash<AcpcPokerTypes::Player, #to_i] Relation from player to the blind that player paid.
|
158
|
+
def player_blind_relation
|
159
|
+
return nil unless @transition.next_state
|
162
160
|
|
163
|
-
|
164
|
-
|
165
|
-
|
161
|
+
@players.inject({}) do |relation, player|
|
162
|
+
relation[player] = blinds[position_relative_to_dealer(player)]
|
163
|
+
relation
|
164
|
+
end
|
166
165
|
end
|
167
|
-
end
|
168
166
|
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
167
|
+
# @return [String] player acting sequence as a string.
|
168
|
+
def player_acting_sequence_string
|
169
|
+
(@player_acting_sequence.map { |per_round| per_round.join('') }).join('/')
|
170
|
+
end
|
173
171
|
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
172
|
+
def betting_sequence_string
|
173
|
+
(betting_sequence.map do |per_round|
|
174
|
+
(per_round.map{|action| action.to_s}).join('')
|
175
|
+
end).join('/')
|
176
|
+
end
|
179
177
|
|
180
|
-
|
181
|
-
|
182
|
-
|
178
|
+
def betting_sequence
|
179
|
+
sequence = [[]]
|
180
|
+
return sequence unless @transition.next_state
|
183
181
|
|
184
|
-
|
185
|
-
|
182
|
+
@player_acting_sequence.each_with_index do |per_round, i|
|
183
|
+
actions_taken_this_round = {}
|
186
184
|
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
185
|
+
unless per_round.empty?
|
186
|
+
@players.each do |player|
|
187
|
+
# Skip if player has folded and a round after the fold is being checked
|
188
|
+
next if i >= player.actions_taken_this_hand.length
|
191
189
|
|
192
|
-
|
190
|
+
actions_taken_this_round[player.seat] = player.actions_taken_this_hand[i].dup
|
191
|
+
end
|
193
192
|
end
|
194
|
-
end
|
195
193
|
|
196
|
-
|
197
|
-
|
194
|
+
per_round.each do |seat|
|
195
|
+
sequence.last << actions_taken_this_round[seat].shift
|
196
|
+
end
|
197
|
+
sequence << [] if (@transition.next_state.round+1) > sequence.length
|
198
198
|
end
|
199
|
-
sequence
|
199
|
+
sequence
|
200
200
|
end
|
201
|
-
sequence
|
202
|
-
end
|
203
201
|
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
202
|
+
# @return [Boolean] +true+ if it is the user's turn to act, +false+ otherwise.
|
203
|
+
def users_turn_to_act?
|
204
|
+
if next_player_to_act
|
205
|
+
next_player_to_act.seat == @users_seat
|
206
|
+
else
|
207
|
+
false
|
208
|
+
end
|
210
209
|
end
|
211
|
-
end
|
212
210
|
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
211
|
+
# @return [Array<AcpcPokerTypes::ChipStack>] AcpcPokerTypes::Player stacks.
|
212
|
+
def chip_stacks
|
213
|
+
@players.map { |player| player.chip_stack }
|
214
|
+
end
|
217
215
|
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
216
|
+
# return [Array<Integer>] Each player's current chip balance.
|
217
|
+
def chip_balances
|
218
|
+
@players.map { |player| player.chip_balance }
|
219
|
+
end
|
222
220
|
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
221
|
+
# return [Array<Array<Integer>>] Each player's current chip contribution organized by round.
|
222
|
+
def chip_contributions
|
223
|
+
@players.map { |player| player.chip_contributions }
|
224
|
+
end
|
227
225
|
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
226
|
+
# @param [Integer] player The player of which the position relative to the
|
227
|
+
# dealer is desired.
|
228
|
+
# @return [Integer] The position relative to the user of the given player,
|
229
|
+
# +player+, indexed such that the player immediately to the left of the
|
230
|
+
# dealer has a +position_relative_to_dealer+ of zero.
|
231
|
+
# @example The player immediately to the left of the user has
|
232
|
+
# +position_relative_to_user+ == 0
|
233
|
+
# @example The user has
|
234
|
+
# +position_relative_to_user+ == +number_of_players+ - 1
|
235
|
+
# @raise (see Integer#position_relative_to)
|
236
|
+
def position_relative_to_user(player)
|
237
|
+
player.seat.position_relative_to user_player.seat, number_of_players
|
238
|
+
end
|
241
239
|
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
240
|
+
# @param [Integer] player The player of which the position relative to the
|
241
|
+
# dealer is desired.
|
242
|
+
# @return [Integer] The position relative to the dealer of the given player,
|
243
|
+
# +player+, indexed such that the player immediately to to the left of the
|
244
|
+
# dealer has a +position_relative_to_dealer+ of zero.
|
245
|
+
# @raise (see Integer#seat_from_relative_position)
|
246
|
+
# @raise (see Integer#position_relative_to)
|
247
|
+
def position_relative_to_dealer(player)
|
248
|
+
seat_of_dealer = @users_seat.seat_from_relative_position(
|
249
|
+
users_position_relative_to_dealer, number_of_players)
|
250
|
+
|
251
|
+
player.seat.position_relative_to seat_of_dealer, number_of_players
|
252
|
+
end
|
255
253
|
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
254
|
+
def amount_to_call(player)
|
255
|
+
@players.map do |p|
|
256
|
+
p.chip_contributions.sum
|
257
|
+
end.max - player.chip_contributions.sum
|
258
|
+
end
|
261
259
|
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
260
|
+
def cost_of_action(player, action, round=@transition.next_state.round_in_which_last_action_taken)
|
261
|
+
AcpcPokerTypes::ChipStack.new(
|
262
|
+
if action.action == AcpcPokerTypes::PokerAction::CALL
|
263
|
+
amount_to_call player
|
264
|
+
elsif action.action == AcpcPokerTypes::PokerAction::BET || action.action == AcpcPokerTypes::PokerAction::RAISE
|
265
|
+
if action.modifier
|
266
|
+
action.modifier.to_i - player.chip_contributions.sum
|
267
|
+
else
|
268
|
+
@game_def.min_wagers[round] + amount_to_call(player)
|
269
|
+
end
|
269
270
|
else
|
270
|
-
|
271
|
+
0
|
271
272
|
end
|
272
|
-
|
273
|
-
0
|
274
|
-
end
|
275
|
-
)
|
276
|
-
end
|
277
|
-
|
278
|
-
# @return [Set] The set of legal actions for the currently acting player.
|
279
|
-
def legal_actions
|
280
|
-
list_of_actions = if next_player_to_act.nil?
|
281
|
-
[]
|
282
|
-
elsif player_sees_wager?
|
283
|
-
['c', 'f', 'r']
|
284
|
-
elsif chips_contributed_to_pot_this_round?
|
285
|
-
['k', 'r']
|
286
|
-
else
|
287
|
-
['k', 'b']
|
273
|
+
)
|
288
274
|
end
|
289
275
|
|
290
|
-
|
291
|
-
|
276
|
+
# @return [Set] The set of legal actions for the currently acting player.
|
277
|
+
def legal_actions
|
278
|
+
Set.new(
|
279
|
+
if next_player_to_act.nil?
|
280
|
+
[]
|
281
|
+
elsif player_sees_wager?
|
282
|
+
[AcpcPokerTypes::PokerAction::CALL, AcpcPokerTypes::PokerAction::FOLD, AcpcPokerTypes::PokerAction::RAISE]
|
283
|
+
elsif chips_contributed_to_pot_this_round?
|
284
|
+
[AcpcPokerTypes::PokerAction::CHECK, AcpcPokerTypes::PokerAction::RAISE]
|
285
|
+
else
|
286
|
+
[AcpcPokerTypes::PokerAction::CHECK, AcpcPokerTypes::PokerAction::BET]
|
287
|
+
end
|
288
|
+
)
|
292
289
|
end
|
293
|
-
end
|
294
290
|
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
291
|
+
# @return [Boolean] +true+ if the current hand is the last in the match.
|
292
|
+
def last_hand?
|
293
|
+
# @todo make sure +@match_state.hand_number+ is not greater than @number_of_hands
|
294
|
+
return false unless @transition.next_state
|
299
295
|
|
300
|
-
|
301
|
-
|
296
|
+
@transition.next_state.hand_number == @number_of_hands - 1
|
297
|
+
end
|
302
298
|
|
303
|
-
|
299
|
+
private
|
304
300
|
|
305
|
-
|
306
|
-
|
307
|
-
|
301
|
+
def player_contributed_to_pot_this_round?(player=next_player_to_act)
|
302
|
+
player.chip_contributions.last > 0
|
303
|
+
end
|
308
304
|
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
305
|
+
# @todo Change MST#next_state to current_state
|
306
|
+
def chips_contributed_to_pot_this_round?(round=@transition.next_state.round)
|
307
|
+
chip_contributions.inject(0) do |all_contributions, contributions|
|
308
|
+
all_contributions += contributions[round].to_r
|
309
|
+
end > 0
|
310
|
+
end
|
315
311
|
|
316
|
-
|
317
|
-
|
318
|
-
|
312
|
+
def player_sees_wager?(player=next_player_to_act)
|
313
|
+
return false unless player
|
314
|
+
amount_to_call(player) > 0
|
315
|
+
end
|
319
316
|
|
320
|
-
|
317
|
+
def users_position_relative_to_dealer() @transition.next_state.position_relative_to_dealer end
|
321
318
|
|
322
|
-
|
323
|
-
|
324
|
-
unless state && state.number_of_actions_this_hand > 0
|
325
|
-
nil
|
326
|
-
else
|
327
|
-
if state.number_of_actions_this_round < 1
|
328
|
-
state.round - 1
|
329
|
-
else
|
330
|
-
state.round
|
331
|
-
end
|
332
|
-
end
|
333
|
-
end
|
319
|
+
def start_new_hand!
|
320
|
+
@player_acting_sequence = [[]]
|
334
321
|
|
335
|
-
|
336
|
-
|
322
|
+
@players.each do |player|
|
323
|
+
player.start_new_hand!(
|
324
|
+
blinds[position_relative_to_dealer(player)],
|
325
|
+
@game_def.chip_stacks[position_relative_to_dealer(player)], # @todo if playing Doyle's game
|
326
|
+
@transition.next_state.list_of_hole_card_hands[position_relative_to_dealer(player)]
|
327
|
+
)
|
328
|
+
end
|
337
329
|
|
338
|
-
|
339
|
-
player.start_new_hand!(
|
340
|
-
blinds[position_relative_to_dealer(player)],
|
341
|
-
@game_def.chip_stacks[position_relative_to_dealer(player)], # @todo if playing Doyle's game
|
342
|
-
@transition.next_state.list_of_hole_card_hands[position_relative_to_dealer(player)]
|
343
|
-
)
|
330
|
+
set_min_wager!
|
344
331
|
end
|
345
332
|
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
@players.each do |player|
|
351
|
-
player.assign_cards! @transition.next_state.list_of_hole_card_hands[position_relative_to_dealer(player)]
|
333
|
+
def assign_hole_cards_to_players!
|
334
|
+
@players.each do |player|
|
335
|
+
player.assign_cards! @transition.next_state.list_of_hole_card_hands[position_relative_to_dealer(player)]
|
336
|
+
end
|
352
337
|
end
|
353
|
-
end
|
354
338
|
|
355
|
-
|
356
|
-
|
339
|
+
def update_state_of_players!
|
340
|
+
assign_hole_cards_to_players!
|
357
341
|
|
358
|
-
|
359
|
-
|
360
|
-
|
342
|
+
action_with_context = AcpcPokerTypes::PokerAction.new(
|
343
|
+
@transition.next_state.last_action.to_s,
|
344
|
+
cost: cost_of_action(
|
361
345
|
player_who_acted_last,
|
362
346
|
@transition.next_state.last_action
|
363
|
-
)
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
last_amount_called = amount_to_call(player_who_acted_last)
|
370
|
-
@min_wager = ChipStack.new [@min_wager.to_r, action_with_context.amount_to_put_in_pot.to_r - last_amount_called].max
|
371
|
-
end
|
347
|
+
)
|
348
|
+
)
|
349
|
+
unless action_with_context.to_s == 'f'
|
350
|
+
last_amount_called = amount_to_call(player_who_acted_last)
|
351
|
+
@min_wager = AcpcPokerTypes::ChipStack.new [@min_wager.to_r, action_with_context.cost.to_r - last_amount_called].max
|
352
|
+
end
|
372
353
|
|
373
|
-
|
354
|
+
player_who_acted_last.take_action!(
|
355
|
+
action_with_context,
|
356
|
+
pot_gained_chips: chips_contributed_to_pot_this_round?(@transition.next_state.round_in_which_last_action_taken),
|
357
|
+
sees_wager: player_sees_wager?
|
358
|
+
)
|
374
359
|
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
360
|
+
if @transition.new_round?
|
361
|
+
active_players.each { |player| player.start_new_round! }
|
362
|
+
set_min_wager!
|
363
|
+
end
|
379
364
|
|
380
|
-
|
381
|
-
|
365
|
+
if hand_ended?
|
366
|
+
distribute_chips! @transition.next_state.board_cards
|
367
|
+
end
|
382
368
|
end
|
383
|
-
end
|
384
369
|
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
# @todo This only works for Doyle's game where there are no side-pots.
|
392
|
-
if 1 == non_folded_players.length
|
393
|
-
non_folded_players.first.take_winnings! pot
|
394
|
-
else
|
395
|
-
players_and_their_hand_strength = {}
|
396
|
-
non_folded_players.each do |player|
|
397
|
-
hand_strength = PileOfCards.new(board_cards.flatten + player.hole_cards).to_poker_hand_strength
|
398
|
-
|
399
|
-
players_and_their_hand_strength[player] = hand_strength
|
400
|
-
end
|
370
|
+
# Distribute chips to all winning players
|
371
|
+
# @param [BoardCards] board_cards The community board cards.
|
372
|
+
def distribute_chips!(board_cards)
|
373
|
+
raise NoChipsToDistribute unless pot > 0
|
374
|
+
raise NoPlayersToTakeChips unless non_folded_players.length > 0
|
401
375
|
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
376
|
+
# @todo This only works for Doyle's game where there are no side-pots.
|
377
|
+
if 1 == non_folded_players.length
|
378
|
+
non_folded_players.first.take_winnings! pot
|
379
|
+
else
|
380
|
+
players_and_their_hand_strength = {}
|
381
|
+
non_folded_players.each do |player|
|
382
|
+
hand_strength = AcpcPokerTypes::PileOfCards.new(board_cards.flatten + player.hole_cards).to_poker_hand_strength
|
406
383
|
|
407
|
-
|
384
|
+
players_and_their_hand_strength[player] = hand_strength
|
385
|
+
end
|
408
386
|
|
409
|
-
|
410
|
-
|
387
|
+
strength_of_strongest_hand = players_and_their_hand_strength.values.max
|
388
|
+
winning_players = players_and_their_hand_strength.find_all do |player, hand_strength|
|
389
|
+
hand_strength == strength_of_strongest_hand
|
390
|
+
end.map { |player_with_hand_strength| player_with_hand_strength.first }
|
391
|
+
|
392
|
+
amount_each_player_wins = pot/winning_players.length.to_r
|
393
|
+
|
394
|
+
winning_players.each do |player|
|
395
|
+
player.take_winnings! amount_each_player_wins
|
396
|
+
end
|
411
397
|
end
|
412
398
|
end
|
413
|
-
end
|
414
399
|
|
415
|
-
|
416
|
-
|
417
|
-
|
400
|
+
def pot
|
401
|
+
chip_contributions.mapped_sum.sum
|
402
|
+
end
|
418
403
|
|
419
|
-
|
420
|
-
|
404
|
+
def set_min_wager!
|
405
|
+
@min_wager = @game_def.min_wagers[@transition.next_state.round]
|
406
|
+
end
|
421
407
|
end
|
422
|
-
end
|
423
408
|
|
424
|
-
class Array
|
425
|
-
|
426
|
-
|
427
|
-
|
409
|
+
class Array
|
410
|
+
def find_out_of_bounds_seat(number_of_players)
|
411
|
+
self.find do |position|
|
412
|
+
!position.seat_in_bounds?(number_of_players)
|
413
|
+
end
|
414
|
+
end
|
415
|
+
def copy
|
416
|
+
inject([]) { |new_array, elem| new_array << elem.copy }
|
428
417
|
end
|
429
418
|
end
|
430
|
-
|
431
|
-
inject([]) { |new_array, elem| new_array << elem.copy }
|
432
|
-
end
|
433
|
-
end
|
419
|
+
end
|