acpc_dealer 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (99) hide show
  1. data/README.md +33 -0
  2. data/Rakefile +20 -0
  3. data/acpc_dealer.gemspec +29 -0
  4. data/bin/acpc_dealer +168 -0
  5. data/ext/hand_evaluator/extconf.rb +5 -0
  6. data/ext/hand_evaluator/hand_evaluator.c +38 -0
  7. data/lib/acpc_dealer/2p.limit.h5.r0.logs/2p.limit.h5.r0.actions.log +5 -0
  8. data/lib/acpc_dealer/2p.limit.h5.r0.logs/2p.limit.h5.r0.log +0 -0
  9. data/lib/acpc_dealer/dealer_runner.rb +72 -0
  10. data/lib/acpc_dealer/version.rb +3 -0
  11. data/lib/acpc_dealer.rb +33 -0
  12. data/lib/hand_evaluator.so +0 -0
  13. data/spec/coverage/assets/0.5.3/app.js +88 -0
  14. data/spec/coverage/assets/0.5.3/fancybox/blank.gif +0 -0
  15. data/spec/coverage/assets/0.5.3/fancybox/fancy_close.png +0 -0
  16. data/spec/coverage/assets/0.5.3/fancybox/fancy_loading.png +0 -0
  17. data/spec/coverage/assets/0.5.3/fancybox/fancy_nav_left.png +0 -0
  18. data/spec/coverage/assets/0.5.3/fancybox/fancy_nav_right.png +0 -0
  19. data/spec/coverage/assets/0.5.3/fancybox/fancy_shadow_e.png +0 -0
  20. data/spec/coverage/assets/0.5.3/fancybox/fancy_shadow_n.png +0 -0
  21. data/spec/coverage/assets/0.5.3/fancybox/fancy_shadow_ne.png +0 -0
  22. data/spec/coverage/assets/0.5.3/fancybox/fancy_shadow_nw.png +0 -0
  23. data/spec/coverage/assets/0.5.3/fancybox/fancy_shadow_s.png +0 -0
  24. data/spec/coverage/assets/0.5.3/fancybox/fancy_shadow_se.png +0 -0
  25. data/spec/coverage/assets/0.5.3/fancybox/fancy_shadow_sw.png +0 -0
  26. data/spec/coverage/assets/0.5.3/fancybox/fancy_shadow_w.png +0 -0
  27. data/spec/coverage/assets/0.5.3/fancybox/fancy_title_left.png +0 -0
  28. data/spec/coverage/assets/0.5.3/fancybox/fancy_title_main.png +0 -0
  29. data/spec/coverage/assets/0.5.3/fancybox/fancy_title_over.png +0 -0
  30. data/spec/coverage/assets/0.5.3/fancybox/fancy_title_right.png +0 -0
  31. data/spec/coverage/assets/0.5.3/fancybox/fancybox-x.png +0 -0
  32. data/spec/coverage/assets/0.5.3/fancybox/fancybox-y.png +0 -0
  33. data/spec/coverage/assets/0.5.3/fancybox/fancybox.png +0 -0
  34. data/spec/coverage/assets/0.5.3/fancybox/jquery.fancybox-1.3.1.css +363 -0
  35. data/spec/coverage/assets/0.5.3/fancybox/jquery.fancybox-1.3.1.pack.js +44 -0
  36. data/spec/coverage/assets/0.5.3/favicon_green.png +0 -0
  37. data/spec/coverage/assets/0.5.3/favicon_red.png +0 -0
  38. data/spec/coverage/assets/0.5.3/favicon_yellow.png +0 -0
  39. data/spec/coverage/assets/0.5.3/highlight.css +129 -0
  40. data/spec/coverage/assets/0.5.3/highlight.pack.js +1 -0
  41. data/spec/coverage/assets/0.5.3/jquery-1.6.2.min.js +18 -0
  42. data/spec/coverage/assets/0.5.3/jquery.dataTables.min.js +152 -0
  43. data/spec/coverage/assets/0.5.3/jquery.timeago.js +141 -0
  44. data/spec/coverage/assets/0.5.3/jquery.url.js +174 -0
  45. data/spec/coverage/assets/0.5.3/loading.gif +0 -0
  46. data/spec/coverage/assets/0.5.3/magnify.png +0 -0
  47. data/spec/coverage/assets/0.5.3/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
  48. data/spec/coverage/assets/0.5.3/smoothness/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
  49. data/spec/coverage/assets/0.5.3/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
  50. data/spec/coverage/assets/0.5.3/smoothness/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
  51. data/spec/coverage/assets/0.5.3/smoothness/images/ui-bg_glass_75_dadada_1x400.png +0 -0
  52. data/spec/coverage/assets/0.5.3/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
  53. data/spec/coverage/assets/0.5.3/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
  54. data/spec/coverage/assets/0.5.3/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
  55. data/spec/coverage/assets/0.5.3/smoothness/images/ui-icons_222222_256x240.png +0 -0
  56. data/spec/coverage/assets/0.5.3/smoothness/images/ui-icons_2e83ff_256x240.png +0 -0
  57. data/spec/coverage/assets/0.5.3/smoothness/images/ui-icons_454545_256x240.png +0 -0
  58. data/spec/coverage/assets/0.5.3/smoothness/images/ui-icons_888888_256x240.png +0 -0
  59. data/spec/coverage/assets/0.5.3/smoothness/images/ui-icons_cd0a0a_256x240.png +0 -0
  60. data/spec/coverage/assets/0.5.3/smoothness/jquery-ui-1.8.4.custom.css +295 -0
  61. data/spec/coverage/assets/0.5.3/stylesheet.css +383 -0
  62. data/spec/coverage/index.html +81 -0
  63. data/spec/dealer_runner_spec.rb +83 -0
  64. data/spec/support/spec_helper.rb +33 -0
  65. data/vendor/project_acpc_server/LICENCE +23 -0
  66. data/vendor/project_acpc_server/Makefile +22 -0
  67. data/vendor/project_acpc_server/README +113 -0
  68. data/vendor/project_acpc_server/README.submission +42 -0
  69. data/vendor/project_acpc_server/acpc_play_match.pl +101 -0
  70. data/vendor/project_acpc_server/bm_server +0 -0
  71. data/vendor/project_acpc_server/bm_server.c +1557 -0
  72. data/vendor/project_acpc_server/bm_server.config +78 -0
  73. data/vendor/project_acpc_server/bm_widget +0 -0
  74. data/vendor/project_acpc_server/bm_widget.c +186 -0
  75. data/vendor/project_acpc_server/dealer +0 -0
  76. data/vendor/project_acpc_server/dealer.c +1278 -0
  77. data/vendor/project_acpc_server/evalHandTables +4269 -0
  78. data/vendor/project_acpc_server/example_player +0 -0
  79. data/vendor/project_acpc_server/example_player.c +204 -0
  80. data/vendor/project_acpc_server/example_player.limit.2p.sh +2 -0
  81. data/vendor/project_acpc_server/example_player.limit.3p.sh +2 -0
  82. data/vendor/project_acpc_server/example_player.nolimit.2p.sh +2 -0
  83. data/vendor/project_acpc_server/example_player.nolimit.3p.sh +2 -0
  84. data/vendor/project_acpc_server/game.c +1793 -0
  85. data/vendor/project_acpc_server/game.h +253 -0
  86. data/vendor/project_acpc_server/holdem.limit.2p.reverse_blinds.game +13 -0
  87. data/vendor/project_acpc_server/holdem.limit.3p.game +13 -0
  88. data/vendor/project_acpc_server/holdem.nolimit.2p.reverse_blinds.game +12 -0
  89. data/vendor/project_acpc_server/holdem.nolimit.3p.game +12 -0
  90. data/vendor/project_acpc_server/net.c +218 -0
  91. data/vendor/project_acpc_server/net.h +61 -0
  92. data/vendor/project_acpc_server/play_match.pl +99 -0
  93. data/vendor/project_acpc_server/protocol.odt +0 -0
  94. data/vendor/project_acpc_server/protocol.pdf +0 -0
  95. data/vendor/project_acpc_server/rng.c +138 -0
  96. data/vendor/project_acpc_server/rng.h +63 -0
  97. data/vendor/project_acpc_server/test.log +11 -0
  98. data/vendor/project_acpc_server/validate_submission.pl +546 -0
  99. metadata +315 -0
