acpc_dealer_data 0.0.1
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.
- 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
|