acpc_dealer_data 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +17 -0
- data/.yardopts +7 -0
- data/Gemfile +4 -0
- data/LICENSE.md +17 -0
- data/README.md +45 -0
- data/Rakefile +12 -0
- data/acpc_dealer_data.gemspec +27 -0
- data/lib/acpc_dealer_data.rb +10 -0
- data/lib/acpc_dealer_data/action_messages.rb +90 -0
- data/lib/acpc_dealer_data/hand_data.rb +164 -0
- data/lib/acpc_dealer_data/hand_results.rb +71 -0
- data/lib/acpc_dealer_data/match_definition.rb +56 -0
- data/lib/acpc_dealer_data/poker_match_data.rb +178 -0
- data/lib/acpc_dealer_data/version.rb +3 -0
- data/spec/action_messages_spec.rb +308 -0
- data/spec/hand_data_spec.rb +295 -0
- data/spec/hand_results_spec.rb +231 -0
- data/spec/match_definition_spec.rb +95 -0
- data/spec/poker_match_data_spec.rb +243 -0
- data/spec/support/spec_helper.rb +24 -0
- metadata +189 -0
@@ -0,0 +1,56 @@
|
|
1
|
+
|
2
|
+
require 'set'
|
3
|
+
|
4
|
+
require 'acpc_poker_types/game_definition'
|
5
|
+
|
6
|
+
require 'dmorrill10-utils/class'
|
7
|
+
|
8
|
+
class MatchDefinition
|
9
|
+
|
10
|
+
exceptions :unable_to_parse, :incorrect_number_of_player_names
|
11
|
+
|
12
|
+
attr_reader :name, :game_def, :number_of_hands, :random_seed, :player_names
|
13
|
+
|
14
|
+
def self.parse(acpc_log_string, player_names, game_def_directory)
|
15
|
+
if acpc_log_string.strip.match(
|
16
|
+
'^\s*#\s*name/game/hands/seed\s+(\S+)\s+(\S+)\s+(\d+)\s+(\d+)\s*$'
|
17
|
+
)
|
18
|
+
name = $1
|
19
|
+
game_def = GameDefinition.parse_file(File.join(game_def_directory, File.basename($2)))
|
20
|
+
number_of_hands = $3
|
21
|
+
random_seed = $4
|
22
|
+
|
23
|
+
MatchDefinition.new(
|
24
|
+
name,
|
25
|
+
game_def,
|
26
|
+
number_of_hands,
|
27
|
+
random_seed,
|
28
|
+
player_names
|
29
|
+
)
|
30
|
+
else
|
31
|
+
nil
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def initialize(name, game_def, number_of_hands, random_seed, player_names)
|
36
|
+
if game_def.number_of_players != player_names.length
|
37
|
+
raise IncorrectNumberOfPlayerNames, "number of players: #{game_def.number_of_players}, number of names: #{player_names.length}"
|
38
|
+
end
|
39
|
+
|
40
|
+
@name = name.to_s
|
41
|
+
@game_def = game_def
|
42
|
+
@number_of_hands = number_of_hands.to_i
|
43
|
+
@random_seed = random_seed.to_i
|
44
|
+
@player_names = player_names
|
45
|
+
end
|
46
|
+
|
47
|
+
def ==(other)
|
48
|
+
(
|
49
|
+
@name == other.name &&
|
50
|
+
Set.new(@game_def.to_a) == Set.new(other.game_def.to_a) &&
|
51
|
+
@number_of_hands == other.number_of_hands &&
|
52
|
+
@random_seed == other.random_seed &&
|
53
|
+
@player_names == other.player_names
|
54
|
+
)
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,178 @@
|
|
1
|
+
|
2
|
+
require 'acpc_poker_types/player'
|
3
|
+
|
4
|
+
require 'celluloid'
|
5
|
+
|
6
|
+
require 'dmorrill10-utils/class'
|
7
|
+
|
8
|
+
require_relative 'action_messages'
|
9
|
+
require_relative 'hand_data'
|
10
|
+
require_relative 'hand_results'
|
11
|
+
require_relative 'match_definition'
|
12
|
+
|
13
|
+
class PokerMatchData
|
14
|
+
|
15
|
+
exceptions :match_definitions_do_not_match, :final_scores_do_not_match, :player_data_inconsistent
|
16
|
+
|
17
|
+
attr_reader :chip_distribution, :match_def, :hand_number, :data, :players
|
18
|
+
attr_accessor :seat
|
19
|
+
|
20
|
+
def self.parse_files(action_messages_file, result_messages_file, player_names, dealer_directory)
|
21
|
+
parsed_action_messages = Celluloid::Future.new { ActionMessages.parse_file action_messages_file, player_names, dealer_directory }
|
22
|
+
parsed_hand_results = Celluloid::Future.new { HandResults.parse_file result_messages_file, player_names, dealer_directory }
|
23
|
+
|
24
|
+
PokerMatchData.new parsed_action_messages.value, parsed_hand_results.value, player_names, dealer_directory
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.parse(action_messages, result_messages, player_names, dealer_directory)
|
28
|
+
parsed_action_messages = ActionMessages.parse action_messages, player_names, dealer_directory
|
29
|
+
parsed_hand_results = HandResults.parse result_messages, player_names, dealer_directory
|
30
|
+
|
31
|
+
PokerMatchData.new parsed_action_messages, parsed_hand_results, player_names, dealer_directory
|
32
|
+
end
|
33
|
+
|
34
|
+
def initialize(parsed_action_messages, parsed_hand_results, player_names, dealer_directory)
|
35
|
+
if (
|
36
|
+
parsed_action_messages.match_def.nil? ||
|
37
|
+
parsed_hand_results.match_def.nil? ||
|
38
|
+
parsed_action_messages.match_def != parsed_hand_results.match_def
|
39
|
+
)
|
40
|
+
raise MatchDefinitionsDoNotMatch
|
41
|
+
end
|
42
|
+
|
43
|
+
if (
|
44
|
+
parsed_action_messages.final_score.nil? ||
|
45
|
+
parsed_hand_results.final_score.nil? ||
|
46
|
+
parsed_action_messages.final_score != parsed_hand_results.final_score
|
47
|
+
)
|
48
|
+
raise FinalScoresDoNotMatch
|
49
|
+
end
|
50
|
+
|
51
|
+
@match_def = parsed_hand_results.match_def
|
52
|
+
|
53
|
+
set_chip_distribution! parsed_hand_results.final_score
|
54
|
+
|
55
|
+
set_data! parsed_action_messages, parsed_hand_results
|
56
|
+
|
57
|
+
@seat = 0
|
58
|
+
@players = @match_def.player_names.length.times.map do |seat|
|
59
|
+
Player.join_match(
|
60
|
+
@match_def.player_names[seat],
|
61
|
+
seat,
|
62
|
+
@match_def.game_def.chip_stacks[seat]
|
63
|
+
)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def for_every_seat!
|
68
|
+
match_def.game_def.number_of_players.times do |seat|
|
69
|
+
@seat = seat
|
70
|
+
|
71
|
+
@players = @match_def.player_names.length.times.map do |seat_j|
|
72
|
+
Player.join_match(
|
73
|
+
@match_def.player_names[seat_j],
|
74
|
+
seat_j,
|
75
|
+
@match_def.game_def.chip_stacks[seat_j]
|
76
|
+
)
|
77
|
+
end
|
78
|
+
|
79
|
+
yield seat
|
80
|
+
end
|
81
|
+
|
82
|
+
self
|
83
|
+
end
|
84
|
+
|
85
|
+
def player_name(seat=@seat) @players[seat].name end
|
86
|
+
def chip_balance(seat=@seat) @players[seat].chip_balance end
|
87
|
+
def hole_cards(seat=@seat) @players[seat].hole_cards end
|
88
|
+
def actions_taken_this_hand(seat=@seat) @players[seat].actions_taken_this_hand end
|
89
|
+
def folded?(seat=@seat) @players[seat].folded? end
|
90
|
+
def all_in?(seat=@seat) @players[seat].all_in? end
|
91
|
+
def active?(seat=@seat) @players[seat].active? end
|
92
|
+
|
93
|
+
def for_every_hand!
|
94
|
+
@data.each_index do |i|
|
95
|
+
@hand_number = i
|
96
|
+
|
97
|
+
@players.each_with_index do |player, seat|
|
98
|
+
player.start_new_hand!(
|
99
|
+
@match_def.game_def.blinds[@seat],
|
100
|
+
@match_def.game_def.chip_stacks[@seat],
|
101
|
+
current_hand.data.first.state_messages[seat].users_hole_cards
|
102
|
+
)
|
103
|
+
end
|
104
|
+
|
105
|
+
yield @hand_number
|
106
|
+
end
|
107
|
+
|
108
|
+
if @chip_distribution != @players.map { |p| p.chip_balance }
|
109
|
+
raise PlayerDataInconsistent, "chip distribution: #{@chip_distribution}, player balances: #{@players.map { |p| p.chip_balance }}"
|
110
|
+
end
|
111
|
+
|
112
|
+
@hand_number = nil
|
113
|
+
self
|
114
|
+
end
|
115
|
+
|
116
|
+
def for_every_turn!
|
117
|
+
current_hand.for_every_turn!(@seat) do |turn_number|
|
118
|
+
@players.each_with_index do |player, seat|
|
119
|
+
last_match_state = current_hand.last_match_state(seat)
|
120
|
+
match_state = current_hand.current_match_state(seat)
|
121
|
+
|
122
|
+
if current_hand.next_action && player.seat == current_hand.next_action[:seat]
|
123
|
+
player.take_action!(current_hand.next_action[:action])
|
124
|
+
end
|
125
|
+
|
126
|
+
if !match_state.first_state_of_first_round? && match_state.round > last_match_state.round
|
127
|
+
player.start_new_round!
|
128
|
+
end
|
129
|
+
|
130
|
+
if current_hand.final_turn?
|
131
|
+
player.take_winnings!(
|
132
|
+
current_hand.chip_distribution[seat] + @match_def.game_def.blinds[@seat]
|
133
|
+
)
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
yield turn_number
|
138
|
+
end
|
139
|
+
|
140
|
+
self
|
141
|
+
end
|
142
|
+
|
143
|
+
def current_hand
|
144
|
+
if @hand_number then @data[@hand_number] else nil end
|
145
|
+
end
|
146
|
+
|
147
|
+
def final_hand?
|
148
|
+
if @hand_number then @hand_number >= @data.length - 1 else nil end
|
149
|
+
end
|
150
|
+
|
151
|
+
protected
|
152
|
+
|
153
|
+
def set_chip_distribution!(final_score)
|
154
|
+
@chip_distribution = []
|
155
|
+
final_score.each do |player_name, amount|
|
156
|
+
begin
|
157
|
+
@chip_distribution[@match_def.player_names.index(player_name.to_s)] = amount
|
158
|
+
rescue TypeError
|
159
|
+
raise PlayerNamesDoNotMatch
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
self
|
164
|
+
end
|
165
|
+
|
166
|
+
def set_data!(parsed_action_messages, parsed_hand_results)
|
167
|
+
@data = []
|
168
|
+
parsed_action_messages.data.zip(parsed_hand_results.data).each do |action_messages_by_hand, hand_result|
|
169
|
+
@data << HandData.new(
|
170
|
+
@match_def,
|
171
|
+
action_messages_by_hand,
|
172
|
+
hand_result
|
173
|
+
)
|
174
|
+
end
|
175
|
+
|
176
|
+
self
|
177
|
+
end
|
178
|
+
end
|
@@ -0,0 +1,308 @@
|
|
1
|
+
|
2
|
+
# Spec helper (must include first to track code coverage with SimpleCov)
|
3
|
+
require_relative 'support/spec_helper'
|
4
|
+
|
5
|
+
require 'mocha'
|
6
|
+
|
7
|
+
require 'acpc_dealer'
|
8
|
+
require 'acpc_poker_types/match_state'
|
9
|
+
require 'acpc_poker_types/poker_action'
|
10
|
+
|
11
|
+
require_relative '../lib/acpc_dealer_data/action_messages'
|
12
|
+
require_relative '../lib/acpc_dealer_data/match_definition'
|
13
|
+
|
14
|
+
describe ActionMessages do
|
15
|
+
before do
|
16
|
+
@data = nil
|
17
|
+
@final_score = nil
|
18
|
+
@patient = nil
|
19
|
+
@match_def = nil
|
20
|
+
@player_names = nil
|
21
|
+
end
|
22
|
+
|
23
|
+
describe '::parse_to_message' do
|
24
|
+
it 'properly parses a ACPC log "TO . . ." line' do
|
25
|
+
[
|
26
|
+
"TO 1 at 1341695999.222281 MATCHSTATE:0:0::5d5c|\n" =>
|
27
|
+
{seat: 0, state: MatchState.parse('MATCHSTATE:0:0::5d5c|')},
|
28
|
+
"TO 2 at 1341695920.914907 MATCHSTATE:1:0:r19686:|9hQd\n" =>
|
29
|
+
{seat: 1, state: MatchState.parse('MATCHSTATE:1:0:r19686:|9hQd')},
|
30
|
+
"TO 3 at 1341696044.566738 MATCHSTATE:2:0:rf:||8dAs\n" =>
|
31
|
+
{seat: 2, state: MatchState.parse('MATCHSTATE:2:0:rf:||8dAs')},
|
32
|
+
"TO 1 at 1341715418.808925 MATCHSTATE:0:0:fcr17162:5d5c||\n" =>
|
33
|
+
{seat: 0, state: MatchState.parse('MATCHSTATE:0:0:fcr17162:5d5c||')}
|
34
|
+
].each do |to_message_to_data|
|
35
|
+
to_message_to_data.each do |to_message, expected_values|
|
36
|
+
ActionMessages.parse_to_message(to_message).must_equal expected_values
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
it 'returns nil if asked to parse an improperly formatted string' do
|
41
|
+
ActionMessages.parse_to_message("improperly formatted string").must_be_nil
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe '::parse_from_message' do
|
46
|
+
it 'properly parses a ACPC log "FROM . . ." line' do
|
47
|
+
[
|
48
|
+
"FROM 2 at 1341695999.222410 MATCHSTATE:1:0::|9hQd:c\n" =>
|
49
|
+
{
|
50
|
+
seat: 1,
|
51
|
+
state: MatchState.parse('MATCHSTATE:1:0::|9hQd'),
|
52
|
+
action: PokerAction.new('c')
|
53
|
+
},
|
54
|
+
"FROM 1 at 1341695920.914935 MATCHSTATE:0:0:r19686:5d5c|:r20000\n" =>
|
55
|
+
{
|
56
|
+
seat: 0,
|
57
|
+
state: MatchState.parse('MATCHSTATE:0:0:r19686:5d5c|'),
|
58
|
+
action: PokerAction.new('r20000')
|
59
|
+
},
|
60
|
+
"FROM 3 at 1341696044.566938 MATCHSTATE:2:0:rfr:||8dAs:r\n" =>
|
61
|
+
{
|
62
|
+
seat: 2,
|
63
|
+
state: MatchState.parse('MATCHSTATE:2:0:rfr:||8dAs'),
|
64
|
+
action: PokerAction.new('r')
|
65
|
+
},
|
66
|
+
"FROM 2 at 1341715418.808896 MATCHSTATE:1:0:fc:|9hQd|:r17162\n" =>
|
67
|
+
{
|
68
|
+
seat: 1,
|
69
|
+
state: MatchState.parse('MATCHSTATE:1:0:fc:|9hQd|'),
|
70
|
+
action: PokerAction.new('r17162')
|
71
|
+
}
|
72
|
+
].each do |from_message_to_data|
|
73
|
+
from_message_to_data.each do |from_message, expected_values|
|
74
|
+
ActionMessages.parse_from_message(from_message).must_equal expected_values
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
it 'returns nil if asked to parse an improperly formatted string' do
|
79
|
+
ActionMessages.parse_from_message("improperly formatted string").must_be_nil
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
describe '::parse_score' do
|
84
|
+
it 'properly parses a ACPC log "SCORE. . ." line' do
|
85
|
+
[
|
86
|
+
"SCORE:100|-100:p1|p2\n" => {p1: 100, p2: -100},
|
87
|
+
'SCORE:19835|621.5|-20455.5:p1|p2|p3' => {p1: 19835, p2: 621.5, p3: -20455.5}
|
88
|
+
].each do |score_to_player_results|
|
89
|
+
score_to_player_results.each do |score_string, expected_values|
|
90
|
+
ActionMessages.parse_score(score_string).must_equal expected_values
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
it 'returns nil if asked to parse an improperly formatted string' do
|
95
|
+
ActionMessages.parse_score("improperly formatted string").must_be_nil
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
describe 'properly parses ACPC log statements' do
|
100
|
+
it 'from file' do
|
101
|
+
skip "Not sure how to test this easily when GameDefinition needs to open a file as well"
|
102
|
+
|
103
|
+
init_data do |action_messages|
|
104
|
+
file_name = 'file_name'
|
105
|
+
File.expects(:open).with(file_name, 'r').yields(
|
106
|
+
action_messages
|
107
|
+
).returns(
|
108
|
+
ActionMessages.parse(
|
109
|
+
action_messages,
|
110
|
+
@player_names,
|
111
|
+
AcpcDealer::DEALER_DIRECTORY
|
112
|
+
)
|
113
|
+
)
|
114
|
+
|
115
|
+
@patient = ActionMessages.parse_file(
|
116
|
+
file_name,
|
117
|
+
@player_names,
|
118
|
+
AcpcDealer::DEALER_DIRECTORY
|
119
|
+
)
|
120
|
+
|
121
|
+
check_patient
|
122
|
+
end
|
123
|
+
end
|
124
|
+
it 'from array' do
|
125
|
+
init_data do |action_messages|
|
126
|
+
@patient = ActionMessages.parse(
|
127
|
+
action_messages,
|
128
|
+
@player_names,
|
129
|
+
AcpcDealer::DEALER_DIRECTORY
|
130
|
+
)
|
131
|
+
|
132
|
+
check_patient
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def check_patient
|
138
|
+
@patient.data.must_equal @data
|
139
|
+
@patient.final_score.must_equal @final_score
|
140
|
+
@patient.match_def.must_equal @match_def
|
141
|
+
end
|
142
|
+
|
143
|
+
def init_data
|
144
|
+
all_data.each do |game, data_hash|
|
145
|
+
@final_score = data_hash[:final_score]
|
146
|
+
@data = data_hash[:data]
|
147
|
+
@player_names = data_hash[:player_names]
|
148
|
+
@match_def = MatchDefinition.parse(
|
149
|
+
data_hash[:action_messages].first,
|
150
|
+
@player_names,
|
151
|
+
AcpcDealer::DEALER_DIRECTORY
|
152
|
+
)
|
153
|
+
|
154
|
+
yield data_hash[:action_messages]
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
def all_data
|
159
|
+
{
|
160
|
+
two_player_limit: {
|
161
|
+
action_messages: [
|
162
|
+
"# name/game/hands/seed 2p.limit.h1000.r0 holdem.limit.2p.reverse_blinds.game 1000 0\n",
|
163
|
+
"TO 1 at 1341696000.058613 MATCHSTATE:1:998:crc/cc/cc/:|TdQd/As6d6h/7h/4s\n",
|
164
|
+
"TO 2 at 1341696000.058634 MATCHSTATE:0:998:crc/cc/cc/:Jc8d|/As6d6h/7h/4s\n",
|
165
|
+
"FROM 2 at 1341696000.058641 MATCHSTATE:0:998:crc/cc/cc/:Jc8d|/As6d6h/7h/4s:r\n",
|
166
|
+
"TO 1 at 1341696000.058664 MATCHSTATE:1:999:crc/cc/cc/r:|TdQd/As6d6h/7h/4s\n",
|
167
|
+
"TO 2 at 1341696000.058681 MATCHSTATE:0:999:crc/cc/cc/r:Jc8d|/As6d6h/7h/4s\n",
|
168
|
+
"FROM 1 at 1341696000.058688 MATCHSTATE:1:999:crc/cc/cc/r:|TdQd/As6d6h/7h/4s:c\n",
|
169
|
+
"TO 1 at 1341696000.058712 MATCHSTATE:1:999:crc/cc/cc/rc:Jc8d|TdQd/As6d6h/7h/4s\n",
|
170
|
+
"TO 2 at 1341696000.058732 MATCHSTATE:0:999:crc/cc/cc/rc:Jc8d|TdQd/As6d6h/7h/4s\n",
|
171
|
+
"FINISHED at 1341696000.058664\n",
|
172
|
+
'SCORE:455|-455:p1|p2'
|
173
|
+
],
|
174
|
+
data: [
|
175
|
+
[
|
176
|
+
{seat: 0, state: MatchState.parse('MATCHSTATE:1:998:crc/cc/cc/:|TdQd/As6d6h/7h/4s')},
|
177
|
+
{seat: 1, state: MatchState.parse('MATCHSTATE:0:998:crc/cc/cc/:Jc8d|/As6d6h/7h/4s')},
|
178
|
+
{
|
179
|
+
seat: 1,
|
180
|
+
state: MatchState.parse('MATCHSTATE:0:998:crc/cc/cc/:Jc8d|/As6d6h/7h/4s'),
|
181
|
+
action: PokerAction.new('r')
|
182
|
+
}
|
183
|
+
],
|
184
|
+
[
|
185
|
+
{seat: 0, state: MatchState.parse('MATCHSTATE:1:999:crc/cc/cc/r:|TdQd/As6d6h/7h/4s')},
|
186
|
+
{seat: 1, state: MatchState.parse('MATCHSTATE:0:999:crc/cc/cc/r:Jc8d|/As6d6h/7h/4s')},
|
187
|
+
{
|
188
|
+
seat: 0,
|
189
|
+
state: MatchState.parse('MATCHSTATE:1:999:crc/cc/cc/r:|TdQd/As6d6h/7h/4s'),
|
190
|
+
action: PokerAction.new('c')
|
191
|
+
},
|
192
|
+
{seat: 0, state: MatchState.parse('MATCHSTATE:1:999:crc/cc/cc/rc:Jc8d|TdQd/As6d6h/7h/4s')},
|
193
|
+
{seat: 1, state: MatchState.parse('MATCHSTATE:0:999:crc/cc/cc/rc:Jc8d|TdQd/As6d6h/7h/4s')}
|
194
|
+
]
|
195
|
+
],
|
196
|
+
final_score: {p1: 455, p2: -455},
|
197
|
+
player_names: ['p1', 'p2']
|
198
|
+
},
|
199
|
+
two_player_nolimit: {
|
200
|
+
action_messages: [
|
201
|
+
"# name/game/hands/seed 2p.nolimit.h1000.r0 holdem.nolimit.2p.reverse_blinds.game 1000 0\n",
|
202
|
+
"TO 1 at 1341695921.617099 MATCHSTATE:0:998:cc/r5841r19996r20000:Kc6h|/QhAh8d\n",
|
203
|
+
"TO 2 at 1341695921.617126 MATCHSTATE:1:998:cc/r5841r19996r20000:|Qc3s/QhAh8d\n",
|
204
|
+
"FROM 2 at 1341695921.617133 MATCHSTATE:1:998:cc/r5841r19996r20000:|Qc3s/QhAh8d:c\n",
|
205
|
+
"TO 1 at 1341695921.617182 MATCHSTATE:0:998:cc/r5841r19996r20000c//:Kc6h|Qc3s/QhAh8d/Th/9d\n",
|
206
|
+
"TO 2 at 1341695921.617224 MATCHSTATE:1:998:cc/r5841r19996r20000c//:Kc6h|Qc3s/QhAh8d/Th/9d\n",
|
207
|
+
"TO 1 at 1341695921.617268 MATCHSTATE:1:999::|TdQd\n",
|
208
|
+
"TO 2 at 1341695921.617309 MATCHSTATE:0:999::Jc8d|\n",
|
209
|
+
"FROM 1 at 1341695921.617324 MATCHSTATE:1:999::|TdQd:f\n",
|
210
|
+
"TO 1 at 1341695921.617377 MATCHSTATE:1:999:f:|TdQd\n",
|
211
|
+
"TO 2 at 1341695921.617415 MATCHSTATE:0:999:f:Jc8d|\n",
|
212
|
+
"FINISHED at 1341695921.617268\n",
|
213
|
+
"SCORE:-64658|64658:p1|p2"
|
214
|
+
],
|
215
|
+
data: [
|
216
|
+
[
|
217
|
+
{seat: 0, state: MatchState.parse('MATCHSTATE:0:998:cc/r5841r19996r20000:Kc6h|/QhAh8d')},
|
218
|
+
{seat: 1, state: MatchState.parse('MATCHSTATE:1:998:cc/r5841r19996r20000:|Qc3s/QhAh8d')},
|
219
|
+
{
|
220
|
+
seat: 1,
|
221
|
+
state: MatchState.parse('MATCHSTATE:1:998:cc/r5841r19996r20000:|Qc3s/QhAh8d:c'),
|
222
|
+
action: PokerAction.new('c')
|
223
|
+
},
|
224
|
+
{seat: 0, state: MatchState.parse('MATCHSTATE:0:998:cc/r5841r19996r20000c//:Kc6h|Qc3s/QhAh8d/Th/9d')},
|
225
|
+
{seat: 1, state: MatchState.parse('MATCHSTATE:1:998:cc/r5841r19996r20000c//:Kc6h|Qc3s/QhAh8d/Th/9d')}
|
226
|
+
],
|
227
|
+
[
|
228
|
+
{seat: 0, state: MatchState.parse('MATCHSTATE:1:999::|TdQd')},
|
229
|
+
{seat: 1, state: MatchState.parse('MATCHSTATE:0:999::Jc8d|')},
|
230
|
+
{
|
231
|
+
seat: 0,
|
232
|
+
state: MatchState.parse('MATCHSTATE:1:999::|TdQd'),
|
233
|
+
action: PokerAction.new('f')
|
234
|
+
},
|
235
|
+
{seat: 0, state: MatchState.parse('MATCHSTATE:1:999:f:|TdQd')},
|
236
|
+
{seat: 1, state: MatchState.parse('MATCHSTATE:0:999:f:Jc8d|')}
|
237
|
+
]
|
238
|
+
],
|
239
|
+
final_score: {p1: -64658, p2: 64658},
|
240
|
+
player_names: ['p1', 'p2']
|
241
|
+
},
|
242
|
+
three_player_limit: {
|
243
|
+
action_messages: [
|
244
|
+
"# name/game/hands/seed 3p.limit.h1000.r0 holdem.limit.3p.game 1000 0\n",
|
245
|
+
"TO 1 at 1341696046.871086 MATCHSTATE:0:999:ccc/ccc/rrcc/rrrfr:QsAs||/4d6d2d/5d/2c\n",
|
246
|
+
"TO 2 at 1341696046.871128 MATCHSTATE:1:999:ccc/ccc/rrcc/rrrfr:|3s8h|/4d6d2d/5d/2c\n",
|
247
|
+
"TO 3 at 1341696046.871175 MATCHSTATE:2:999:ccc/ccc/rrcc/rrrfr:||Qd3c/4d6d2d/5d/2c\n",
|
248
|
+
"FROM 3 at 1341696046.871201 MATCHSTATE:2:999:ccc/ccc/rrcc/rrrfr:||Qd3c/4d6d2d/5d/2c:c\n",
|
249
|
+
"TO 1 at 1341696046.871245 MATCHSTATE:0:999:ccc/ccc/rrcc/rrrfrc:QsAs|3s8h|Qd3c/4d6d2d/5d/2c\n",
|
250
|
+
"TO 2 at 1341696046.871267 MATCHSTATE:1:999:ccc/ccc/rrcc/rrrfrc:|3s8h|Qd3c/4d6d2d/5d/2c\n",
|
251
|
+
"TO 3 at 1341696046.871313 MATCHSTATE:2:999:ccc/ccc/rrcc/rrrfrc:|3s8h|Qd3c/4d6d2d/5d/2c\n",
|
252
|
+
"FINISHED at 1341696046.871175\n",
|
253
|
+
"SCORE:-4330|625|3705:p1|p2|p3"
|
254
|
+
],
|
255
|
+
data: [
|
256
|
+
[
|
257
|
+
{seat: 0, state: MatchState.parse('MATCHSTATE:0:999:ccc/ccc/rrcc/rrrfr:QsAs||/4d6d2d/5d/2c')},
|
258
|
+
{seat: 1, state: MatchState.parse('MATCHSTATE:1:999:ccc/ccc/rrcc/rrrfr:|3s8h|/4d6d2d/5d/2c')},
|
259
|
+
{seat: 2, state: MatchState.parse('MATCHSTATE:2:999:ccc/ccc/rrcc/rrrfr:||Qd3c/4d6d2d/5d/2c')},
|
260
|
+
{
|
261
|
+
seat: 2,
|
262
|
+
state: MatchState.parse('MATCHSTATE:2:999:ccc/ccc/rrcc/rrrfr:||Qd3c/4d6d2d/5d/2c'),
|
263
|
+
action: PokerAction.new('c')
|
264
|
+
},
|
265
|
+
{seat: 0, state: MatchState.parse('MATCHSTATE:0:999:ccc/ccc/rrcc/rrrfrc:QsAs|3s8h|Qd3c/4d6d2d/5d/2c')},
|
266
|
+
{seat: 1, state: MatchState.parse('MATCHSTATE:1:999:ccc/ccc/rrcc/rrrfrc:|3s8h|Qd3c/4d6d2d/5d/2c')},
|
267
|
+
{seat: 2, state: MatchState.parse('MATCHSTATE:2:999:ccc/ccc/rrcc/rrrfrc:|3s8h|Qd3c/4d6d2d/5d/2c')}
|
268
|
+
]
|
269
|
+
],
|
270
|
+
final_score: {p1: -4330, p2: 625, p3: 3705},
|
271
|
+
player_names: ['p1', 'p2', 'p3']
|
272
|
+
},
|
273
|
+
three_player_nolimit: {
|
274
|
+
action_messages: [
|
275
|
+
"# name/game/hands/seed 3p.nolimit.h1000.r0 holdem.nolimit.3p.game 1000 0\n",
|
276
|
+
"TO 1 at 1341715420.129997 MATCHSTATE:0:998:ccr12926r20000c:QsAs||\n",
|
277
|
+
"TO 2 at 1341715420.130034 MATCHSTATE:1:998:ccr12926r20000c:|3s8h|\n",
|
278
|
+
"TO 3 at 1341715420.130070 MATCHSTATE:2:998:ccr12926r20000c:||Qd3c\n",
|
279
|
+
"FROM 2 at 1341715420.130093 MATCHSTATE:1:998:ccr12926r20000c:|3s8h|:c\n",
|
280
|
+
"TO 1 at 1341715420.130156 MATCHSTATE:0:999:ccr12926r20000cc///:QsAs|3s8h|Qd3c/4d6d2d/5d/2c\n",
|
281
|
+
"TO 2 at 1341715420.130191 MATCHSTATE:1:999:ccr12926r20000cc///:QsAs|3s8h|Qd3c/4d6d2d/5d/2c\n",
|
282
|
+
"TO 3 at 1341715420.130225 MATCHSTATE:2:999:ccr12926r20000cc///:QsAs|3s8h|Qd3c/4d6d2d/5d/2c\n",
|
283
|
+
"FINISHED at 1341715420.130034\n",
|
284
|
+
"SCORE:684452|552584.5|-1237036.5:p1|p2|p3"
|
285
|
+
],
|
286
|
+
data: [
|
287
|
+
[
|
288
|
+
{seat: 0, state: MatchState.parse('MATCHSTATE:0:998:ccr12926r20000c:QsAs||')},
|
289
|
+
{seat: 1, state: MatchState.parse('MATCHSTATE:1:998:ccr12926r20000c:|3s8h|')},
|
290
|
+
{seat: 2, state: MatchState.parse('MATCHSTATE:2:998:ccr12926r20000c:||Qd3c')},
|
291
|
+
{
|
292
|
+
seat: 1,
|
293
|
+
state: MatchState.parse('MATCHSTATE:1:998:ccr12926r20000c:|3s8h|'),
|
294
|
+
action: PokerAction.new('c')
|
295
|
+
}
|
296
|
+
],
|
297
|
+
[
|
298
|
+
{seat: 0, state: MatchState.parse('MATCHSTATE:0:999:ccr12926r20000cc///:QsAs|3s8h|Qd3c/4d6d2d/5d/2c')},
|
299
|
+
{seat: 1, state: MatchState.parse('MATCHSTATE:1:999:ccr12926r20000cc///:QsAs|3s8h|Qd3c/4d6d2d/5d/2c')},
|
300
|
+
{seat: 2, state: MatchState.parse('MATCHSTATE:2:999:ccr12926r20000cc///:QsAs|3s8h|Qd3c/4d6d2d/5d/2c')}
|
301
|
+
]
|
302
|
+
],
|
303
|
+
final_score: {p1: 684452, p2: 552584.5, p3: -1237036.5},
|
304
|
+
player_names: ['p1', 'p2', 'p3']
|
305
|
+
}
|
306
|
+
}
|
307
|
+
end
|
308
|
+
end
|