acpc_dealer 2.4.1 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (90) hide show
  1. checksums.yaml +4 -4
  2. data/Brickfile +6 -0
  3. data/README.md +7 -6
  4. data/Rakefile +30 -14
  5. data/acpc_dealer.gemspec +2 -1
  6. data/bin/acpc_dealer +4 -0
  7. data/ext/hand_evaluator/extconf.rb +10 -0
  8. data/lib/acpc_dealer/version.rb +1 -1
  9. data/lib/hand_evaluator.bundle +0 -0
  10. data/spec/dealer_runner_spec.rb +76 -72
  11. metadata +19 -82
  12. data/vendor/project_acpc_server/LICENCE +0 -23
  13. data/vendor/project_acpc_server/Makefile +0 -35
  14. data/vendor/project_acpc_server/README +0 -113
  15. data/vendor/project_acpc_server/README.submission +0 -42
  16. data/vendor/project_acpc_server/acpc_play_match.pl +0 -101
  17. data/vendor/project_acpc_server/bm_run_matches.c +0 -238
  18. data/vendor/project_acpc_server/bm_server.c +0 -1604
  19. data/vendor/project_acpc_server/bm_server.config +0 -78
  20. data/vendor/project_acpc_server/bm_widget.c +0 -230
  21. data/vendor/project_acpc_server/dealer.c +0 -1293
  22. data/vendor/project_acpc_server/evalHandTables +0 -4269
  23. data/vendor/project_acpc_server/example_player.c +0 -204
  24. data/vendor/project_acpc_server/example_player.limit.2p.sh +0 -3
  25. data/vendor/project_acpc_server/example_player.limit.3p.sh +0 -3
  26. data/vendor/project_acpc_server/example_player.nolimit.2p.sh +0 -3
  27. data/vendor/project_acpc_server/example_player.nolimit.3p.sh +0 -3
  28. data/vendor/project_acpc_server/game.c +0 -1792
  29. data/vendor/project_acpc_server/game.h +0 -253
  30. data/vendor/project_acpc_server/holdem.limit.2p.reverse_blinds.game +0 -13
  31. data/vendor/project_acpc_server/holdem.limit.3p.game +0 -13
  32. data/vendor/project_acpc_server/holdem.nolimit.2p.reverse_blinds.game +0 -12
  33. data/vendor/project_acpc_server/holdem.nolimit.3p.game +0 -12
  34. data/vendor/project_acpc_server/kuhn.limit.3p.game +0 -14
  35. data/vendor/project_acpc_server/kuhn_3p_equilibrium_player.sf1.sh +0 -3
  36. data/vendor/project_acpc_server/kuhn_3p_equilibrium_player.sf2.sh +0 -3
  37. data/vendor/project_acpc_server/kuhn_3p_equilibrium_player.sf3.sh +0 -3
  38. data/vendor/project_acpc_server/kuhn_3p_equilibrium_player/LICENCE +0 -23
  39. data/vendor/project_acpc_server/kuhn_3p_equilibrium_player/Makefile +0 -127
  40. data/vendor/project_acpc_server/kuhn_3p_equilibrium_player/README.md +0 -35
  41. data/vendor/project_acpc_server/kuhn_3p_equilibrium_player/src/CExceptionConfig.h +0 -12
  42. data/vendor/project_acpc_server/kuhn_3p_equilibrium_player/src/dealer_connection.c +0 -49
  43. data/vendor/project_acpc_server/kuhn_3p_equilibrium_player/src/dealer_connection.h +0 -22
  44. data/vendor/project_acpc_server/kuhn_3p_equilibrium_player/src/kuhn_3p_equilibrium_player.c +0 -483
  45. data/vendor/project_acpc_server/kuhn_3p_equilibrium_player/src/kuhn_3p_equilibrium_player.h +0 -108
  46. data/vendor/project_acpc_server/kuhn_3p_equilibrium_player/src/main.c +0 -84
  47. data/vendor/project_acpc_server/kuhn_3p_equilibrium_player/src/player_config.c +0 -253
  48. data/vendor/project_acpc_server/kuhn_3p_equilibrium_player/src/player_config.h +0 -21
  49. data/vendor/project_acpc_server/kuhn_3p_equilibrium_player/test/support/test_helper.c +0 -45
  50. data/vendor/project_acpc_server/kuhn_3p_equilibrium_player/test/support/test_helper.h +0 -27
  51. data/vendor/project_acpc_server/kuhn_3p_equilibrium_player/test/test_kuhn_3p_equilibrium_player.c +0 -698
  52. data/vendor/project_acpc_server/kuhn_3p_equilibrium_player/test/test_kuhn_3p_equilibrium_player_sub_family_1.c +0 -324
  53. data/vendor/project_acpc_server/kuhn_3p_equilibrium_player/test/test_kuhn_3p_equilibrium_player_sub_family_2.c +0 -262
  54. data/vendor/project_acpc_server/kuhn_3p_equilibrium_player/test/test_kuhn_3p_equilibrium_player_sub_family_3.c +0 -177
  55. data/vendor/project_acpc_server/kuhn_3p_equilibrium_player/vendor/cexception/docs/license.txt +0 -30
  56. data/vendor/project_acpc_server/kuhn_3p_equilibrium_player/vendor/cexception/docs/readme.txt +0 -242
  57. data/vendor/project_acpc_server/kuhn_3p_equilibrium_player/vendor/cexception/lib/CException.c +0 -43
  58. data/vendor/project_acpc_server/kuhn_3p_equilibrium_player/vendor/cexception/lib/CException.h +0 -86
  59. data/vendor/project_acpc_server/kuhn_3p_equilibrium_player/vendor/cexception/release/build.info +0 -2
  60. data/vendor/project_acpc_server/kuhn_3p_equilibrium_player/vendor/cexception/release/version.info +0 -2
  61. data/vendor/project_acpc_server/kuhn_3p_equilibrium_player/vendor/commander.c/History.md +0 -27
  62. data/vendor/project_acpc_server/kuhn_3p_equilibrium_player/vendor/commander.c/Makefile +0 -8
  63. data/vendor/project_acpc_server/kuhn_3p_equilibrium_player/vendor/commander.c/Readme.md +0 -103
  64. data/vendor/project_acpc_server/kuhn_3p_equilibrium_player/vendor/commander.c/package.json +0 -9
  65. data/vendor/project_acpc_server/kuhn_3p_equilibrium_player/vendor/commander.c/src/commander.c +0 -250
  66. data/vendor/project_acpc_server/kuhn_3p_equilibrium_player/vendor/commander.c/src/commander.h +0 -88
  67. data/vendor/project_acpc_server/kuhn_3p_equilibrium_player/vendor/commander.c/test.c +0 -34
  68. data/vendor/project_acpc_server/kuhn_3p_equilibrium_player/vendor/unity/auto/colour_prompt.rb +0 -94
  69. data/vendor/project_acpc_server/kuhn_3p_equilibrium_player/vendor/unity/auto/colour_reporter.rb +0 -39
  70. data/vendor/project_acpc_server/kuhn_3p_equilibrium_player/vendor/unity/auto/generate_config.yml +0 -36
  71. data/vendor/project_acpc_server/kuhn_3p_equilibrium_player/vendor/unity/auto/generate_module.rb +0 -202
  72. data/vendor/project_acpc_server/kuhn_3p_equilibrium_player/vendor/unity/auto/generate_test_runner.rb +0 -316
  73. data/vendor/project_acpc_server/kuhn_3p_equilibrium_player/vendor/unity/auto/test_file_filter.rb +0 -23
  74. data/vendor/project_acpc_server/kuhn_3p_equilibrium_player/vendor/unity/auto/unity_test_summary.rb +0 -139
  75. data/vendor/project_acpc_server/kuhn_3p_equilibrium_player/vendor/unity/docs/Unity Summary.txt +0 -216
  76. data/vendor/project_acpc_server/kuhn_3p_equilibrium_player/vendor/unity/docs/license.txt +0 -31
  77. data/vendor/project_acpc_server/kuhn_3p_equilibrium_player/vendor/unity/release/build.info +0 -2
  78. data/vendor/project_acpc_server/kuhn_3p_equilibrium_player/vendor/unity/release/version.info +0 -2
  79. data/vendor/project_acpc_server/kuhn_3p_equilibrium_player/vendor/unity/src/unity.c +0 -1146
  80. data/vendor/project_acpc_server/kuhn_3p_equilibrium_player/vendor/unity/src/unity.h +0 -245
  81. data/vendor/project_acpc_server/kuhn_3p_equilibrium_player/vendor/unity/src/unity_internals.h +0 -546
  82. data/vendor/project_acpc_server/net.c +0 -218
  83. data/vendor/project_acpc_server/net.h +0 -62
  84. data/vendor/project_acpc_server/play_match.pl +0 -99
  85. data/vendor/project_acpc_server/protocol.md +0 -239
  86. data/vendor/project_acpc_server/protocol.odt +0 -0
  87. data/vendor/project_acpc_server/protocol.pdf +0 -0
  88. data/vendor/project_acpc_server/rng.c +0 -139
  89. data/vendor/project_acpc_server/rng.h +0 -63
  90. data/vendor/project_acpc_server/validate_submission.pl +0 -546