@@ -0,0 +1,546 @@
1
+ #!/usr/bin/perl -w
2
+
3
+ # Copyright (C) 2011 by the Computer Poker Research Group, University of Alberta
4
+
5
+ use strict;
6
+
7
+ use POSIX;
8
+ use File::Path;
9
+ use File::Copy;
10
+ use File::Spec;
11
+ use File::stat;
12
+ use Getopt::Long;
13
+ use Pod::Usage;
14
+
15
+ ###############
16
+ # Main script #
17
+ ###############
18
+
19
+ # There are several variables that should be set here by the competition
20
+ # organizer specifying what minimum length of testing is desired
21
+
22
+ my $max_submission_size = 50 * ( 1024 ** 3 ); # 50Gb of disk
23
+ my $max_avg_millisec_per_hand = 7 * 1000; # 7 sec average per hand
24
+ my $max_response_millisec = 10 * 60 * 1000; #10 minute max per response
25
+ my $max_millisec_per_hand = $max_avg_millisec_per_hand * 3000; # Unconstrained
26
+ my $max_shutdown_secs = 10; # Agents have 10 seconds to shutdown after a match
27
+ my $min_test_hands = 12000;
28
+ my $num_test_hands = 12000;
29
+
30
+ my %game_types = (
31
+ "submission_2pl" => {
32
+ game_def => "holdem.limit.2p.reverse_blinds.game",
33
+ chump => "example_player.limit.2p.sh",
34
+ num_hands => 3000,
35
+ big_blind => 10,
36
+ players => 2
37
+ },
38
+ "submission_2pn" => {
39
+ game_def => "holdem.nolimit.2p.reverse_blinds.game",
40
+ chump => "example_player.nolimit.2p.sh",
41
+ num_hands => 3000,
42
+ big_blind => 100,
43
+ players => 2
44
+ },
45
+ "submission_3pl" => {
46
+ game_def => "holdem.limit.3p.game",
47
+ chump => "example_player.limit.3p.sh",
48
+ num_hands => 1000,
49
+ big_blind => 10,
50
+ players => 3
51
+ }
52
+ # For the possibility of future 3p_nolimit games
53
+ # "3p_nolimit" => {
54
+ # gamedef => "holdem.nolimit.3p.game",
55
+ # chump => "example_player.nolimit.3p.sh",
56
+ # num_hands => 1000,
57
+ # big_blind => 100,
58
+ # players => 3
59
+ # }
60
+ );
61
+
62
+ my $man;
63
+ my $help;
64
+
65
+ # Parse command line arguments
66
+ GetOptions( 'help' => \$help, 'man' => \$man,
67
+ 'num_hands=i' => \$num_test_hands )
68
+ or pod2usage( -exitstatus => 2,
69
+ -message => "Invalid arguments.\n" .
70
+ "Use --help or --man for detailed usage." );
71
+
72
+ pod2usage( -verbose => 1 ) if( $help );
73
+ pod2usage( -verbose => 2 ) if( $man );
74
+ $#ARGV >= 0
75
+ or pod2usage( -exitstatus => 2,
76
+ -message => "Insufficient arguments.\n" .
77
+ "Use --help or --man for detailed usage." );
78
+
79
+ ( $num_test_hands >= $min_test_hands )
80
+ or die "Must play at least $min_test_hands hands for validation, stopped";
81
+
82
+ # Set up file paths
83
+ my $submission_path = File::Spec->rel2abs( $ARGV[ 0 ] ) ;
84
+ my ( $submission_volume, $submission_dir, $submission_last_comp )
85
+ = File::Spec->splitpath( $submission_path );
86
+
87
+ my $validation_dir = "$submission_path.validation";
88
+ my $validation_path
89
+ = File::Spec->catfile( $validation_dir, "$submission_last_comp.validation" );
90
+
91
+ # XXX: Script relies on its relative position with the rest of the code. This
92
+ # isn't great, but avoids other configuration files specifying this
93
+ my ( $volume, $directories, $test_script_file )
94
+ = File::Spec->splitpath( File::Spec->rel2abs( $0 ) );
95
+ my $scripts_dir = File::Spec->catpath( $volume, $directories, '' );
96
+ my $server_dir = File::Spec->catpath( $volume, $directories, '' );
97
+ my $test_script_path = File::Spec->catfile( $scripts_dir, $test_script_file );
98
+ my $dealer_path = File::Spec->catfile( $server_dir, "dealer" );
99
+ my $example_player_path = File::Spec->catfile( $server_dir, "example_player" );
100
+ my $play_match_path = File::Spec->catfile( $server_dir, "acpc_play_match.pl" );
101
+
102
+ # Ensure we aren't overwriting an existing validation file
103
+ ( ! -e $validation_dir )
104
+ or die "ERROR: $validation_dir already exists. Move/remove it and rerun\n";
105
+
106
+ mkpath( $validation_dir );
107
+
108
+ # Open the validation file for writing
109
+ my $VALIDATION;
110
+ open( $VALIDATION, '>', $validation_path )
111
+ or die "ERROR: Cannot open validation file $validation_path" .
112
+ "for writing: $!\n";
113
+
114
+ # Begin validation tests
115
+ print $VALIDATION "Validating $submission_path\n\n";
116
+ print "Validating $submission_path\n";
117
+ print "Validation files will be placed in $validation_dir\n";
118
+ print "Matches in progress will have output in $server_dir\n";
119
+ print "Check $validation_path for more detailed progress or errors\n\n";
120
+
121
+ # Test the versions of the files using checksums
122
+ print $VALIDATION "Gathering file versions (md5sums)...\n\n";
123
+
124
+ # Ensure the testing script is the right version
125
+ my $test_script_version_cmd = "md5sum $test_script_path";
126
+ print $VALIDATION "Testing script: $test_script_path\n";
127
+ print $VALIDATION "$test_script_version_cmd\n";
128
+
129
+ my $test_script_version_output = `$test_script_version_cmd 2>&1`;
130
+ print $VALIDATION "$test_script_version_output\n";
131
+ if( $? != 0 ) {
132
+ print $VALIDATION "FAILED.\n";
133
+ print $VALIDATION "Validation FAILED.\n";
134
+ die "$test_script_version_cmd\n$test_script_version_output\n" .
135
+ "ERROR: Unable to verify testing script version, stopped";
136
+ }
137
+
138
+ # Verify the version of the dealer program
139
+ my $dealer_version_cmd = "md5sum $dealer_path";
140
+ print $VALIDATION "dealer: $dealer_path\n";
141
+ print $VALIDATION "$dealer_version_cmd\n";
142
+
143
+ my $dealer_version_output = `$dealer_version_cmd 2>&1`;
144
+ print $VALIDATION "$dealer_version_output\n";
145
+ if( $? != 0 ) {
146
+ print $VALIDATION "FAILED.\n";
147
+ print $VALIDATION "Validation FAILED.\n";
148
+ die "$dealer_version_cmd\n$dealer_version_output\n" .
149
+ "ERROR: Unable to verify dealer version, stopped";
150
+ }
151
+
152
+ # Verify the version of the example_player program
153
+ my $example_player_version_cmd = "md5sum $example_player_path";
154
+ print $VALIDATION "example_player: $example_player_path\n";
155
+ print $VALIDATION "$example_player_version_cmd\n";
156
+
157
+ my $example_player_version_output = `$example_player_version_cmd 2>&1`;
158
+ print $VALIDATION "$example_player_version_output\n";
159
+ if( $? != 0 ) {
160
+ print $VALIDATION "FAILED.\n";
161
+ print $VALIDATION "Validation FAILED.\n";
162
+ die "$example_player_version_cmd\n$example_player_version_output\n" .
163
+ "ERROR: Unable to verify example_player version, stopped";
164
+ }
165
+
166
+ # Verify the version of the play_match program
167
+ my $play_match_version_cmd = "md5sum $play_match_path";
168
+ print $VALIDATION "play_match: $play_match_path\n";
169
+ print $VALIDATION "$play_match_version_cmd\n";
170
+
171
+ my $play_match_version_output = `$play_match_version_cmd 2>&1`;
172
+ print $VALIDATION "$play_match_version_output\n";
173
+ if( $? != 0 ) {
174
+ print $VALIDATION "FAILED.\n";
175
+ print $VALIDATION "Validation FAILED.\n";
176
+ die "$play_match_version_cmd\n$play_match_version_output\n" .
177
+ "ERROR: Unable to verify play_match.pl version, stopped";
178
+ }
179
+
180
+ # Test for what kind of submission it is (i.e., which game)
181
+ my $game_label = undef;
182
+ print $VALIDATION "Checking for game label... ";
183
+ foreach my $game ( keys( %game_types ) ) {
184
+ if( $submission_last_comp eq $game ) {
185
+ $game_label = $game;
186
+ print $VALIDATION "PASSED. Found $game_label\n\n";
187
+ last;
188
+ }
189
+ }
190
+
191
+ if( not defined $game_label ) {
192
+ $, = ", "; # Sets the list printing separator
193
+ print $VALIDATION " FAILED.\n";
194
+ print $VALIDATION "Unrecognized directory name $submission_last_comp\n";
195
+ print $VALIDATION "Submission directory must be one of: ",
196
+ print $VALIDATION keys( %game_types );
197
+ print $VALIDATION "\n";
198
+ print $VALIDATION "Validation FAILED.\n";
199
+ die "ERROR: Unrecognized submission directory name, stopped";
200
+ }
201
+
202
+ my $agent_name;
203
+ if( -d $submission_path ) {
204
+ $agent_name = ( File::Spec->splitdir( $submission_path ) )[ -1 ];
205
+ } else {
206
+ print $VALIDATION "FAILED.\n";
207
+ print $VALIDATION "$submission_path is not a directory.\n";
208
+ print $VALIDATION "Validation FAILED.\n";
209
+ die "ERROR: Expected a directory, stopped";
210
+ }
211
+
212
+ # Check if the directory contains a README file
213
+ print $VALIDATION "Checking for README file... ";
214
+ if( -e File::Spec->catfile( $submission_path, "README" ) ) {
215
+ print $VALIDATION "PASSED.\n\n";
216
+ } else {
217
+ print $VALIDATION "FAILED.\n";
218
+ print $VALIDATION "Validation FAILED.\n";
219
+ die "ERROR: Missing README file, stopped";
220
+ }
221
+
222
+ # Check if the directory contains an executable startme.sh script
223
+ print $VALIDATION "Checking for executable startme.sh script... ";
224
+ my $startme_stat = stat( File::Spec->catfile( $submission_path, "startme.sh" ) );
225
+ if( $startme_stat ) {
226
+ my $mode = $startme_stat->mode;
227
+ my $perm_mask = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
228
+ my $perm_str = sprintf( "%03o", $perm_mask & 00777 );
229
+ # Test if the file has the same permissions as the mask
230
+ if( ( $mode & $perm_mask ) == $perm_mask ) {
231
+ print $VALIDATION "PASSED.\n\n";
232
+ } else {
233
+ print $VALIDATION "FAILED.\n";
234
+ print $VALIDATION "startme.sh must have at least $perm_str permissions\n";
235
+ print $VALIDATION "Validation FAILED.\n";
236
+ die "ERROR: startme.sh must have at least $perm_str permissions, stopped";
237
+ }
238
+ } else {
239
+ print $VALIDATION "FAILED.\n";
240
+ print $VALIDATION "Validation FAILED.\n";
241
+ die "ERROR: Unable to stat startme.sh file: $!, stopped";
242
+ }
243
+
244
+ # Check if the uncompressed size of the agent submission directory is too big
245
+ # NOTE: This isn't done is a very platorm independent way. du does not always
246
+ # have -b available (not to mention other OSes). Should probably just walk the
247
+ # file structure ourselves.
248
+ print $VALIDATION "Checking $submission_path for uncompressed file size... ";
249
+ my $agent_size_cmd = "du -bc $submission_path";
250
+ my @agent_size_output = `$agent_size_cmd 2>&1`;
251
+ # $? is the return value of the backtick command, test it for failure
252
+ if( $? == 0 ) {
253
+ my @fields = split( /\W/, $agent_size_output[ -1 ] );
254
+ my $agent_size = $fields[ 0 ];
255
+ if( $agent_size <= $max_submission_size ) {
256
+ print $VALIDATION "PASSED. ($agent_size bytes)\n\n";
257
+ } else {
258
+ print $VALIDATION "FAILED.\n";
259
+ print $VALIDATION "Validation FAILED.\n";
260
+ die "ERROR: $submission_path is too large, stopped";
261
+ }
262
+ } else {
263
+ $, = ""; # Sets the list printing separator
264
+ print $VALIDATION "FAILED.\n";
265
+ print $VALIDATION "Validation FAILED.\n";
266
+ die "$agent_size_cmd\n@agent_size_output\n" .
267
+ "ERROR: Unable to get agent directory size, stopped";
268
+ }
269
+
270
+ # Run the submitted agent for the specified number of trial hands.
271
+ my $matches_played = 0;
272
+ my $min_matches = ceil( $num_test_hands /
273
+ $game_types{ $game_label }{ num_hands } );
274
+
275
+ my $total_decision_time = 0;
276
+ my $total_score = 0;
277
+
278
+ my $game_def = $game_types{ $game_label }{ game_def };
279
+ my $num_players = $game_types{ $game_label }{ players };
280
+ my $num_hands = $game_types{ $game_label }{ num_hands };
281
+ my $big_blind = $game_types{ $game_label }{ big_blind };
282
+ my $example_player_startme_path
283
+ = File::Spec->catfile( $server_dir, $game_types{ $game_label }{ chump } );
284
+
285
+ print "Running matches...\n";
286
+ # Change directory to the server directory as play_match relies on relative
287
+ # paths from that directory
288
+ chdir( $server_dir ) or die "Unable to chdir to $server_dir: $!, stopped";
289
+ # Play all of the matches needed to at least meet the minimum hand count
290
+ while( $matches_played < $min_matches ) {
291
+ my ( $match_start_time, $match_end_time );
292
+ my $match_name = "$agent_name.test_match.$matches_played";
293
+
294
+ # TODO?: Should the generated shell scripts be used to run the agent
295
+ # If not, then files could be left over or we may not detect issues with
296
+ # using the scripts
297
+
298
+ # Construct the command for running a match
299
+ my $match_cmd = "$play_match_path $match_name $game_def $num_hands " .
300
+ "$matches_played $agent_name $submission_path/startme.sh";
301
+ # Add the remaining players
302
+ for( my $player = 1; $player < $num_players; $player++ ) {
303
+ $match_cmd = $match_cmd . " chump" .
304
+ ( $num_players > 2 ? "-$player" : "" ) . " $example_player_startme_path"
305
+ }
306
+ # Add the server timing options
307
+ $match_cmd = $match_cmd . " --t_per_hand $max_avg_millisec_per_hand " .
308
+ "--t_response $max_response_millisec " .
309
+ "--t_hand $max_millisec_per_hand";
310
+
311
+ # Give some visual output of progress
312
+ print "Match ", $matches_played + 1,
313
+ " of $min_matches: $match_name\n";
314
+ print $VALIDATION "========== Match ", $matches_played + 1,
315
+ " of $min_matches: $match_name ==========\n";
316
+
317
+ # Ensure no other startme.sh script are running prior to the next match
318
+ print $VALIDATION "Checking for existing agents... ";
319
+ my $lingering_agent_cmd = "ps -eo command";
320
+ my @lingering_agent_output = `$lingering_agent_cmd 2>&1`;
321
+ # $? is the return value of the backtick command, test it for failure
322
+ if( $? == 0 ) {
323
+ my @lingering_agents = grep { /startme\.sh/ } @lingering_agent_output;
324
+ if( @lingering_agents == 0 ) {
325
+ print $VALIDATION "PASSED.\n\n";
326
+ } else {
327
+ $, = "\n"; # Sets the list printing separator
328
+ print $VALIDATION "FAILED.\n";
329
+ print $VALIDATION "Found the following existing agents:\n";
330
+ print $VALIDATION @lingering_agents;
331
+ print $VALIDATION "\n";
332
+ print $VALIDATION "Stop other agents before proceeding with testing\n";
333
+ print $VALIDATION "Validation FAILED.\n";
334
+ die "ERROR: lingering startme.sh found before match $match_name, stopped";
335
+ }
336
+ } else {
337
+ $, = ""; # Sets the list printing separator
338
+ print $VALIDATION "FAILED.\n";
339
+ print $VALIDATION "Validation FAILED.\n";
340
+ die "$lingering_agent_cmd\n@lingering_agent_output\n" .
341
+ "ERROR: Unable to get processes to check for lingering agents, stopped";
342
+ }
343
+
344
+ print $VALIDATION "$match_cmd\n\n";
345
+
346
+ # Collect timing statistics for the run.
347
+ $match_start_time = time();
348
+ my $match_output = `$match_cmd 2>&1`;
349
+ $match_end_time = time();
350
+
351
+ # Move any available output files to the $validation_dir
352
+ foreach my $file ( glob( "$server_dir/$match_name*" ) ) {
353
+ move( $file, $validation_dir );
354
+ }
355
+
356
+ chomp( $match_output );
357
+ print $VALIDATION "$match_output\n";
358
+
359
+ if( $? != 0 ) {
360
+ print $VALIDATION "FAILED.\n";
361
+ print $VALIDATION "Validation FAILED.\n";
362
+ die "$match_cmd\n$match_output\n" .
363
+ "ERROR: Match $agent_name.test_match.$matches_played FAILED " .
364
+ "(returned $?).\n" .
365
+ "Check match log files in validation directory for cause, stopped";
366
+ }
367
+
368
+ # Extract the score from the dealer output
369
+ # e.g., SCORE:-1430|1430:2p_limit_foo|chump
370
+ my $scores = ( split( /:/, $match_output ) )[ 1 ];
371
+ $total_score += ( split( /\|/, $scores ) )[ 0 ];
372
+ $matches_played++;
373
+ $total_decision_time += $match_end_time - $match_start_time;
374
+
375
+ # Verify that the agent is shutting down correctly
376
+ print $VALIDATION "Checking for lingering agents... ";
377
+ # Wait a short while to give the agent time to exit after the match
378
+ sleep( $max_shutdown_secs );
379
+ @lingering_agent_output = `$lingering_agent_cmd 2>&1`;
380
+ # $? is the return value of the backtick command, test it for failure
381
+ if( $? == 0 ) {
382
+ my @lingering_agents = grep { /startme\.sh/ } @lingering_agent_output;
383
+ if( @lingering_agents == 0 ) {
384
+ print $VALIDATION "PASSED.\n\n";
385
+ } else {
386
+ $, = "\n"; # Sets the list printing separator
387
+ print $VALIDATION "FAILED.\n";
388
+ print $VALIDATION "Found the following lingering agents:\n";
389
+ print $VALIDATION @lingering_agents;
390
+ print $VALIDATION "\n";
391
+ print $VALIDATION "Validation FAILED.\n";
392
+ die "ERROR: lingering startme.sh found after match $match_name, stopped";
393
+ }
394
+ } else {
395
+ print $VALIDATION "FAILED.\n";
396
+ print $VALIDATION "Validation FAILED.\n";
397
+ die "$lingering_agent_cmd\n@lingering_agent_output\n" .
398
+ "ERROR: Unable to get processes to check for lingering agents, stopped";
399
+ }
400
+
401
+ # Check for any warnings in the output
402
+ print $VALIDATION "Checking $match_name.err output for errors/warnings... ";
403
+
404
+ if( not open( DEALER_STDERR,
405
+ File::Spec->catfile( $validation_dir, "$match_name.err" ) ) ) {
406
+ print $VALIDATION "FAILED.\n";
407
+ print $VALIDATION "Unable to open $match_name.err for reading: $!\n";
408
+ print $VALIDATION "Validation FAILED.\n";
409
+ die "ERROR: Cannot open $match_name.err for reading to check for " .
410
+ "errors in match $match_name: $!, stopped";
411
+ }
412
+
413
+ my @match_warnings = grep { /(WARNING|ERROR)/ } <DEALER_STDERR>;
414
+ close DEALER_STDERR;
415
+
416
+ if( @match_warnings == 0 ) {
417
+ print $VALIDATION "PASSED.\n\n";
418
+ } else {
419
+ $, = ""; # Sets the list printing separator
420
+ print $VALIDATION "FAILED.\n";
421
+ print $VALIDATION "Found the following warnings/errors:\n";
422
+ print $VALIDATION @match_warnings;
423
+ print $VALIDATION "\n";
424
+ print $VALIDATION "Validation FAILED.\n";
425
+ die "ERROR: dealer warnings detected in match $match_name, stopped";
426
+ }
427
+ }
428
+
429
+ print $VALIDATION "========= Test match statistics ==========\n";
430
+ print $VALIDATION "Matches played: $matches_played\n";
431
+ print $VALIDATION "Hands played: ", ( $matches_played * $num_hands ), "\n";
432
+ print $VALIDATION "Average time per hand (seconds): ",
433
+ $total_decision_time / ( $matches_played * $num_hands ), "\n";
434
+ print $VALIDATION "Average time per match (seconds): ",
435
+ $total_decision_time / $matches_played, "\n";
436
+
437
+ my $performance
438
+ = ( 1000 * $total_score ) / ( $big_blind * $matches_played * $num_hands );
439
+ print $VALIDATION "Performance (milli big blinds per hand): ",
440
+ $performance, "\n";
441
+
442
+ print $VALIDATION "Checking for winning performance... ";
443
+ if( $performance >= 0 ) {
444
+ print $VALIDATION "PASSED.\n\n";
445
+ } else {
446
+ print $VALIDATION "FAILED.\n";
447
+ print $VALIDATION "Validation FAILED.\n";
448
+ die "ERROR: Submission unable to beat chump in test matches, stopped";
449
+ }
450
+
451
+ # Print completion messages
452
+ print "Validation PASSED.\n";
453
+
454
+ print $VALIDATION "Validation PASSED.\n";
455
+
456
+ close $VALIDATION;
457
+
458
+ # POD Documentation for usage message
459
+ __END__
460
+
461
+ =head1 NAME
462
+
463
+ B<validate_submission.pl> - Checks that the sepcified submission file for the
464
+ Annual Computer Poker Competition is well formed and works.
465
+
466
+ =head1 SYNOPSIS
467
+
468
+ B<validate_submission.pl> [options] submission_dir
469
+
470
+ =head1 DESCRIPTION
471
+
472
+ B<validate_submission.pl> - Tests that the specified submission file passes
473
+ basic sanity checks expected of entries in the Annual Computer Poker
474
+ Competition. This process could take a long time depending on the
475
+ size of your submission file and the rate at which it plays.
476
+
477
+ Note that this script expects that your agent:
478
+
479
+ =over 8
480
+
481
+ =item *
482
+
483
+ Is contained in a single directory named submission_2pl, submission_2pn
484
+ or submission_3pl
485
+
486
+ =item *
487
+
488
+ Has an startme.sh script with permissions of at least 755 at the root of your
489
+ directory
490
+
491
+ =item *
492
+
493
+ Has a README file at the root of your directory
494
+
495
+ =item *
496
+
497
+ Is within the size limit
498
+
499
+ =item *
500
+
501
+ Plays only valid actions
502
+
503
+ =item *
504
+
505
+ Cleans itself up once the match is over
506
+
507
+ =item *
508
+
509
+ Beats an agent that plays randomly and does not look at its cards
510
+
511
+ =back
512
+
513
+ Failure on any of these points will cause the validation to fail. Futhermore,
514
+ ensure that you are B<only running one test script at a time> as they will
515
+ interfere with each other.
516
+
517
+ The required argument is:
518
+
519
+ =over 8
520
+
521
+ =item B<submission_dir>
522
+
523
+ A path to a submission directory that you want to check for basic correctness
524
+
525
+ =back
526
+
527
+ =head1 OPTIONS
528
+
529
+ =over 8
530
+
531
+ =item B<--help>
532
+
533
+ Print a brief help message and exits.
534
+
535
+ =item B<--man>
536
+
537
+ Prints the manual page and exits.
538
+
539
+ =item B<--num_hands=[positive integer]>
540
+
541
+ Set the number of hands you want to test for. Defaults to the minimum number
542
+ of hands for validation. Please run as many as you can.
543
+
544
+ =back
545
+
546
+ =cut