@@ -1,78 +0,0 @@
1
- # port to connect to the server
2
- port 54000
3
-
4
- # maxmimum number of simultaneously locally running bots
5
- # 0 disables
6
- maxRunningBots 0
7
-
8
- # maximum time in seconds to wait for clients to connect when starting a match
9
- startupTimeoutSecs 100
10
- # maximum time in seconds to wait for clients to act during a match
11
- responseTimeoutSecs 600
12
- # maximum time in seconds allowed for a client to play a given hand
13
- handTimeoutSecs 21000
14
- # average time in seconds allowed for a client to spend on each hand
15
- avgHandTimeSecs 7
16
-
17
- # heads up limit Texas Hold'em
18
- game holdem.limit.2p.reverse_blinds.game {
19
-
20
- # maximum number of times a match can be run with a single player request
21
- maxMatchRuns 10
22
-
23
- # maxmimum number of simultaneously running matches using this game
24
- # 0 disables
25
- maxRunningJobs 1
26
-
27
- # number of hands in a match
28
- matchHands 5000
29
-
30
- # bot botName botStartupScript
31
- # botStartupScript is run with 3 args: server name, port, local position
32
- # local postion indicates which LOCAL bot this is (index starting from 0)
33
- # This is useful when determining which of multiple machines to run on
34
- bot testBot example_player.limit.2p.sh
35
- }
36
-
37
- # heads up limit Texas Hold'em
38
- game holdem.nolimit.2p.reverse_blinds.game {
39
-
40
- # maximum number of times a match can be run with a single player request
41
- maxMatchRuns 10
42
-
43
- # maxmimum number of simultaneously running matches using this game
44
- # 0 disables
45
- maxRunningJobs 1
46
-
47
- # number of hands in a match
48
- matchHands 5000
49
-
50
- # bot botName botStartupScript
51
- # botStartupScript is run with 3 args: server name, port, local position
52
- # local postion indicates which LOCAL bot this is (index starting from 0)
53
- # This is useful when determining which of multiple machines to run on
54
- bot testBot example_player.nolimit.2p.sh
55
- }
56
-
57
- # heads up limit Texas Hold'em
58
- game holdem.limit.3p.game {
59
-
60
- # maximum number of times a match can be run with a single player request
61
- maxMatchRuns 10
62
-
63
- # maxmimum number of simultaneously running matches using this game
64
- # 0 disables
65
- maxRunningJobs 1
66
-
67
- # number of hands in a match
68
- matchHands 5000
69
-
70
- # bot botName botStartupScript
71
- # botStartupScript is run with 3 args: server name, port, local position
72
- # local postion indicates which LOCAL bot this is (index starting from 0)
73
- # This is useful when determining which of multiple machines to run on
74
- bot testBot example_player.limit.3p.sh
75
- }
76
-
77
- # Users authorized to run jobs on the benchmark (user name pass)
78
- user neil test
@@ -1,230 +0,0 @@
1
- /*
2
- Copyright (C) 2011 by the Computer Poker Research Group, University of Alberta
3
- */
4
-
5
- #include <stdlib.h>
6
- #include <stdio.h>
7
- #define __STDC_FORMAT_MACROS
8
- #include <inttypes.h>
9
- #include <assert.h>
10
- #include <string.h>
11
- #include <unistd.h>
12
- #include <netdb.h>
13
- #include <sys/socket.h>
14
- #include <netinet/in.h>
15
- #include <netinet/tcp.h>
16
- #include <sys/wait.h>
17
- #include <errno.h>
18
- #include "net.h"
19
-
20
-
21
- #define ARG_SERVERNAME 1
22
- #define ARG_SERVERPORT 2
23
- #define ARG_BOT_COMMAND 3
24
- #define ARG_NUM_ARGS 4
25
-
26
-
27
- static void printUsage( FILE *file )
28
- {
29
- fprintf( file, "usage: bm_widget bm_hostname bm_port bot_command\n" );
30
- fprintf( file, " bot_command: agent executable, passed \"hostname port\"\n");
31
- }
32
-
33
-
34
- /* 0 on success, -1 on failure */
35
- int login( char *user, char *passwd, FILE *conn )
36
- {
37
- if( fprintf( conn, "%s %s\n", user, passwd ) < 0 ) {
38
-
39
- return -1;
40
- }
41
- fflush( conn );
42
-
43
- return 0;
44
- }
45
-
46
-
47
- int main( int argc, char **argv )
48
- {
49
- int sock, i;
50
- pid_t childPID;
51
- uint16_t port;
52
- ReadBuf *fromUser, *fromServer;
53
- fd_set readfds;
54
- char line[ READBUF_LEN ];
55
-
56
- if( argc < ARG_NUM_ARGS ) {
57
-
58
- printUsage( stderr );
59
- exit( EXIT_FAILURE );
60
- }
61
-
62
-
63
- /* connect to the server */
64
- if( sscanf( argv[ ARG_SERVERPORT ], "%"SCNu16, &port ) < 1 ) {
65
-
66
- fprintf( stderr, "ERROR: invalid port %s\n", argv[ ARG_SERVERPORT ] );
67
- exit( EXIT_FAILURE );
68
- }
69
- sock = connectTo( argv[ ARG_SERVERNAME ], port );
70
- if( sock < 0 ) {
71
-
72
- exit( EXIT_FAILURE );
73
- }
74
-
75
- // EJ additions 9/3/2012
76
- // Turn on keep-alive for socket connection with more frequent checking
77
- // than the Linux default. What I've observed is that if a socket
78
- // connection is idle for long enough it gets dropped. This only
79
- // happens for some users.
80
- struct protoent *proto = getprotobyname("tcp");
81
- if (proto == NULL) {
82
- fprintf( stderr, "ERROR: Unable to get TCP protocol number.\n" );
83
- exit( EXIT_FAILURE );
84
- }
85
- int level = proto->p_proto;
86
-
87
- int on = 1;
88
- if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on)) == -1) {
89
- fprintf( stderr, "ERROR: setsockopt failed; errno %i\n", errno );
90
- exit( EXIT_FAILURE );
91
- }
92
- // Not sure what this should be
93
- int num_before_failure = 2;
94
- if (setsockopt(sock, level, TCP_KEEPCNT, &num_before_failure,
95
- sizeof(num_before_failure)) == -1) {
96
- fprintf( stderr, "ERROR: setsockopt failed; errno %i\n", errno );
97
- exit( EXIT_FAILURE );
98
- }
99
- #ifdef TCP_KEEPIDLE
100
- // First check after 60 seconds
101
- int initial_secs = 60;
102
- if (setsockopt(sock, level, TCP_KEEPIDLE, &initial_secs,
103
- sizeof(initial_secs)) == -1) {
104
- fprintf( stderr, "ERROR: setsockopt failed; errno %i\n", errno );
105
- exit( EXIT_FAILURE );
106
- }
107
- #endif
108
- // Thereafter, also check every 60 seconds
109
- int interval_secs = 60;
110
- if (setsockopt(sock, level, TCP_KEEPINTVL, &interval_secs,
111
- sizeof(interval_secs)) == -1) {
112
- fprintf( stderr, "ERROR: setsockopt failed; errno %i\n", errno );
113
- exit( EXIT_FAILURE );
114
- }
115
-
116
- /* set up read buffers */
117
- fromUser = createReadBuf( 0 );
118
- fromServer = createReadBuf( sock );
119
-
120
- printf( "Log in with 'user password'\n" );
121
- fflush( stdout );
122
-
123
- /* main loop */
124
- while( 1 ) {
125
-
126
- /* clean up any children */
127
- while( waitpid( -1, NULL, WNOHANG ) > 0 );
128
-
129
- /* wait for input */
130
- FD_ZERO( &readfds );
131
- FD_SET( 0, &readfds );
132
- FD_SET( sock, &readfds );
133
- i = select( sock + 1, &readfds, NULL, NULL, NULL );
134
- if( i < 0 ) {
135
-
136
- fprintf( stderr, "ERROR: select failed\n" );
137
- exit( EXIT_FAILURE );
138
- }
139
- if( i == 0 ) {
140
- /* nothing ready - shouldn't happen without timeout */
141
-
142
- continue;
143
- }
144
-
145
- /* handle user input by passing it directly to server */
146
- if( FD_ISSET( 0, &readfds ) ) {
147
-
148
- /* get the input */
149
- while( ( i = getLine( fromUser, READBUF_LEN, line, 0 ) ) >= 0 ) {
150
-
151
- if( i == 0 ) {
152
- /* Done! */
153
-
154
- exit( EXIT_SUCCESS );
155
- }
156
-
157
- /* write to server */
158
- if( write( sock, line, i ) < 0 ) {
159
-
160
- fprintf( stderr, "ERROR: failed while sending to server\n" );
161
- exit( EXIT_FAILURE );
162
- }
163
- }
164
- }
165
-
166
- /* handle server messages */
167
- if( FD_ISSET( sock, &readfds ) ) {
168
-
169
- /* get the input */
170
- while( ( i = getLine( fromServer, READBUF_LEN, line, 0 ) ) >= 0 ) {
171
-
172
- if( i == 0 ) {
173
-
174
- fprintf( stderr, "ERROR: server closed connection?\n" );
175
- exit( EXIT_FAILURE );
176
- }
177
-
178
- /* check for server commands */
179
- if( strncasecmp( line, "run ", 4 ) == 0 ) {
180
-
181
- /* split the rest of the line into name ' ' port */
182
- for( i = 4; line[ i ]; ++i ) {
183
-
184
- if( line[ i ] == ' ' ) {
185
- /* found the separator */
186
-
187
- line[ i ] = 0;
188
- break;
189
- }
190
- }
191
-
192
- printf( "starting match %s:%s", &line[ 4 ], &line[ i + 1 ] );
193
- fflush( stdout );
194
-
195
- /* run `command machine port` */
196
- childPID = fork();
197
- if( childPID < 0 ) {
198
-
199
- fprintf( stderr, "ERROR: fork() failed\n" );
200
- exit( EXIT_FAILURE );
201
- }
202
- if( childPID == 0 ) {
203
- /* child runs the command */
204
-
205
- execl( argv[ ARG_BOT_COMMAND ],
206
- argv[ ARG_BOT_COMMAND ],
207
- &line[ 4 ],
208
- &line[ i + 1 ],
209
- NULL );
210
- fprintf( stderr,
211
- "ERROR: could not run %s\n",
212
- argv[ ARG_BOT_COMMAND ] );
213
- exit( EXIT_FAILURE );
214
- }
215
- } else {
216
- /* just a message, print it out */
217
-
218
- if( fwrite( line, 1, i, stdout ) < 0 ) {
219
-
220
- fprintf( stderr, "ERROR: failed while printing server message\n" );
221
- exit( EXIT_FAILURE );
222
- }
223
- fflush( stdout );
224
- }
225
- }
226
- }
227
- }
228
-
229
- return EXIT_SUCCESS;
230
- }
@@ -1,1293 +0,0 @@
1
- /*
2
- Copyright (C) 2011 by the Computer Poker Research Group, University of Alberta
3
- */
4
-
5
- #include <stdlib.h>
6
- #include <stdio.h>
7
- #define __STDC_LIMIT_MACROS
8
- #include <stdint.h>
9
- #include <unistd.h>
10
- #include <sys/socket.h>
11
- #include <sys/time.h>
12
- #include <sys/select.h>
13
- #include <netinet/in.h>
14
- #include <netinet/tcp.h>
15
- #include <getopt.h>
16
- #include "game.h"
17
- #include "net.h"
18
-
19
-
20
- /* the ports for players to connect to will be printed on standard out
21
- (in player order)
22
-
23
- if log file is enabled, matchName.log will contain finished states
24
- and values, followed by the final total values for each player
25
-
26
- if transaction file is enabled, matchName.tlog will contain a list
27
- of actions taken and timestamps that is sufficient to recreate an
28
- interrupted match
29
-
30
- if the quiet option is not enabled, standard error will print out
31
- the messages sent to and receieved from the players
32
-
33
- the final total values for each player will be printed to both
34
- standard out and standard error
35
-
36
- exit value is EXIT_SUCCESS if the match was a success,
37
- or EXIT_FAILURE on any failure */
38
-
39
-
40
- #define DEFAULT_MAX_INVALID_ACTIONS UINT32_MAX
41
- #define DEFAULT_MAX_RESPONSE_MICROS 600000000
42
- #define DEFAULT_MAX_USED_HAND_MICROS 600000000
43
- #define DEFAULT_MAX_USED_PER_HAND_MICROS 7000000
44
-
45
-
46
- typedef struct {
47
- uint32_t maxInvalidActions;
48
- uint64_t maxResponseMicros;
49
- uint64_t maxUsedHandMicros;
50
- uint64_t maxUsedMatchMicros;
51
-
52
- uint32_t numInvalidActions[ MAX_PLAYERS ];
53
- uint64_t usedHandMicros[ MAX_PLAYERS ];
54
- uint64_t usedMatchMicros[ MAX_PLAYERS ];
55
- } ErrorInfo;
56
-
57
-
58
- static void printUsage( FILE *file, int verbose )
59
- {
60
- fprintf( file, "usage: dealer matchName gameDefFile #Hands rngSeed p1name p2name ... [options]\n" );
61
- fprintf( file, " -f use fixed dealer button at table\n" );
62
- fprintf( file, " -l/L disable/enable log file - enabled by default\n" );
63
- fprintf( file, " -p player1_port,player2_port,... [default is random]\n" );
64
- fprintf( file, " -q only print errors, warnings, and final value to stderr\n" );
65
- fprintf( file, " -t/T disable/enable transaction file - disabled by default\n" );
66
- fprintf( file, " -a append to log/transaction files - disabled by default\n" );
67
- fprintf( file, " --t_response [milliseconds] maximum time per response\n" );
68
- fprintf( file, " --t_hand [milliseconds] maximum player time per hand\n" );
69
- fprintf( file, " --t_per_hand [milliseconds] maximum average player time for match\n" );
70
- fprintf( file, " --start_timeout [milliseconds] maximum time to wait for players to connect\n" );
71
- fprintf( file, " <0 [default] is no timeout\n" );
72
- }
73
-
74
- /* returns >= 0 on success, -1 on error */
75
- static int scanPortString( const char *string,
76
- uint16_t listenPort[ MAX_PLAYERS ] )
77
- {
78
- int c, r, p;
79
-
80
- c = 0;
81
- for( p = 0; p < MAX_PLAYERS; ++p ) {
82
-
83
- if( string[ c ] == 0 ) {
84
- /* finished parsing the string */
85
-
86
- break;
87
- }
88
-
89
- if( p ) {
90
- /* look for separator */
91
-
92
- if( string[ c ] != ',' ) {
93
- /* numbers should be comma separated */
94
-
95
- return -1;
96
- }
97
- ++c;
98
- }
99
-
100
- if( sscanf( &string[ c ], "%"SCNu16"%n", &listenPort[ p ], &r ) < 1 ) {
101
- /* couldn't get a number */
102
-
103
- return -1;
104
- }
105
- c += r;
106
- }
107
-
108
- return 0;
109
- }
110
-
111
- static void initErrorInfo( const uint32_t maxInvalidActions,
112
- const uint64_t maxResponseMicros,
113
- const uint64_t maxUsedHandMicros,
114
- const uint64_t maxUsedMatchMicros,
115
- ErrorInfo *info )
116
- {
117
- int s;
118
-
119
- info->maxInvalidActions = maxInvalidActions;
120
- info->maxResponseMicros = maxResponseMicros;
121
- info->maxUsedHandMicros = maxUsedHandMicros;
122
- info->maxUsedMatchMicros = maxUsedMatchMicros;
123
-
124
- for( s = 0; s < MAX_PLAYERS; ++s ) {
125
- info->numInvalidActions[ s ] = 0;
126
- info->usedHandMicros[ s ] = 0;
127
- info->usedMatchMicros[ s ] = 0;
128
- }
129
- }
130
-
131
-
132
- /* update the number of invalid actions for seat
133
- returns >= 0 if match should continue, -1 for failure */
134
- static int checkErrorInvalidAction( const uint8_t seat, ErrorInfo *info )
135
- {
136
- ++( info->numInvalidActions[ seat ] );
137
-
138
- if( info->numInvalidActions[ seat ] > info->maxInvalidActions ) {
139
- return -1;
140
- }
141
-
142
- return 0;
143
- }
144
-
145
- /* update the time used by seat
146
- returns >= 0 if match should continue, -1 for failure */
147
- static int checkErrorTimes( const uint8_t seat,
148
- const struct timeval *sendTime,
149
- const struct timeval *recvTime,
150
- ErrorInfo *info )
151
- {
152
- uint64_t responseMicros;
153
-
154
- /* calls to gettimeofday can return earlier times on later calls :/ */
155
- if( recvTime->tv_sec < sendTime->tv_sec
156
- || ( recvTime->tv_sec == sendTime->tv_sec
157
- && recvTime->tv_usec < sendTime->tv_usec ) ) {
158
- return 0;
159
- }
160
-
161
- /* figure out how many microseconds the response took */
162
- responseMicros = ( recvTime->tv_sec - sendTime->tv_sec ) * 1000000
163
- + recvTime->tv_usec - sendTime->tv_usec;
164
-
165
- /* update usage counts */
166
- info->usedHandMicros[ seat ] += responseMicros;
167
- info->usedMatchMicros[ seat ] += responseMicros;
168
-
169
- /* check time used for the response */
170
- if( responseMicros > info->maxResponseMicros ) {
171
- return -1;
172
- }
173
-
174
- /* check time used in the current hand */
175
- if( info->usedHandMicros[ seat ] > info->maxUsedHandMicros ) {
176
- return -1;
177
- }
178
-
179
- /* check time used in the entire match */
180
- if( info->usedMatchMicros[ seat ] > info->maxUsedMatchMicros ) {
181
- return -1;
182
- }
183
-
184
- return 0;
185
- }
186
-
187
- /* note that there is a new hand
188
- returns >= 0 if match should continue, -1 for failure */
189
- static int checkErrorNewHand( const Game *game, ErrorInfo *info )
190
- {
191
- uint8_t p;
192
-
193
- for( p = 0; p < game->numPlayers; ++p ) {
194
- info->usedHandMicros[ p ] = 0;
195
- }
196
-
197
- return 0;
198
- }
199
-
200
-
201
- static uint8_t seatToPlayer( const Game *game, const uint8_t player0Seat,
202
- const uint8_t seat )
203
- {
204
- return ( seat + game->numPlayers - player0Seat ) % game->numPlayers;
205
- }
206
-
207
- static uint8_t playerToSeat( const Game *game, const uint8_t player0Seat,
208
- const uint8_t player )
209
- {
210
- return ( player + player0Seat ) % game->numPlayers;
211
- }
212
-
213
- /* returns >= 0 if match should continue, -1 for failure */
214
- static int sendPlayerMessage( const Game *game, const MatchState *state,
215
- const int quiet, const uint8_t seat,
216
- const int seatFD, struct timeval *sendTime )
217
- {
218
- int c;
219
- char line[ MAX_LINE_LEN ];
220
-
221
- /* prepare the message */
222
- c = printMatchState( game, state, MAX_LINE_LEN, line );
223
- if( c < 0 || c > MAX_LINE_LEN - 3 ) {
224
- /* message is too long */
225
-
226
- fprintf( stderr, "ERROR: state message too long\n" );
227
- return -1;
228
- }
229
- line[ c ] = '\r';
230
- line[ c + 1 ] = '\n';
231
- line[ c + 2 ] = 0;
232
- c += 2;
233
-
234
- /* send it to the player and flush */
235
- if( write( seatFD, line, c ) != c ) {
236
- /* couldn't send the line */
237
-
238
- fprintf( stderr, "ERROR: could not send state to seat %"PRIu8"\n",
239
- seat + 1 );
240
- return -1;
241
- }
242
-
243
- /* note when we sent the message */
244
- gettimeofday( sendTime, NULL );
245
-
246
- /* log the message */
247
- if( !quiet ) {
248
- fprintf( stderr, "TO %d at %zu.%.06zu %s", seat + 1,
249
- sendTime->tv_sec, sendTime->tv_usec, line );
250
- }
251
-
252
- return 0;
253
- }
254
-
255
- /* returns >= 0 if action/size has been set to a valid action
256
- returns -1 for failure (disconnect, timeout, too many bad actions, etc) */
257
- static int readPlayerResponse( const Game *game,
258
- const MatchState *state,
259
- const int quiet,
260
- const uint8_t seat,
261
- const struct timeval *sendTime,
262
- ErrorInfo *errorInfo,
263
- ReadBuf *readBuf,
264
- Action *action,
265
- struct timeval *recvTime )
266
- {
267
- int c, r;
268
- MatchState tempState;
269
- char line[ MAX_LINE_LEN ];
270
-
271
- while( 1 ) {
272
-
273
- /* read a line of input from player */
274
- struct timeval start;
275
- gettimeofday( &start, NULL );
276
- if( getLine( readBuf, MAX_LINE_LEN, line,
277
- errorInfo->maxResponseMicros ) <= 0 ) {
278
- /* couldn't get any input from player */
279
-
280
- struct timeval after;
281
- gettimeofday( &after, NULL );
282
- uint64_t micros_spent =
283
- (uint64_t)( after.tv_sec - start.tv_sec ) * 1000000
284
- + ( after.tv_usec - start.tv_usec );
285
- fprintf( stderr, "ERROR: could not get action from seat %"PRIu8"\n",
286
- seat + 1 );
287
- // Print out how much time has passed so we can see if this was a
288
- // timeout as opposed to some other sort of failure (e.g., socket
289
- // closing).
290
- fprintf( stderr, "%.1f seconds spent waiting; timeout %.1f\n",
291
- micros_spent / 1000000.0,
292
- errorInfo->maxResponseMicros / 1000000.0);
293
- return -1;
294
- }
295
-
296
- /* note when the message arrived */
297
- gettimeofday( recvTime, NULL );
298
-
299
- /* log the response */
300
- if( !quiet ) {
301
- fprintf( stderr, "FROM %d at %zu.%06zu %s", seat + 1,
302
- recvTime->tv_sec, recvTime->tv_usec, line );
303
- }
304
-
305
- /* ignore comments */
306
- if( line[ 0 ] == '#' || line[ 0 ] == ';' ) {
307
- continue;
308
- }
309
-
310
- /* check for any timeout issues */
311
- if( checkErrorTimes( seat, sendTime, recvTime, errorInfo ) < 0 ) {
312
-
313
- fprintf( stderr, "ERROR: seat %"PRIu8" ran out of time\n", seat + 1 );
314
- return -1;
315
- }
316
-
317
- /* parse out the state */
318
- c = readMatchState( line, game, &tempState );
319
- if( c < 0 ) {
320
- /* couldn't get an intelligible state */
321
-
322
- fprintf( stderr, "WARNING: bad state format in response\n" );
323
- continue;
324
- }
325
-
326
- /* ignore responses that don't match the current state */
327
- if( !matchStatesEqual( game, state, &tempState ) ) {
328
-
329
- fprintf( stderr, "WARNING: ignoring un-requested response\n" );
330
- continue;
331
- }
332
-
333
- /* get the action */
334
- if( line[ c++ ] != ':'
335
- || ( r = readAction( &line[ c ], game, action ) ) < 0 ) {
336
-
337
- if( checkErrorInvalidAction( seat, errorInfo ) < 0 ) {
338
-
339
- fprintf( stderr, "ERROR: bad action format in response\n" );
340
- }
341
-
342
- fprintf( stderr,
343
- "WARNING: bad action format in response, changed to call\n" );
344
- action->type = a_call;
345
- action->size = 0;
346
- goto doneRead;
347
- }
348
- c += r;
349
-
350
- /* make sure the action is valid */
351
- if( !isValidAction( game, &state->state, 1, action ) ) {
352
-
353
- if( checkErrorInvalidAction( seat, errorInfo ) < 0 ) {
354
-
355
- fprintf( stderr, "ERROR: invalid action\n" );
356
- return -1;
357
- }
358
-
359
- fprintf( stderr, "WARNING: invalid action, changed to call\n" );
360
- action->type = a_call;
361
- action->size = 0;
362
- }
363
-
364
- goto doneRead;
365
- }
366
-
367
- doneRead:
368
- return 0;
369
- }
370
-
371
- /* returns >= 0 if match should continue, -1 for failure */
372
- static int setUpNewHand( const Game *game, const uint8_t fixedSeats,
373
- uint32_t *handId, uint8_t *player0Seat,
374
- rng_state_t *rng, ErrorInfo *errorInfo, State *state )
375
- {
376
- ++( *handId );
377
-
378
- /* rotate the players around the table */
379
- if( !fixedSeats ) {
380
-
381
- *player0Seat = ( *player0Seat + 1 ) % game->numPlayers;
382
- }
383
-
384
- if( checkErrorNewHand( game, errorInfo ) < 0 ) {
385
-
386
- fprintf( stderr, "ERROR: unexpected game\n" );
387
- return -1;
388
- }
389
- initState( game, *handId, state );
390
- dealCards( game, rng, state );
391
-
392
- return 0;
393
- }
394
-
395
- /* returns >= 0 if match should continue, -1 for failure */
396
- static int processTransactionFile( const Game *game, const int fixedSeats,
397
- uint32_t *handId, uint8_t *player0Seat,
398
- rng_state_t *rng, ErrorInfo *errorInfo,
399
- double totalValue[ MAX_PLAYERS ],
400
- MatchState *state, FILE *file )
401
- {
402
- int c, r;
403
- uint32_t h;
404
- uint8_t s;
405
- Action action;
406
- struct timeval sendTime, recvTime;
407
- char line[ MAX_LINE_LEN ];
408
-
409
- while( fgets( line, MAX_LINE_LEN, file ) ) {
410
-
411
- /* get the log entry */
412
-
413
- /* ACTION */
414
- c = readAction( line, game, &action );
415
- if( c < 0 ) {
416
-
417
- fprintf( stderr, "ERROR: could not parse transaction action %s", line );
418
- return -1;
419
- }
420
-
421
- /* ACTION HANDID SEND RECV */
422
- if( sscanf( &line[ c ], " %"SCNu32" %zu.%06zu %zu.%06zu%n", &h,
423
- &sendTime.tv_sec, &sendTime.tv_usec,
424
- &recvTime.tv_sec, &recvTime.tv_usec, &r ) < 4 ) {
425
-
426
- fprintf( stderr, "ERROR: could not parse transaction stamp %s", line );
427
- return -1;
428
- }
429
- c += r;
430
-
431
- /* check that we're processing the expected handId */
432
- if( h != *handId ) {
433
-
434
- fprintf( stderr, "ERROR: handId mismatch in transaction log: %s", line );
435
- return -1;
436
- }
437
-
438
- /* make sure the action is valid */
439
- if( !isValidAction( game, &state->state, 0, &action ) ) {
440
-
441
- fprintf( stderr, "ERROR: invalid action in transaction log: %s", line );
442
- return -1;
443
- }
444
-
445
- /* check for any timeout issues */
446
- s = playerToSeat( game, *player0Seat,
447
- currentPlayer( game, &state->state ) );
448
- if( checkErrorTimes( s, &sendTime, &recvTime, errorInfo ) < 0 ) {
449
-
450
- fprintf( stderr,
451
- "ERROR: seat %"PRIu8" ran out of time in transaction file\n",
452
- s + 1 );
453
- return -1;
454
- }
455
-
456
- doAction( game, &action, &state->state );
457
-
458
- if( stateFinished( &state->state ) ) {
459
- /* hand is finished */
460
-
461
- /* update the total value for each player */
462
- for( s = 0; s < game->numPlayers; ++s ) {
463
-
464
- totalValue[ s ]
465
- += valueOfState( game, &state->state,
466
- seatToPlayer( game, *player0Seat, s ) );
467
- }
468
-
469
- /* move on to next hand */
470
- if( setUpNewHand( game, fixedSeats, handId, player0Seat,
471
- rng, errorInfo, &state->state ) < 0 ) {
472
-
473
- return -1;
474
- }
475
- }
476
- }
477
-
478
- return 0;
479
- }
480
-
481
- /* returns >= 0 if match should continue, -1 on failure */
482
- static int logTransaction( const Game *game, const State *state,
483
- const Action *action,
484
- const struct timeval *sendTime,
485
- const struct timeval *recvTime,
486
- FILE *file )
487
- {
488
- int c, r;
489
- char line[ MAX_LINE_LEN ];
490
-
491
- c = printAction( game, action, MAX_LINE_LEN, line );
492
- if( c < 0 ) {
493
-
494
- fprintf( stderr, "ERROR: transaction message too long\n" );
495
- return -1;
496
- }
497
-
498
- r = snprintf( &line[ c ], MAX_LINE_LEN - c,
499
- " %"PRIu32" %zu.%06zu %zu.%06zu\n",
500
- state->handId, sendTime->tv_sec, sendTime->tv_usec,
501
- recvTime->tv_sec, recvTime->tv_usec );
502
- if( r < 0 ) {
503
-
504
- fprintf( stderr, "ERROR: transaction message too long\n" );
505
- return -1;
506
- }
507
- c += r;
508
-
509
- if( fwrite( line, 1, c, file ) != c ) {
510
-
511
- fprintf( stderr, "ERROR: could not write to transaction file\n" );
512
- return -1;
513
- }
514
- fflush( file );
515
-
516
- return c;
517
- }
518
-
519
- /* returns >= 0 if match should continue, -1 on failure */
520
- static int checkVersion( const uint8_t seat,
521
- ReadBuf *readBuf )
522
- {
523
- uint32_t major, minor, rev;
524
- char line[ MAX_LINE_LEN ];
525
-
526
-
527
- if( getLine( readBuf, MAX_LINE_LEN, line, -1 ) <= 0 ) {
528
-
529
- fprintf( stderr,
530
- "ERROR: could not read version string from seat %"PRIu8"\n",
531
- seat + 1 );
532
- return -1;
533
- }
534
-
535
- if( sscanf( line, "VERSION:%"SCNu32".%"SCNu32".%"SCNu32,
536
- &major, &minor, &rev ) < 3 ) {
537
-
538
- fprintf( stderr,
539
- "ERROR: invalid version string %s", line );
540
- return -1;
541
- }
542
-
543
- if( major != VERSION_MAJOR || minor > VERSION_MINOR ) {
544
-
545
- fprintf( stderr, "ERROR: this server is currently using version %"SCNu32".%"SCNu32".%"SCNu32"\n", VERSION_MAJOR, VERSION_MINOR, VERSION_REVISION );
546
- }
547
-
548
- return 0;
549
- }
550
-
551
- /* returns >= 0 if match should continue, -1 on failure */
552
- static int addToLogFile( const Game *game, const State *state,
553
- const double value[ MAX_PLAYERS ],
554
- const uint8_t player0Seat,
555
- char *seatName[ MAX_PLAYERS ], FILE *logFile )
556
- {
557
- int c, r;
558
- uint8_t p;
559
- char line[ MAX_LINE_LEN ];
560
-
561
- /* prepare the message */
562
- c = printState( game, state, MAX_LINE_LEN, line );
563
- if( c < 0 ) {
564
- /* message is too long */
565
-
566
- fprintf( stderr, "ERROR: log state message too long\n" );
567
- return -1;
568
- }
569
-
570
- /* add the values */
571
- for( p = 0; p < game->numPlayers; ++p ) {
572
-
573
- r = snprintf( &line[ c ], MAX_LINE_LEN - c,
574
- p ? "|%.6f" : ":%.6f", value[ p ] );
575
- if( r < 0 ) {
576
-
577
- fprintf( stderr, "ERROR: log message too long\n" );
578
- return -1;
579
- }
580
- c += r;
581
-
582
- /* remove trailing zeros after decimal-point */
583
- while( line[ c - 1 ] == '0' ) { --c; }
584
- if( line[ c - 1 ] == '.' ) { --c; }
585
- line[ c ] = 0;
586
- }
587
-
588
- /* add the player names */
589
- for( p = 0; p < game->numPlayers; ++p ) {
590
-
591
- r = snprintf( &line[ c ], MAX_LINE_LEN - c,
592
- p ? "|%s" : ":%s",
593
- seatName[ playerToSeat( game, player0Seat, p ) ] );
594
- if( r < 0 ) {
595
-
596
- fprintf( stderr, "ERROR: log message too long\n" );
597
- return -1;
598
- }
599
- c += r;
600
- }
601
-
602
- /* print the line to log and flush */
603
- if( fprintf( logFile, "%s\n", line ) < 0 ) {
604
-
605
- fprintf( stderr, "ERROR: logging failed for game %s\n", line );
606
- return -1;
607
- }
608
- fflush( logFile );
609
-
610
- return 0;
611
- }
612
-
613
- /* returns >= 0 if match should continue, -1 on failure */
614
- static int printInitialMessage( const char *matchName, const char *gameName,
615
- const uint32_t numHands, const uint32_t seed,
616
- const ErrorInfo *info, FILE *logFile )
617
- {
618
- int c;
619
- char line[ MAX_LINE_LEN ];
620
-
621
- c = snprintf( line, MAX_LINE_LEN, "# name/game/hands/seed %s %s %"PRIu32" %"PRIu32"\n#--t_response %"PRIu64"\n#--t_hand %"PRIu64"\n#--t_per_hand %"PRIu64"\n",
622
- matchName, gameName, numHands, seed,
623
- info->maxResponseMicros / 1000,
624
- info->maxUsedHandMicros / 1000,
625
- info->maxUsedMatchMicros / numHands / 1000 );
626
- if( c < 0 ) {
627
- /* message is too long */
628
-
629
- fprintf( stderr, "ERROR: initial game comment too long\n" );
630
- return -1;
631
- }
632
-
633
- fprintf( stderr, "%s", line );
634
- if( logFile ) {
635
-
636
- fprintf( logFile, "%s", line );
637
- }
638
-
639
- return 0;
640
- }
641
-
642
- /* returns >= 0 if match should continue, -1 on failure */
643
- static int printFinalMessage( const Game *game, char *seatName[ MAX_PLAYERS ],
644
- const double totalValue[ MAX_PLAYERS ],
645
- FILE *logFile )
646
- {
647
- int c, r;
648
- uint8_t s;
649
- char line[ MAX_LINE_LEN ];
650
-
651
- c = snprintf( line, MAX_LINE_LEN, "SCORE" );
652
- if( c < 0 ) {
653
- /* message is too long */
654
-
655
- fprintf( stderr, "ERROR: value state message too long\n" );
656
- return -1;
657
- }
658
-
659
- for( s = 0; s < game->numPlayers; ++s ) {
660
-
661
- r = snprintf( &line[ c ], MAX_LINE_LEN - c,
662
- s ? "|%.6f" : ":%.6f", totalValue[ s ] );
663
- if( r < 0 ) {
664
-
665
- fprintf( stderr, "ERROR: value message too long\n" );
666
- return -1;
667
- }
668
- c += r;
669
-
670
- /* remove trailing zeros after decimal-point */
671
- while( line[ c - 1 ] == '0' ) { --c; }
672
- if( line[ c - 1 ] == '.' ) { --c; }
673
- line[ c ] = 0;
674
- }
675
-
676
- /* add the player names */
677
- for( s = 0; s < game->numPlayers; ++s ) {
678
-
679
- r = snprintf( &line[ c ], MAX_LINE_LEN - c,
680
- s ? "|%s" : ":%s", seatName[ s ] );
681
- if( r < 0 ) {
682
-
683
- fprintf( stderr, "ERROR: log message too long\n" );
684
- return -1;
685
- }
686
- c += r;
687
- }
688
-
689
- fprintf( stdout, "%s\n", line );
690
- fprintf( stderr, "%s\n", line );
691
-
692
- if( logFile ) {
693
-
694
- fprintf( logFile, "%s\n", line );
695
- }
696
-
697
- return 0;
698
- }
699
-
700
- /* run a match of numHands hands of the supplied game
701
-
702
- cards are dealt using rng, error conditions like timeouts
703
- are controlled and stored in errorInfo
704
-
705
- actions are read/sent to seat p on seatFD[ p ]
706
-
707
- if quiet is not zero, only print out errors, warnings, and final value
708
-
709
- if logFile is not NULL, print out a single line for each completed
710
- match with the final state and all player values. The values are
711
- printed in player, not seat order.
712
-
713
- if transactionFile is not NULL, a transaction log of actions made
714
- is written to the file, and if there is any input left to read on
715
- the stream when gameLoop is called, it will be processed to
716
- initialise the state
717
-
718
- returns >=0 if the match finished correctly, -1 on error */
719
- static int gameLoop( const Game *game, char *seatName[ MAX_PLAYERS ],
720
- const uint32_t numHands, const int quiet,
721
- const int fixedSeats, rng_state_t *rng,
722
- ErrorInfo *errorInfo, const int seatFD[ MAX_PLAYERS ],
723
- ReadBuf *readBuf[ MAX_PLAYERS ],
724
- FILE *logFile, FILE *transactionFile )
725
- {
726
- uint32_t handId;
727
- uint8_t seat, p, player0Seat, currentP, currentSeat;
728
- struct timeval t, sendTime, recvTime;
729
- Action action;
730
- MatchState state;
731
- double value[ MAX_PLAYERS ], totalValue[ MAX_PLAYERS ];
732
-
733
- /* check version string for each player */
734
- for( seat = 0; seat < game->numPlayers; ++seat ) {
735
-
736
- if( checkVersion( seat, readBuf[ seat ] ) < 0 ) {
737
- /* error messages already handled in function */
738
-
739
- return -1;
740
- }
741
- }
742
-
743
- gettimeofday( &sendTime, NULL );
744
- if( !quiet ) {
745
- fprintf( stderr, "STARTED at %zu.%06zu\n",
746
- sendTime.tv_sec, sendTime.tv_usec );
747
- }
748
-
749
- /* start at the first hand */
750
- handId = 0;
751
- if( checkErrorNewHand( game, errorInfo ) < 0 ) {
752
-
753
- fprintf( stderr, "ERROR: unexpected game\n" );
754
- return -1;
755
- }
756
- initState( game, handId, &state.state );
757
- dealCards( game, rng, &state.state );
758
- for( seat = 0; seat < game->numPlayers; ++seat ) {
759
- totalValue[ seat ] = 0.0;
760
- }
761
-
762
- /* seat 0 is player 0 in first game */
763
- player0Seat = 0;
764
-
765
- /* process the transaction file */
766
- if( transactionFile != NULL ) {
767
-
768
- if( processTransactionFile( game, fixedSeats, &handId, &player0Seat,
769
- rng, errorInfo, totalValue,
770
- &state, transactionFile ) < 0 ) {
771
- /* error messages already handled in function */
772
-
773
- return -1;
774
- }
775
- }
776
-
777
- if( handId >= numHands ) {
778
- goto finishedGameLoop;
779
- }
780
-
781
- /* play all the (remaining) hands */
782
- while( 1 ) {
783
-
784
- /* play the hand */
785
- while( !stateFinished( &state.state ) ) {
786
-
787
- /* find the current player */
788
- currentP = currentPlayer( game, &state.state );
789
-
790
- /* send state to each player */
791
- for( seat = 0; seat < game->numPlayers; ++seat ) {
792
-
793
- state.viewingPlayer = seatToPlayer( game, player0Seat, seat );
794
- if( sendPlayerMessage( game, &state, quiet, seat,
795
- seatFD[ seat ], &t ) < 0 ) {
796
- /* error messages already handled in function */
797
-
798
- return -1;
799
- }
800
-
801
- /* remember the seat and send time if player is acting */
802
- if( state.viewingPlayer == currentP ) {
803
-
804
- sendTime = t;
805
- }
806
- }
807
-
808
- /* get action from current player */
809
- state.viewingPlayer = currentP;
810
- currentSeat = playerToSeat( game, player0Seat, currentP );
811
- if( readPlayerResponse( game, &state, quiet, currentSeat, &sendTime,
812
- errorInfo, readBuf[ currentSeat ],
813
- &action, &recvTime ) < 0 ) {
814
- /* error messages already handled in function */
815
-
816
- return -1;
817
- }
818
-
819
- /* log the transaction */
820
- if( transactionFile != NULL ) {
821
-
822
- if( logTransaction( game, &state.state, &action,
823
- &sendTime, &recvTime, transactionFile ) < 0 ) {
824
- /* error messages already handled in function */
825
-
826
- return -1;
827
- }
828
- }
829
-
830
- /* do the action */
831
- doAction( game, &action, &state.state );
832
- }
833
-
834
- /* get values */
835
- for( p = 0; p < game->numPlayers; ++p ) {
836
-
837
- value[ p ] = valueOfState( game, &state.state, p );
838
- totalValue[ playerToSeat( game, player0Seat, p ) ] += value[ p ];
839
- }
840
-
841
- /* add the game to the log */
842
- if( logFile != NULL ) {
843
-
844
- if( addToLogFile( game, &state.state, value, player0Seat,
845
- seatName, logFile ) < 0 ) {
846
- /* error messages already handled in function */
847
-
848
- return -1;
849
- }
850
- }
851
-
852
- /* send final state to each player */
853
- for( seat = 0; seat < game->numPlayers; ++seat ) {
854
-
855
- state.viewingPlayer = seatToPlayer( game, player0Seat, seat );
856
- if( sendPlayerMessage( game, &state, quiet, seat,
857
- seatFD[ seat ], &t ) < 0 ) {
858
- /* error messages already handled in function */
859
-
860
- return -1;
861
- }
862
- }
863
-
864
- if ( !quiet ) {
865
- if ( handId % 100 == 0) {
866
- for( seat = 0; seat < game->numPlayers; ++seat ) {
867
- fprintf(stderr, "Seconds cumulatively spent in match for seat %i: "
868
- "%i\n", seat,
869
- (int)(errorInfo->usedMatchMicros[ seat ] / 1000000));
870
- }
871
- }
872
- }
873
-
874
- /* start a new hand */
875
- if( setUpNewHand( game, fixedSeats, &handId, &player0Seat,
876
- rng, errorInfo, &state.state ) < 0 ) {
877
- /* error messages already handled in function */
878
-
879
- return -1;
880
- }
881
- if( handId >= numHands ) {
882
- break;
883
- }
884
- }
885
-
886
- finishedGameLoop:
887
- /* print out the final values */
888
- if( !quiet ) {
889
- gettimeofday( &t, NULL );
890
- fprintf( stderr, "FINISHED at %zu.%06zu\n",
891
- sendTime.tv_sec, sendTime.tv_usec );
892
- }
893
- if( printFinalMessage( game, seatName, totalValue, logFile ) < 0 ) {
894
- /* error messages already handled in function */
895
-
896
- return -1;
897
- }
898
-
899
- return 0;
900
- }
901
-
902
- int main( int argc, char **argv )
903
- {
904
- int i, listenSocket[ MAX_PLAYERS ], v, longOpt;
905
- int fixedSeats, quiet, append;
906
- int seatFD[ MAX_PLAYERS ];
907
- FILE *file, *logFile, *transactionFile;
908
- ReadBuf *readBuf[ MAX_PLAYERS ];
909
- Game *game;
910
- rng_state_t rng;
911
- ErrorInfo errorInfo;
912
- struct sockaddr_in addr;
913
- socklen_t addrLen;
914
- char *seatName[ MAX_PLAYERS ];
915
-
916
- int useLogFile, useTransactionFile;
917
- uint64_t maxResponseMicros, maxUsedHandMicros, maxUsedPerHandMicros;
918
- int64_t startTimeoutMicros;
919
- uint32_t numHands, seed, maxInvalidActions;
920
- uint16_t listenPort[ MAX_PLAYERS ];
921
-
922
- struct timeval startTime, tv;
923
-
924
- char name[ MAX_LINE_LEN ];
925
- static struct option longOptions[] = {
926
- { "t_response", 1, 0, 0 },
927
- { "t_hand", 1, 0, 0 },
928
- { "t_per_hand", 1, 0, 0 },
929
- { "start_timeout", 1, 0, 0 },
930
- { 0, 0, 0, 0 }
931
- };
932
-
933
- /* set defaults */
934
-
935
- /* game error conditions */
936
- maxInvalidActions = DEFAULT_MAX_INVALID_ACTIONS;
937
- maxResponseMicros = DEFAULT_MAX_RESPONSE_MICROS;
938
- maxUsedHandMicros = DEFAULT_MAX_USED_HAND_MICROS;
939
- maxUsedPerHandMicros = DEFAULT_MAX_USED_PER_HAND_MICROS;
940
-
941
- /* use random ports */
942
- for( i = 0; i < MAX_PLAYERS; ++i ) {
943
-
944
- listenPort[ i ] = 0;
945
- }
946
-
947
- /* use log file, don't use transaction file */
948
- useLogFile = 1;
949
- useTransactionFile = 0;
950
-
951
- /* print all messages */
952
- quiet = 0;
953
-
954
- /* by default, overwrite preexisting log/transaction files */
955
- append = 0;
956
-
957
- /* players rotate around the table */
958
- fixedSeats = 0;
959
-
960
- /* no timeout on startup */
961
- startTimeoutMicros = -1;
962
-
963
- /* parse options */
964
- while( 1 ) {
965
-
966
- i = getopt_long( argc, argv, "flLp:qtTa", longOptions, &longOpt );
967
- if( i < 0 ) {
968
-
969
- break;
970
- }
971
-
972
- switch( i ) {
973
- case 0:
974
- /* long option longOpt */
975
-
976
- switch( longOpt ) {
977
- case 0:
978
- /* t_response */
979
-
980
- if( sscanf( optarg, "%"SCNu64, &maxResponseMicros ) < 1 ) {
981
-
982
- fprintf( stderr, "ERROR: could not get response timeout from %s\n",
983
- optarg );
984
- exit( EXIT_FAILURE );
985
- }
986
-
987
- /* convert from milliseconds to microseconds */
988
- maxResponseMicros *= 1000;
989
- break;
990
-
991
- case 1:
992
- /* t_hand */
993
-
994
- if( sscanf( optarg, "%"SCNu64, &maxUsedHandMicros ) < 1 ) {
995
-
996
- fprintf( stderr,
997
- "ERROR: could not get player hand timeout from %s\n",
998
- optarg );
999
- exit( EXIT_FAILURE );
1000
- }
1001
-
1002
- /* convert from milliseconds to microseconds */
1003
- maxUsedHandMicros *= 1000;
1004
- break;
1005
-
1006
- case 2:
1007
- /* t_per_hand */
1008
-
1009
- if( sscanf( optarg, "%"SCNu64, &maxUsedPerHandMicros ) < 1 ) {
1010
-
1011
- fprintf( stderr, "ERROR: could not get average player hand timeout from %s\n", optarg );
1012
- exit( EXIT_FAILURE );
1013
- }
1014
-
1015
- /* convert from milliseconds to microseconds */
1016
- maxUsedPerHandMicros *= 1000;
1017
- break;
1018
-
1019
- case 3:
1020
- /* start_timeout */
1021
-
1022
- if( sscanf( optarg, "%"SCNd64, &startTimeoutMicros ) < 1 ) {
1023
-
1024
- fprintf( stderr, "ERROR: could not get start timeout %s\n", optarg );
1025
- exit( EXIT_FAILURE );
1026
- }
1027
-
1028
- /* convert from milliseconds to microseconds */
1029
- if( startTimeoutMicros > 0 ) {
1030
-
1031
- startTimeoutMicros *= 1000;
1032
- }
1033
- break;
1034
-
1035
- }
1036
- break;
1037
-
1038
- case 'f':
1039
- /* fix the player seats */;
1040
-
1041
- fixedSeats = 1;
1042
- break;
1043
-
1044
- case 'l':
1045
- /* no transactionFile */;
1046
-
1047
- useLogFile = 0;
1048
- break;
1049
-
1050
- case 'L':
1051
- /* use transactionFile */;
1052
-
1053
- useLogFile = 1;
1054
- break;
1055
-
1056
- case 'p':
1057
- /* port specification */
1058
-
1059
- if( scanPortString( optarg, listenPort ) < 0 ) {
1060
-
1061
- fprintf( stderr, "ERROR: bad port string %s\n", optarg );
1062
- exit( EXIT_FAILURE );
1063
- }
1064
-
1065
- break;
1066
-
1067
- case 'q':
1068
-
1069
- quiet = 1;
1070
- break;
1071
-
1072
- case 't':
1073
- /* no transactionFile */
1074
-
1075
- useTransactionFile = 0;
1076
- break;
1077
-
1078
- case 'T':
1079
- /* use transactionFile */
1080
-
1081
- useTransactionFile = 1;
1082
- break;
1083
-
1084
- case 'a':
1085
-
1086
- append = 1;
1087
- break;
1088
-
1089
- default:
1090
-
1091
- fprintf( stderr, "ERROR: unknown option %c\n", i );
1092
- exit( EXIT_FAILURE );
1093
- }
1094
- }
1095
-
1096
- if( optind + 4 > argc ) {
1097
-
1098
- printUsage( stdout, 0 );
1099
- exit( EXIT_FAILURE );
1100
- }
1101
-
1102
- /* get the game definition */
1103
- file = fopen( argv[ optind + 1 ], "r" );
1104
- if( file == NULL ) {
1105
-
1106
- fprintf( stderr, "ERROR: could not open game definition %s\n",
1107
- argv[ optind + 1 ] );
1108
- exit( EXIT_FAILURE );
1109
- }
1110
- game = readGame( file );
1111
- if( game == NULL ) {
1112
-
1113
- fprintf( stderr, "ERROR: could not read game %s\n", argv[ optind + 1 ] );
1114
- exit( EXIT_FAILURE );
1115
- }
1116
- fclose( file );
1117
-
1118
- /* save the seat names */
1119
- if( optind + 4 + game->numPlayers > argc ) {
1120
-
1121
- printUsage( stdout, 0 );
1122
- exit( EXIT_FAILURE );
1123
- }
1124
- for( i = 0; i < game->numPlayers; ++i ) {
1125
-
1126
- seatName[ i ] = argv[ optind + 4 + i ];
1127
- }
1128
-
1129
- /* get number of hands */
1130
- if( sscanf( argv[ optind + 2 ], "%"SCNu32, &numHands ) < 1
1131
- || numHands == 0 ) {
1132
-
1133
- fprintf( stderr, "ERROR: invalid number of hands %s\n",
1134
- argv[ optind + 2 ] );
1135
- exit( EXIT_FAILURE );
1136
- }
1137
-
1138
- /* get random number seed */
1139
- if( sscanf( argv[ optind + 3 ], "%"SCNu32, &seed ) < 1 ) {
1140
-
1141
- fprintf( stderr, "ERROR: invalid random number seed %s\n",
1142
- argv[ optind + 3 ] );
1143
- exit( EXIT_FAILURE );
1144
- }
1145
- init_genrand( &rng, seed );
1146
- srandom( seed ); /* used for random port selection */
1147
-
1148
- if( useLogFile ) {
1149
- /* create/open the log */
1150
- if( snprintf( name, MAX_LINE_LEN, "%s.log", argv[ optind ] ) < 0 ) {
1151
-
1152
- fprintf( stderr, "ERROR: match file name too long %s\n", argv[ optind ] );
1153
- exit( EXIT_FAILURE );
1154
- }
1155
- if (append) {
1156
- logFile = fopen( name, "a+" );
1157
- } else {
1158
- logFile = fopen( name, "w" );
1159
- }
1160
- if( logFile == NULL ) {
1161
-
1162
- fprintf( stderr, "ERROR: could not open log file %s\n", name );
1163
- exit( EXIT_FAILURE );
1164
- }
1165
- } else {
1166
- /* no log file */
1167
-
1168
- logFile = NULL;
1169
- }
1170
-
1171
- if( useTransactionFile ) {
1172
- /* create/open the transaction log */
1173
-
1174
- if( snprintf( name, MAX_LINE_LEN, "%s.tlog", argv[ optind ] ) < 0 ) {
1175
-
1176
- fprintf( stderr, "ERROR: match file name too long %s\n", argv[ optind ] );
1177
- exit( EXIT_FAILURE );
1178
- }
1179
- if (append) {
1180
- transactionFile = fopen( name, "a+" );
1181
- } else {
1182
- transactionFile = fopen( name, "w" );
1183
- }
1184
- if( transactionFile == NULL ) {
1185
-
1186
- fprintf( stderr, "ERROR: could not open transaction file %s\n", name );
1187
- exit( EXIT_FAILURE );
1188
- }
1189
- } else {
1190
- /* no transaction file */
1191
-
1192
- transactionFile = NULL;
1193
- }
1194
-
1195
- /* set up the error info */
1196
- initErrorInfo( maxInvalidActions, maxResponseMicros, maxUsedHandMicros,
1197
- maxUsedPerHandMicros * numHands, &errorInfo );
1198
-
1199
- /* open sockets for players to connect to */
1200
- for( i = 0; i < game->numPlayers; ++i ) {
1201
-
1202
- listenSocket[ i ] = getListenSocket( &listenPort[ i ] );
1203
- if( listenSocket[ i ] < 0 ) {
1204
-
1205
- fprintf( stderr, "ERROR: could not create listen socket for player %d\n",
1206
- i + 1 );
1207
- exit( EXIT_FAILURE );
1208
- }
1209
- }
1210
-
1211
- /* print out the final port assignments */
1212
- for( i = 0; i < game->numPlayers; ++i ) {
1213
-
1214
- printf( i ? " %"PRIu16 : "%"PRIu16, listenPort[ i ] );
1215
- }
1216
- printf( "\n" );
1217
- fflush( stdout );
1218
-
1219
- /* print out usage information */
1220
- printInitialMessage( argv[ optind ], argv[ optind + 1 ],
1221
- numHands, seed, &errorInfo, logFile );
1222
-
1223
- /* wait for each player to connect */
1224
- gettimeofday( &startTime, NULL );
1225
- for( i = 0; i < game->numPlayers; ++i ) {
1226
-
1227
- if( startTimeoutMicros >= 0 ) {
1228
- uint64_t startTimeLeft;
1229
- fd_set fds;
1230
-
1231
- gettimeofday( &tv, NULL );
1232
- startTimeLeft = startTimeoutMicros
1233
- - (uint64_t)( tv.tv_sec - startTime.tv_sec ) * 1000000
1234
- - ( tv.tv_usec - startTime.tv_usec );
1235
- if( startTimeLeft < 0 ) {
1236
-
1237
- startTimeLeft = 0;
1238
- }
1239
- tv.tv_sec = startTimeLeft / 1000000;
1240
- tv.tv_usec = startTimeLeft % 1000000;
1241
-
1242
- FD_ZERO( &fds );
1243
- FD_SET( listenSocket[ i ], &fds );
1244
- if( select( listenSocket[ i ] + 1, &fds, NULL, NULL, &tv ) < 1 ) {
1245
- /* no input ready within time, or an actual error */
1246
-
1247
- fprintf( stderr, "ERROR: timed out waiting for seat %d to connect\n",
1248
- i + 1 );
1249
- exit( EXIT_FAILURE );
1250
- }
1251
- }
1252
-
1253
- addrLen = sizeof( addr );
1254
- seatFD[ i ] = accept( listenSocket[ i ],
1255
- (struct sockaddr *)&addr, &addrLen );
1256
- if( seatFD[ i ] < 0 ) {
1257
-
1258
- fprintf( stderr, "ERROR: seat %d could not connect\n", i + 1 );
1259
- exit( EXIT_FAILURE );
1260
- }
1261
- close( listenSocket[ i ] );
1262
-
1263
- v = 1;
1264
- setsockopt( seatFD[ i ], IPPROTO_TCP, TCP_NODELAY,
1265
- (char *)&v, sizeof(int) );
1266
-
1267
- readBuf[ i ] = createReadBuf( seatFD[ i ] );
1268
- }
1269
-
1270
- /* play the match */
1271
- if( gameLoop( game, seatName, numHands, quiet, fixedSeats, &rng, &errorInfo,
1272
- seatFD, readBuf, logFile, transactionFile ) < 0 ) {
1273
- /* should have already printed an error message */
1274
-
1275
- exit( EXIT_FAILURE );
1276
- }
1277
-
1278
- //fflush( stderr );
1279
- //fflush( stdout );
1280
- // Otherwise the last line or two of the log file
1281
- // won't be written sometimes when run through a
1282
- // Ruby interface.
1283
- fflush(NULL);
1284
- if( transactionFile != NULL ) {
1285
- fclose( transactionFile );
1286
- }
1287
- if( logFile != NULL ) {
1288
- fclose( logFile );
1289
- }
1290
- free( game );
1291
-
1292
- return EXIT_SUCCESS;
1293
- }