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,1793 @@
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
+ #include <string.h>
8
+ #include <ctype.h>
9
+ #include <assert.h>
10
+ #define __STDC_LIMIT_MACROS
11
+ #include <stdint.h>
12
+ #include "game.h"
13
+ #include "rng.h"
14
+
15
+ #include "evalHandTables"
16
+
17
+
18
+ static enum ActionType charToAction[ 256 ] = {
19
+ /* 0x0X */
20
+ a_invalid, a_invalid, a_invalid, a_invalid,
21
+ a_invalid, a_invalid, a_invalid, a_invalid,
22
+ a_invalid, a_invalid, a_invalid, a_invalid,
23
+ a_invalid, a_invalid, a_invalid, a_invalid,
24
+ /* 0x1X */
25
+ a_invalid, a_invalid, a_invalid, a_invalid,
26
+ a_invalid, a_invalid, a_invalid, a_invalid,
27
+ a_invalid, a_invalid, a_invalid, a_invalid,
28
+ a_invalid, a_invalid, a_invalid, a_invalid,
29
+ /* 0x2X */
30
+ a_invalid, a_invalid, a_invalid, a_invalid,
31
+ a_invalid, a_invalid, a_invalid, a_invalid,
32
+ a_invalid, a_invalid, a_invalid, a_invalid,
33
+ a_invalid, a_invalid, a_invalid, a_invalid,
34
+ /* 0x3X */
35
+ a_invalid, a_invalid, a_invalid, a_invalid,
36
+ a_invalid, a_invalid, a_invalid, a_invalid,
37
+ a_invalid, a_invalid, a_invalid, a_invalid,
38
+ a_invalid, a_invalid, a_invalid, a_invalid,
39
+ /* 0x4X */
40
+ a_invalid, a_invalid, a_raise, a_call,
41
+ a_invalid, a_invalid, a_fold, a_invalid,
42
+ a_invalid, a_invalid, a_invalid, a_call,
43
+ a_invalid, a_invalid, a_invalid, a_invalid,
44
+ /* 0x5X */
45
+ a_invalid, a_invalid, a_raise, a_invalid,
46
+ a_invalid, a_invalid, a_invalid, a_invalid,
47
+ a_invalid, a_invalid, a_invalid, a_invalid,
48
+ a_invalid, a_invalid, a_invalid, a_invalid,
49
+ /* 0x6X */
50
+ a_invalid, a_invalid, a_raise, a_call,
51
+ a_invalid, a_invalid, a_fold, a_invalid,
52
+ a_invalid, a_invalid, a_invalid, a_call,
53
+ a_invalid, a_invalid, a_invalid, a_invalid,
54
+ /* 0x7X */
55
+ a_invalid, a_invalid, a_raise, a_invalid,
56
+ a_invalid, a_invalid, a_invalid, a_invalid,
57
+ a_invalid, a_invalid, a_invalid, a_invalid,
58
+ a_invalid, a_invalid, a_invalid, a_invalid,
59
+ /* 0x8X */
60
+ a_invalid, a_invalid, a_invalid, a_invalid,
61
+ a_invalid, a_invalid, a_invalid, a_invalid,
62
+ a_invalid, a_invalid, a_invalid, a_invalid,
63
+ a_invalid, a_invalid, a_invalid, a_invalid,
64
+ /* 0x9X */
65
+ a_invalid, a_invalid, a_invalid, a_invalid,
66
+ a_invalid, a_invalid, a_invalid, a_invalid,
67
+ a_invalid, a_invalid, a_invalid, a_invalid,
68
+ a_invalid, a_invalid, a_invalid, a_invalid,
69
+ /* 0xAX */
70
+ a_invalid, a_invalid, a_invalid, a_invalid,
71
+ a_invalid, a_invalid, a_invalid, a_invalid,
72
+ a_invalid, a_invalid, a_invalid, a_invalid,
73
+ a_invalid, a_invalid, a_invalid, a_invalid,
74
+ /* 0xBX */
75
+ a_invalid, a_invalid, a_invalid, a_invalid,
76
+ a_invalid, a_invalid, a_invalid, a_invalid,
77
+ a_invalid, a_invalid, a_invalid, a_invalid,
78
+ a_invalid, a_invalid, a_invalid, a_invalid,
79
+ /* 0xCX */
80
+ a_invalid, a_invalid, a_invalid, a_invalid,
81
+ a_invalid, a_invalid, a_invalid, a_invalid,
82
+ a_invalid, a_invalid, a_invalid, a_invalid,
83
+ a_invalid, a_invalid, a_invalid, a_invalid,
84
+ /* 0xDX */
85
+ a_invalid, a_invalid, a_invalid, a_invalid,
86
+ a_invalid, a_invalid, a_invalid, a_invalid,
87
+ a_invalid, a_invalid, a_invalid, a_invalid,
88
+ a_invalid, a_invalid, a_invalid, a_invalid,
89
+ /* 0xEX */
90
+ a_invalid, a_invalid, a_invalid, a_invalid,
91
+ a_invalid, a_invalid, a_invalid, a_invalid,
92
+ a_invalid, a_invalid, a_invalid, a_invalid,
93
+ a_invalid, a_invalid, a_invalid, a_invalid,
94
+ /* 0xFX */
95
+ a_invalid, a_invalid, a_invalid, a_invalid,
96
+ a_invalid, a_invalid, a_invalid, a_invalid,
97
+ a_invalid, a_invalid, a_invalid, a_invalid,
98
+ a_invalid, a_invalid, a_invalid, a_invalid
99
+ };
100
+
101
+ static char actionChars[ a_invalid +1 ] = "fcr";
102
+
103
+ static char suitChars[ MAX_SUITS +1] = "cdhs";
104
+ static char rankChars[ MAX_RANKS +1] = "23456789TJQKA";
105
+
106
+
107
+ static int consumeSpaces( const char *string, int consumeEqual )
108
+ {
109
+ int i;
110
+
111
+ for( i = 0; string[ i ] != 0
112
+ && ( isspace( string[ i ] )
113
+ || ( consumeEqual && string[ i ] == '=' ) );
114
+ ++i ) {
115
+ }
116
+
117
+ return i;
118
+ }
119
+
120
+ /* reads up to numItems with scanf format itemFormat from string,
121
+ returning item i in *items[ i ]
122
+ ignore the '=' character if consumeEqual is non-zero
123
+ returns the number of characters consumed doing this in charsConsumed
124
+ returns the number of items read */
125
+ static int readItems( const char *itemFormat, const int numItems,
126
+ const char *string, const int consumeEqual,
127
+ void *items, const size_t itemSize,
128
+ int *charsConsumed )
129
+ {
130
+ int i, c, r;
131
+ char *fmt;
132
+
133
+ i = strlen( itemFormat );
134
+ fmt = (char*)malloc( i + 3 );
135
+ assert( fmt != 0 );
136
+ strcpy( fmt, itemFormat );
137
+ fmt[ i ] = '%';
138
+ fmt[ i + 1 ] = 'n';
139
+ fmt[ i + 2 ] = 0;
140
+
141
+ c = 0;
142
+ for( i = 0; i < numItems; ++i ) {
143
+
144
+ c += consumeSpaces( &string[ c ], consumeEqual );
145
+ if( sscanf( &string[ c ], fmt, items + i * itemSize, &r ) < 1 ) {
146
+ break;
147
+ }
148
+ c += r;
149
+ }
150
+
151
+ free( fmt );
152
+
153
+ *charsConsumed = c;
154
+ return i;
155
+ }
156
+
157
+ Game *readGame( FILE *file )
158
+ {
159
+ int stackRead, blindRead, raiseSizeRead, boardCardsRead, c, t;
160
+ char line[ MAX_LINE_LEN ];
161
+ Game *game;
162
+
163
+ game = (Game*)malloc( sizeof( *game ) );
164
+ assert( game != 0 );
165
+ stackRead = 4;
166
+ for( c = 0; c < MAX_ROUNDS; ++c ) {
167
+ game->stack[ c ] = INT32_MAX;
168
+ }
169
+ blindRead = 0;
170
+ raiseSizeRead = 0;
171
+ game->bettingType = limitBetting;
172
+ game->numPlayers = 0;
173
+ game->numRounds = 0;
174
+ for( c = 0; c < MAX_ROUNDS; ++c ) {
175
+ game->firstPlayer[ c ] = 1;
176
+ }
177
+ for( c = 0; c < MAX_ROUNDS; ++c ) {
178
+ game->maxRaises[ c ] = UINT8_MAX;
179
+ }
180
+ game->numSuits = 0;
181
+ game->numRanks = 0;
182
+ game->numHoleCards = 0;
183
+ boardCardsRead = 0;
184
+
185
+ while( fgets( line, MAX_LINE_LEN, file ) ) {
186
+
187
+ if( line[ 0 ] == '#' || line[ 0 ] == '\n' ) {
188
+ continue;
189
+ }
190
+
191
+ if( !strncasecmp( line, "end gamedef", 11 ) ) {
192
+
193
+ break;
194
+ } else if( !strncasecmp( line, "gamedef", 7 ) ) {
195
+
196
+ continue;
197
+ } else if( !strncasecmp( line, "stack", 5 ) ) {
198
+
199
+ stackRead = readItems( "%"SCNd32, MAX_PLAYERS, &line[ 5 ],
200
+ 1, game->stack, 4, &c );
201
+ } else if( !strncasecmp( line, "blind", 5 ) ) {
202
+
203
+ blindRead = readItems( "%"SCNd32, MAX_PLAYERS, &line[ 5 ],
204
+ 1, game->blind, 4, &c );
205
+ } else if( !strncasecmp( line, "raisesize", 9 ) ) {
206
+
207
+ raiseSizeRead = readItems( "%"SCNd32, MAX_PLAYERS, &line[ 9 ],
208
+ 1, game->raiseSize, 4, &c );
209
+ } else if( !strncasecmp( line, "limit", 5 ) ) {
210
+
211
+ game->bettingType = limitBetting;
212
+ } else if( !strncasecmp( line, "nolimit", 7 ) ) {
213
+
214
+ game->bettingType = noLimitBetting;
215
+ } else if( !strncasecmp( line, "numplayers", 10 ) ) {
216
+
217
+ readItems( "%"SCNu8, 1, &line[ 10 ], 1, &game->numPlayers, 1, &c );
218
+ } else if( !strncasecmp( line, "numrounds", 9 ) ) {
219
+
220
+ readItems( "%"SCNu8, 1, &line[ 9 ], 1, &game->numRounds, 1, &c );
221
+ } else if( !strncasecmp( line, "firstplayer", 11 ) ) {
222
+
223
+ readItems( "%"SCNu8, MAX_ROUNDS, &line[ 11 ],
224
+ 1, game->firstPlayer, 1, &c );
225
+ } else if( !strncasecmp( line, "maxraises", 9 ) ) {
226
+
227
+ readItems( "%"SCNu8, MAX_ROUNDS, &line[ 9 ],
228
+ 1, game->maxRaises, 1, &c );
229
+ } else if( !strncasecmp( line, "numsuits", 8 ) ) {
230
+
231
+ readItems( "%"SCNu8, 1, &line[ 8 ], 1, &game->numSuits, 1, &c );
232
+ } else if( !strncasecmp( line, "numranks", 8 ) ) {
233
+
234
+ readItems( "%"SCNu8, 1, &line[ 8 ], 1, &game->numRanks, 1, &c );
235
+ } else if( !strncasecmp( line, "numholecards", 12 ) ) {
236
+
237
+ readItems( "%"SCNu8, 1, &line[ 12 ], 1, &game->numHoleCards, 1, &c );
238
+ } else if( !strncasecmp( line, "numboardcards", 13 ) ) {
239
+
240
+ boardCardsRead = readItems( "%"SCNu8, MAX_ROUNDS, &line[ 13 ],
241
+ 1, game->numBoardCards, 1, &c );
242
+ }
243
+ }
244
+
245
+ /* do sanity checks */
246
+ if( game->numRounds == 0 || game->numRounds > MAX_ROUNDS ) {
247
+
248
+ fprintf( stderr, "invalid number of rounds: %"PRIu8"\n", game->numRounds );
249
+ free( game );
250
+ return NULL;
251
+ }
252
+
253
+ if( game->numPlayers < 2 || game->numPlayers > MAX_PLAYERS ) {
254
+
255
+ fprintf( stderr, "invalid number of players: %"PRIu8"\n",
256
+ game->numPlayers );
257
+ free( game );
258
+ return NULL;
259
+ }
260
+
261
+ if( stackRead < game->numPlayers ) {
262
+
263
+ fprintf( stderr, "only read %"PRIu8" stack sizes, need %"PRIu8"\n",
264
+ stackRead, game->numPlayers );
265
+ free( game );
266
+ return NULL;
267
+ }
268
+
269
+ if( blindRead < game->numPlayers ) {
270
+
271
+ fprintf( stderr, "only read %"PRIu8" blinds, need %"PRIu8"\n",
272
+ blindRead, game->numPlayers );
273
+ free( game );
274
+ return NULL;
275
+ }
276
+ for( c = 0; c < game->numPlayers; ++c ) {
277
+
278
+ if( game->blind[ c ] > game->stack[ c ] ) {
279
+ fprintf( stderr, "blind for player %d is greater than stack size\n",
280
+ c + 1 );
281
+ free( game );
282
+ return NULL;
283
+ }
284
+ }
285
+
286
+ if( game->bettingType == limitBetting
287
+ && raiseSizeRead < game->numRounds ) {
288
+
289
+ fprintf( stderr, "only read %"PRIu8" raise sizes, need %"PRIu8"\n",
290
+ raiseSizeRead, game->numRounds );
291
+ free( game );
292
+ return NULL;
293
+ }
294
+
295
+ for( c = 0; c < game->numRounds; ++c ) {
296
+
297
+ if( game->firstPlayer[ c ] == 0
298
+ || game->firstPlayer[ c ] > game->numPlayers ) {
299
+
300
+ fprintf( stderr, "invalid first player %"PRIu8" on round %d\n",
301
+ game->firstPlayer[ c ], c + 1 );
302
+ free( game );
303
+ return NULL;
304
+ }
305
+
306
+ --game->firstPlayer[ c ];
307
+ }
308
+
309
+ if( game->numSuits == 0 || game->numSuits > MAX_SUITS ) {
310
+
311
+ fprintf( stderr, "invalid number of suits: %"PRIu8"\n", game->numSuits );
312
+ free( game );
313
+ return NULL;
314
+ }
315
+
316
+ if( game->numRanks == 0 || game->numRanks > MAX_RANKS ) {
317
+
318
+ fprintf( stderr, "invalid number of ranks: %"PRIu8"\n", game->numRanks );
319
+ free( game );
320
+ return NULL;
321
+ }
322
+
323
+ if( game->numHoleCards == 0 || game->numHoleCards > MAX_HOLE_CARDS ) {
324
+
325
+ fprintf( stderr, "invalid number of hole cards: %"PRIu8"\n",
326
+ game->numHoleCards );
327
+ free( game );
328
+ return NULL;
329
+ }
330
+
331
+ if( boardCardsRead < game->numRounds ) {
332
+
333
+ fprintf( stderr, "only read %"PRIu8" board card numbers, need %"PRIu8"\n",
334
+ boardCardsRead, game->numRounds );
335
+ free( game );
336
+ return NULL;
337
+ }
338
+
339
+ t = game->numHoleCards * game->numPlayers;
340
+ for( c = 0; c < game->numRounds; ++c ) {
341
+ t += game->numBoardCards[ c ];
342
+ }
343
+ if( t > game->numSuits * game->numRanks ) {
344
+
345
+ fprintf( stderr, "too many hole and board cards for specified deck\n" );
346
+ free( game );
347
+ return NULL;
348
+ }
349
+
350
+ return game;
351
+ }
352
+
353
+ void printGame( FILE *file, const Game *game )
354
+ {
355
+ int i;
356
+
357
+ fprintf( file, "GAMEDEF\n" );
358
+
359
+ if( game->bettingType == noLimitBetting ) {
360
+ fprintf( file, "nolimit\n" );
361
+ } else {
362
+ fprintf( file, "limit\n" );
363
+ }
364
+
365
+ fprintf( file, "numPlayers = %"PRIu8"\n", game->numPlayers );
366
+
367
+ fprintf( file, "numRounds = %"PRIu8"\n", game->numRounds );
368
+
369
+ for( i = 0; i < game->numPlayers; ++i ) {
370
+ if( game->stack[ i ] < INT32_MAX ) {
371
+
372
+ fprintf( file, "stack =" );
373
+ for( i = 0; i < game->numPlayers; ++i ) {
374
+ fprintf( file, " %"PRId32, game->stack[ i ] );
375
+ }
376
+ fprintf( file, "\n" );
377
+
378
+ break;
379
+ }
380
+ }
381
+
382
+ fprintf( file, "blind =" );
383
+ for( i = 0; i < game->numPlayers; ++i ) {
384
+ fprintf( file, " %"PRId32, game->blind[ i ] );
385
+ }
386
+ fprintf( file, "\n" );
387
+
388
+ if( game->bettingType == limitBetting ) {
389
+
390
+ fprintf( file, "raiseSize =" );
391
+ for( i = 0; i < game->numRounds; ++i ) {
392
+ fprintf( file, " %"PRId32, game->raiseSize[ i ] );
393
+ }
394
+ fprintf( file, "\n" );
395
+ }
396
+
397
+ for( i = 0; i < game->numRounds; ++i ) {
398
+ if( game->firstPlayer[ i ] != 0 ) {
399
+
400
+ fprintf( file, "firstPlayer =" );
401
+ for( i = 0; i < game->numRounds; ++i ) {
402
+ fprintf( file, " %"PRIu8, game->firstPlayer[ i ] + 1 );
403
+ }
404
+ fprintf( file, "\n" );
405
+
406
+ break;
407
+ }
408
+ }
409
+
410
+ for( i = 0; i < game->numRounds; ++i ) {
411
+ if( game->maxRaises[ i ] != UINT8_MAX ) {
412
+
413
+ fprintf( file, "maxRaises =" );
414
+ for( i = 0; i < game->numRounds; ++i ) {
415
+ fprintf( file, " %"PRIu8, game->maxRaises[ i ] );
416
+ }
417
+ fprintf( file, "\n" );
418
+
419
+ break;
420
+ }
421
+ }
422
+
423
+ fprintf( file, "numSuits = %"PRIu8"\n", game->numSuits );
424
+
425
+ fprintf( file, "numRanks = %"PRIu8"\n", game->numRanks );
426
+
427
+ fprintf( file, "numHoleCards = %"PRIu8"\n", game->numHoleCards );
428
+
429
+ fprintf( file, "numBoardCards =" );
430
+ for( i = 0; i < game->numRounds; ++i ) {
431
+ fprintf( file, " %"PRIu8, game->numBoardCards[ i ] );
432
+ }
433
+ fprintf( file, "\n" );
434
+
435
+ fprintf( file, "END GAMEDEF\n" );
436
+ }
437
+
438
+ uint8_t bcStart( const Game *game, const uint8_t round )
439
+ {
440
+ int r;
441
+ uint8_t start;
442
+
443
+ start = 0;
444
+ for( r = 0; r < round; ++r ) {
445
+
446
+ start += game->numBoardCards[ r ];
447
+ }
448
+
449
+ return start;
450
+ }
451
+
452
+ uint8_t sumBoardCards( const Game *game, const uint8_t round )
453
+ {
454
+ int r;
455
+ uint8_t total;
456
+
457
+ total = 0;
458
+ for( r = 0; r <= round; ++r ) {
459
+ total += game->numBoardCards[ r ];
460
+ }
461
+
462
+ return total;
463
+ }
464
+
465
+ static uint8_t nextPlayer( const Game *game, const State *state,
466
+ const uint8_t curPlayer )
467
+ {
468
+ uint8_t n;
469
+
470
+ n = curPlayer;
471
+ do {
472
+ n = ( n + 1 ) % game->numPlayers;
473
+ } while( state->playerFolded[ n ]
474
+ || state->spent[ n ] >= game->stack[ n ] );
475
+
476
+ return n;
477
+ }
478
+
479
+ uint8_t currentPlayer( const Game *game, const State *state )
480
+ {
481
+ /* if action has already been made, compute next player from last player */
482
+ if( state->numActions[ state->round ] ) {
483
+ return nextPlayer( game, state, state->actingPlayer[ state->round ]
484
+ [ state->numActions[ state->round ] - 1 ] );
485
+ }
486
+
487
+ /* first player in a round is determined by the game and round
488
+ use nextPlayer() because firstPlayer[round] might be unable to act */
489
+ return nextPlayer( game, state, game->firstPlayer[ state->round ]
490
+ + game->numPlayers - 1 );
491
+ }
492
+
493
+ uint8_t numRaises( const State *state )
494
+ {
495
+ int i;
496
+ uint8_t ret;
497
+
498
+ ret = 0;
499
+ for( i = 0; i < state->numActions[ state->round ]; ++i ) {
500
+ if( state->action[ state->round ][ i ].type == a_raise ) {
501
+ ++ret;
502
+ }
503
+ }
504
+
505
+ return ret;
506
+ }
507
+
508
+ uint8_t numFolded( const Game *game, const State *state )
509
+ {
510
+ int p;
511
+ uint8_t ret;
512
+
513
+ ret = 0;
514
+ for( p = 0; p < game->numPlayers; ++p ) {
515
+ if( state->playerFolded[ p ] ) {
516
+ ++ret;
517
+ }
518
+ }
519
+
520
+ return ret;
521
+ }
522
+
523
+ uint8_t numCalled( const Game *game, const State *state )
524
+ {
525
+ int i;
526
+ uint8_t ret, p;
527
+
528
+ ret = 0;
529
+ for( i = state->numActions[ state->round ]; i > 0; --i ) {
530
+
531
+ p = state->actingPlayer[ state->round ][ i - 1 ];
532
+
533
+ if( state->action[ state->round ][ i - 1 ].type == a_raise ) {
534
+ /* player initiated the bet, so they've called it */
535
+
536
+ if( state->spent[ p ] < game->stack[ p ] ) {
537
+ /* player is not all-in, so they're still acting */
538
+
539
+ ++ret;
540
+ }
541
+
542
+ /* this is the start of the current bet, so we're finished */
543
+ return ret;
544
+ } else if( state->action[ state->round ][ i - 1 ].type == a_call ) {
545
+
546
+ if( state->spent[ p ] < game->stack[ p ] ) {
547
+ /* player is not all-in, so they're still acting */
548
+
549
+ ++ret;
550
+ }
551
+ }
552
+ }
553
+
554
+ return ret;
555
+ }
556
+
557
+ uint8_t numAllIn( const Game *game, const State *state )
558
+ {
559
+ int p;
560
+ uint8_t ret;
561
+
562
+ ret = 0;
563
+ for( p = 0; p < game->numPlayers; ++p ) {
564
+ if( state->spent[ p ] >= game->stack[ p ] ) {
565
+ ++ret;
566
+ }
567
+ }
568
+
569
+ return ret;
570
+ }
571
+
572
+ uint8_t numActingPlayers( const Game *game, const State *state )
573
+ {
574
+ int p;
575
+ uint8_t ret;
576
+
577
+ ret = 0;
578
+ for( p = 0; p < game->numPlayers; ++p ) {
579
+ if( state->playerFolded[ p ] == 0
580
+ && state->spent[ p ] < game->stack[ p ] ) {
581
+ ++ret;
582
+ }
583
+ }
584
+
585
+ return ret;
586
+ }
587
+
588
+ void initState( const Game *game, const uint32_t handId, State *state )
589
+ {
590
+ int p, r;
591
+
592
+ state->handId = handId;
593
+
594
+ state->maxSpent = 0;
595
+ for( p = 0; p < game->numPlayers; ++p ) {
596
+
597
+ state->spent[ p ] = game->blind[ p ];
598
+ if( game->blind[ p ] > state->maxSpent ) {
599
+
600
+ state->maxSpent = game->blind[ p ];
601
+ }
602
+ }
603
+
604
+ if( game->bettingType == noLimitBetting ) {
605
+ /* no-limit games need to keep track of the minimum bet */
606
+
607
+ if( state->maxSpent ) {
608
+ /* we'll have to call the big blind and then raise by that
609
+ amount, so the minimum raise-to is 2*maximum blinds */
610
+
611
+ state->minNoLimitRaiseTo = state->maxSpent * 2;
612
+ } else {
613
+ /* need to bet at least one chip, and there are no blinds/ante */
614
+
615
+ state->minNoLimitRaiseTo = 1;
616
+ }
617
+ } else {
618
+ /* no need to worry about minimum raises outside of no-limit games */
619
+
620
+ state->minNoLimitRaiseTo = 0;
621
+ }
622
+
623
+ for( p = 0; p < game->numPlayers; ++p ) {
624
+
625
+ state->spent[ p ] = game->blind[ p ];
626
+
627
+ if( game->blind[ p ] > state->maxSpent ) {
628
+ state->maxSpent = game->blind[ p ];
629
+ }
630
+
631
+ state->playerFolded[ p ] = 0;
632
+ }
633
+
634
+ for( r = 0; r < game->numRounds; ++r ) {
635
+
636
+ state->numActions[ r ] = 0;
637
+ }
638
+
639
+ state->round = 0;
640
+
641
+ state->finished = 0;
642
+ }
643
+
644
+ static uint8_t dealCard( rng_state_t *rng, uint8_t *deck, const int numCards )
645
+ {
646
+ int i;
647
+ uint8_t ret;
648
+
649
+ i = genrand_int32( rng ) % numCards;
650
+ ret = deck[ i ];
651
+ deck[ i ] = deck[ numCards - 1 ];
652
+
653
+ return ret;
654
+ }
655
+
656
+ void dealCards( const Game *game, rng_state_t *rng, State *state )
657
+ {
658
+ int r, s, numCards, i, p;
659
+ uint8_t deck[ MAX_RANKS * MAX_SUITS ];
660
+
661
+ numCards = 0;
662
+ for( s = 0; s < game->numSuits; ++s ) {
663
+
664
+ for( r = 0; r < game->numRanks; ++r ) {
665
+
666
+ deck[ numCards ] = makeCard( r, s );
667
+ ++numCards;
668
+ }
669
+ }
670
+
671
+ for( p = 0; p < game->numPlayers; ++p ) {
672
+
673
+ for( i = 0; i < game->numHoleCards; ++i ) {
674
+
675
+ state->holeCards[ p ][ i ] = dealCard( rng, deck, numCards );
676
+ --numCards;
677
+ }
678
+ }
679
+
680
+ s = 0;
681
+ for( r = 0; r < game->numRounds; ++r ) {
682
+
683
+ for( i = 0; i < game->numBoardCards[ r ]; ++i ) {
684
+
685
+ state->boardCards[ s ] = dealCard( rng, deck, numCards );
686
+ --numCards;
687
+ ++s;
688
+ }
689
+ }
690
+ }
691
+
692
+ /* check whether some portions of a state are equal,
693
+ common to both statesEqual and matchStatesEqual */
694
+ static int statesEqualCommon( const Game *game, const State *a,
695
+ const State *b )
696
+ {
697
+ int r, i, t;
698
+
699
+ /* is it the same hand? */
700
+ if( a->handId != b->handId ) {
701
+ return 0;
702
+ }
703
+
704
+ /* make sure the betting is the same */
705
+ if( a->round != b->round ) {
706
+ return 0;
707
+ }
708
+
709
+ for( r = 0; r <= a->round; ++r ) {
710
+
711
+ if( a->numActions[ r ] != b->numActions[ r ] ) {
712
+ return 0;
713
+ }
714
+
715
+ for( i = 0; i < a->numActions[ r ]; ++i ) {
716
+
717
+ if( a->action[ r ][ i ].type != b->action[ r ][ i ].type ) {
718
+ return 0;
719
+ }
720
+ if( a->action[ r ][ i ].size != b->action[ r ][ i ].size ) {
721
+ return 0;
722
+ }
723
+ }
724
+ }
725
+
726
+ /* spent, maxSpent, actingPlayer, finished, and playerFolded are
727
+ all determined by the betting taken, so if it's equal, so are
728
+ they (at least for valid states) */
729
+
730
+ /* are the board cards the same? */
731
+ t = sumBoardCards( game, a->round );
732
+ for( i = 0; i < t; ++i ) {
733
+
734
+ if( a->boardCards[ i ] != b->boardCards[ i ] ) {
735
+ return 0;
736
+ }
737
+ }
738
+
739
+ /* all tests say states are equal */
740
+ return 1;
741
+ }
742
+
743
+ int statesEqual( const Game *game, const State *a, const State *b )
744
+ {
745
+ int p, i;
746
+
747
+ if( !statesEqualCommon( game, a, b ) ) {
748
+ return 0;
749
+ }
750
+
751
+ /* are all the hole cards the same? */
752
+ for( p = 0; p < game->numPlayers; ++p ) {
753
+
754
+ for( i = 0; i < game->numHoleCards; ++i ) {
755
+ if( a->holeCards[ p ][ i ] != b->holeCards[ p ][ i ] ) {
756
+ return 0;
757
+ }
758
+ }
759
+ }
760
+
761
+ return 1;
762
+ }
763
+
764
+ int matchStatesEqual( const Game *game, const MatchState *a,
765
+ const MatchState *b )
766
+ {
767
+ int p, i;
768
+
769
+ if( a->viewingPlayer != b->viewingPlayer ) {
770
+ return 0;
771
+ }
772
+
773
+ if( !statesEqualCommon( game, &a->state, &b->state ) ) {
774
+ return 0;
775
+ }
776
+
777
+ /* are the viewing player's hole cards the same? */
778
+ p = a->viewingPlayer;
779
+ for( i = 0; i < game->numHoleCards; ++i ) {
780
+ if( a->state.holeCards[ p ][ i ] != b->state.holeCards[ p ][ i ] ) {
781
+ return 0;
782
+ }
783
+ }
784
+
785
+ return 1;
786
+ }
787
+
788
+ int raiseIsValid( const Game *game, const State *curState,
789
+ int32_t *minSize, int32_t *maxSize )
790
+ {
791
+ int p;
792
+
793
+ if( numRaises( curState ) >= game->maxRaises[ curState->round ] ) {
794
+ /* already made maximum number of raises */
795
+
796
+ return 0;
797
+ }
798
+
799
+ if( curState->numActions[ curState->round ] + game->numPlayers
800
+ > MAX_NUM_ACTIONS ) {
801
+ /* 1 raise + NUM PLAYERS-1 calls is too many actions */
802
+
803
+ fprintf( stderr, "WARNING: #actions in round is too close to MAX_NUM_ACTIONS, forcing call/fold\n" );
804
+ return 0;
805
+ }
806
+
807
+ if( numActingPlayers( game, curState ) <= 1 ) {
808
+ /* last remaining player can't bet if there's no one left to call
809
+ (this check is needed if the 2nd last player goes all in, and
810
+ the last player has enough stack left to bet) */
811
+
812
+ return 0;
813
+ }
814
+
815
+ if( game->bettingType != noLimitBetting ) {
816
+ /* if it's not no-limit betting, don't worry about sizes */
817
+
818
+ *minSize = 0;
819
+ *maxSize = 0;
820
+ return 1;
821
+ }
822
+
823
+ p = currentPlayer( game, curState );
824
+ *minSize = curState->minNoLimitRaiseTo;
825
+ *maxSize = game->stack[ p ];
826
+
827
+ /* handle case where remaining player stack is too small */
828
+ if( *minSize > game->stack[ p ] ) {
829
+ /* can't handle the minimum bet size - can we bet at all? */
830
+
831
+ if( curState->maxSpent >= game->stack[ p ] ) {
832
+ /* not enough money to increase current bet */
833
+
834
+ return 0;
835
+ } else {
836
+ /* can raise by going all-in */
837
+
838
+ *minSize = *maxSize;
839
+ return 1;
840
+ }
841
+ }
842
+
843
+ return 1;
844
+ }
845
+
846
+ int isValidAction( const Game *game, const State *curState,
847
+ const int tryFixing, Action *action )
848
+ {
849
+ int min, max, p;
850
+
851
+ if( stateFinished( curState ) || action->type == a_invalid ) {
852
+ return 0;
853
+ }
854
+
855
+ p = currentPlayer( game, curState );
856
+
857
+ if( action->type == a_raise ) {
858
+
859
+ if( !raiseIsValid( game, curState, &min, &max ) ) {
860
+ /* there are no valid raise sizes */
861
+
862
+ return 0;
863
+ }
864
+
865
+ if( game->bettingType == noLimitBetting ) {
866
+ /* no limit games have a size */
867
+
868
+ if( action->size < min ) {
869
+ /* bet size is too small */
870
+
871
+ if( !tryFixing ) {
872
+
873
+ return 0;
874
+ }
875
+ fprintf( stderr, "WARNING: raise of %d increased to %d\n",
876
+ action->size, min );
877
+ action->size = min;
878
+ } else if( action->size > max ) {
879
+ /* bet size is too big */
880
+
881
+ if( !tryFixing ) {
882
+
883
+ return 0;
884
+ }
885
+ fprintf( stderr, "WARNING: raise of %d decreased to %d\n",
886
+ action->size, max );
887
+ action->size = max;
888
+ }
889
+ } else {
890
+
891
+ }
892
+ } else if( action->type == a_fold ) {
893
+
894
+ if( curState->spent[ p ] == curState->maxSpent
895
+ || curState->spent[ p ] == game->stack[ p ] ) {
896
+ /* player has already called all bets, or is all-in */
897
+
898
+ return 0;
899
+ }
900
+
901
+ if( action->size != 0 ) {
902
+
903
+ fprintf( stderr, "WARNING: size given for fold\n" );
904
+ action->size = 0;
905
+ }
906
+ } else {
907
+ /* everything else */
908
+
909
+ if( action->size != 0 ) {
910
+
911
+ fprintf( stderr, "WARNING: size given for something other than a no-limit raise\n" );
912
+ action->size = 0;
913
+ }
914
+ }
915
+
916
+ return 1;
917
+ }
918
+
919
+ void doAction( const Game *game, const Action *action, State *state )
920
+ {
921
+ int p = currentPlayer( game, state );
922
+
923
+ assert( state->numActions[ state->round ] < MAX_NUM_ACTIONS );
924
+
925
+ state->action[ state->round ][ state->numActions[ state->round ] ] = *action;
926
+ state->actingPlayer[ state->round ][ state->numActions[ state->round ] ] = p;
927
+ ++state->numActions[ state->round ];
928
+
929
+ switch( action->type ) {
930
+ case a_fold:
931
+
932
+ state->playerFolded[ p ] = 1;
933
+ break;
934
+
935
+ case a_call:
936
+
937
+ if( state->maxSpent > game->stack[ p ] ) {
938
+ /* calling puts player all-in */
939
+
940
+ state->spent[ p ] = game->stack[ p ];
941
+ } else {
942
+ /* player matches the bet by spending same amount of money */
943
+
944
+ state->spent[ p ] = state->maxSpent;
945
+ }
946
+ break;
947
+
948
+ case a_raise:
949
+
950
+ if( game->bettingType == noLimitBetting ) {
951
+ /* no-limit betting uses size in action */
952
+
953
+ assert( action->size > state->maxSpent );
954
+ assert( action->size <= game->stack[ p ] );
955
+
956
+ /* next raise must call this bet, and raise by at least this much */
957
+ if( action->size + action->size - state->maxSpent
958
+ > state->minNoLimitRaiseTo ) {
959
+
960
+ state->minNoLimitRaiseTo
961
+ = action->size + action->size - state->maxSpent;
962
+ }
963
+ state->maxSpent = action->size;
964
+ } else {
965
+ /* limit betting uses a fixed amount on top of current bet size */
966
+
967
+ if( state->maxSpent + game->raiseSize[ state->round ]
968
+ > game->stack[ p ] ) {
969
+ /* raise puts player all-in */
970
+
971
+ state->maxSpent = game->stack[ p ];
972
+ } else {
973
+ /* player raises by the normal limit size */
974
+
975
+ state->maxSpent += game->raiseSize[ state->round ];
976
+ }
977
+ }
978
+
979
+ state->spent[ p ] = state->maxSpent;
980
+ break;
981
+
982
+ default:
983
+ fprintf( stderr, "ERROR: trying to do invalid action %d", action->type );
984
+ assert( 0 );
985
+ }
986
+
987
+ /* see if the round or game has ended */
988
+ if( numFolded( game, state ) + 1 >= game->numPlayers ) {
989
+ /* only one player left - game is immediately over, no showdown */
990
+
991
+ state->finished = 1;
992
+ } else if( numCalled( game, state ) >= numActingPlayers( game, state ) ) {
993
+ /* >= 2 non-folded players, all acting players have called */
994
+
995
+ if( numActingPlayers( game, state ) > 1 ) {
996
+ /* there are at least 2 acting players */
997
+
998
+ if( state->round + 1 < game->numRounds ) {
999
+ /* active players move onto next round */
1000
+
1001
+ ++state->round;
1002
+
1003
+ /* minimum raise-by is reset to minimum of big blind or 1 chip */
1004
+ state->minNoLimitRaiseTo = 1;
1005
+ for( p = 0; p < game->numPlayers; ++p ) {
1006
+
1007
+ if( game->blind[ p ] > state->minNoLimitRaiseTo ) {
1008
+
1009
+ state->minNoLimitRaiseTo = game->blind[ p ];
1010
+ }
1011
+ }
1012
+
1013
+ /* we finished at least one round, so raise-to = raise-by + maxSpent */
1014
+ state->minNoLimitRaiseTo += state->maxSpent;
1015
+ } else {
1016
+ /* no more betting rounds, so we're totally finished */
1017
+
1018
+ state->finished = 1;
1019
+ }
1020
+ } else {
1021
+ /* not enough players for more betting, but still need a showdown */
1022
+
1023
+ state->finished = 1;
1024
+ state->round = game->numRounds - 1;
1025
+ }
1026
+ }
1027
+ }
1028
+
1029
+ static int rankHand( const Game *game, const State *state,
1030
+ const uint8_t player )
1031
+ {
1032
+ int i;
1033
+ Cardset c = emptyCardset();
1034
+
1035
+ for( i = 0; i < game->numHoleCards; ++i ) {
1036
+
1037
+ addCardToCardset( &c, suitOfCard( state->holeCards[ player ][ i ] ),
1038
+ rankOfCard( state->holeCards[ player ][ i ] ) );
1039
+ }
1040
+
1041
+ for( i = 0; i < sumBoardCards( game, state->round ); ++i ) {
1042
+
1043
+ addCardToCardset( &c, suitOfCard( state->boardCards[ i ] ),
1044
+ rankOfCard( state->boardCards[ i ] ) );
1045
+ }
1046
+
1047
+ return rankCardset( c );
1048
+ }
1049
+
1050
+ double valueOfState( const Game *game, const State *state,
1051
+ const uint8_t player )
1052
+ {
1053
+ double value;
1054
+ int p, numPlayers, playerIdx, numWinners, newNumPlayers;
1055
+ int32_t size, spent[ MAX_PLAYERS ];
1056
+ int rank[ MAX_PLAYERS ], winRank;
1057
+
1058
+ if( state->playerFolded[ player ] ) {
1059
+ /* folding player loses all spent money */
1060
+
1061
+ return (double)-state->spent[ player ];
1062
+ }
1063
+
1064
+ if( numFolded( game, state ) + 1 == game->numPlayers ) {
1065
+ /* everyone else folded, so player takes the pot */
1066
+
1067
+ value = 0.0;
1068
+ for( p = 0; p < game->numPlayers; ++p ) {
1069
+ if( p == player ) { continue; }
1070
+
1071
+ value += (double)state->spent[ p ];
1072
+ }
1073
+
1074
+ return value;
1075
+ }
1076
+
1077
+ /* there's a showdown, and player is particpating. Exciting! */
1078
+
1079
+ /* make up a list of players */
1080
+ numPlayers = 0;
1081
+ playerIdx = -1; /* useless, but gets rid of a warning */
1082
+ for( p = 0; p < game->numPlayers; ++p ) {
1083
+
1084
+ if( state->spent[ p ] == 0 ) {
1085
+ continue;
1086
+ }
1087
+
1088
+ if( state->playerFolded[ p ] ) {
1089
+ /* folding players have a negative rank so they lose to a real hand
1090
+ we have also tested for fold, so p can't be the player of interest */
1091
+
1092
+ rank[ numPlayers ] = -1;
1093
+ } else {
1094
+ /* p is participating in a showdown */
1095
+
1096
+ if( p == player ) {
1097
+ playerIdx = numPlayers;
1098
+ }
1099
+ rank[ numPlayers ] = rankHand( game, state, p );
1100
+ }
1101
+
1102
+ spent[ numPlayers ] = state->spent[ p ];
1103
+ ++numPlayers;
1104
+ }
1105
+ assert( numPlayers > 1 );
1106
+
1107
+ /* go through all the sidepots player is participating in */
1108
+ value = 0.0;
1109
+ while( 1 ) {
1110
+
1111
+ /* find the smallest remaining sidepot, largest rank,
1112
+ and number of winners with largest rank */
1113
+ size = INT32_MAX;
1114
+ winRank = 0;
1115
+ numWinners = 0;
1116
+ for( p = 0; p < numPlayers; ++p ) {
1117
+ assert( spent[ p ] > 0 );
1118
+
1119
+ if( spent[ p ] < size ) {
1120
+ size = spent[ p ];
1121
+ }
1122
+
1123
+ if( rank[ p ] > winRank ) {
1124
+ /* new largest rank - only one player with this rank so far */
1125
+
1126
+ winRank = rank[ p ];
1127
+ numWinners = 1;
1128
+ } else if( rank[ p ] == winRank ) {
1129
+ /* another player with highest rank */
1130
+
1131
+ ++numWinners;
1132
+ }
1133
+ }
1134
+
1135
+ if( rank[ playerIdx ] == winRank ) {
1136
+ /* player has spent size, and splits pot with other winners */
1137
+
1138
+ value += (double)( size * ( numPlayers - numWinners ) )
1139
+ / (double)numWinners;
1140
+ } else {
1141
+ /* player loses this pot */
1142
+
1143
+ value -= (double)size;
1144
+ }
1145
+
1146
+ /* update list of players for next pot */
1147
+ newNumPlayers = 0;
1148
+ for( p = 0; p < numPlayers; ++p ) {
1149
+
1150
+ spent[ p ] -= size;
1151
+ if( spent[ p ] == 0 ) {
1152
+ /* player p is not participating in next side pot */
1153
+
1154
+ if( p == playerIdx ) {
1155
+ /* p is the player of interest, so we're done */
1156
+
1157
+ return value;
1158
+ }
1159
+
1160
+ continue;
1161
+ }
1162
+
1163
+ if( p == playerIdx ) {
1164
+ /* p is the player of interest, so note the new index */
1165
+
1166
+ playerIdx = newNumPlayers;
1167
+ }
1168
+
1169
+ if( p != newNumPlayers ) {
1170
+ /* put entry p into new position */
1171
+
1172
+ spent[ newNumPlayers ] = spent[ p ];
1173
+ rank[ newNumPlayers ] = rank[ p ];
1174
+ }
1175
+ ++newNumPlayers;
1176
+ }
1177
+ numPlayers = newNumPlayers;
1178
+ }
1179
+ }
1180
+
1181
+ /* read actions from a string, updating state with the actions
1182
+ reading is terminated by '\0' and ':'
1183
+ returns number of characters consumed, or -1 on failure
1184
+ state will be modified, even on failure */
1185
+ static int readBetting( const char *string, const Game *game, State *state )
1186
+ {
1187
+ int c, r;
1188
+ Action action;
1189
+
1190
+ c = 0;
1191
+ while( 1 ) {
1192
+
1193
+ if( string[ c ] == 0 ) {
1194
+ break;
1195
+ }
1196
+
1197
+ if( string[ c ] == ':' ) {
1198
+ ++c;
1199
+ break;
1200
+ }
1201
+
1202
+ /* ignore / character */
1203
+ if( string[ c ] == '/' ) {
1204
+ ++c;
1205
+ continue;
1206
+ }
1207
+
1208
+ r = readAction( &string[ c ], game, &action );
1209
+ if( r < 0 ) {
1210
+ return -1;
1211
+ }
1212
+
1213
+ if( !isValidAction( game, state, 0, &action ) ) {
1214
+ return -1;
1215
+ }
1216
+
1217
+ doAction( game, &action, state );
1218
+ c += r;
1219
+ }
1220
+
1221
+ return c;
1222
+ }
1223
+
1224
+ /* print actions to a string
1225
+ returns number of characters printed to string, or -1 on failure
1226
+ DOES NOT COUNT FINAL 0 TERMINATOR IN THIS COUNT!!! */
1227
+ static int printBetting( const Game *game, const State *state,
1228
+ const int maxLen, char *string )
1229
+ {
1230
+ int i, a, c, r;
1231
+
1232
+ c = 0;
1233
+ for( i = 0; i <= state->round; ++i ) {
1234
+
1235
+ /* print state separator */
1236
+ if( i != 0 ) {
1237
+
1238
+ if( c >= maxLen ) {
1239
+ return -1;
1240
+ }
1241
+ string[ c ] = '/';
1242
+ ++c;
1243
+ }
1244
+
1245
+ /* print betting for round */
1246
+ for( a = 0; a < state->numActions[ i ]; ++a ) {
1247
+
1248
+ r = printAction( game, &state->action[ i ][ a ],
1249
+ maxLen - c, &string[ c ] );
1250
+ if( r < 0 ) {
1251
+ return -1;
1252
+ }
1253
+ c += r;
1254
+ }
1255
+ }
1256
+
1257
+ if( c >= maxLen ) {
1258
+ return -1;
1259
+ }
1260
+ string[ c ] = 0;
1261
+
1262
+ return c;
1263
+ }
1264
+
1265
+ static int readHoleCards( const char *string, const Game *game,
1266
+ State *state )
1267
+ {
1268
+ int p, c, r, num;
1269
+
1270
+ c = 0;
1271
+ for( p = 0; p < game->numPlayers; ++p ) {
1272
+
1273
+ /* check for player separator '|' */
1274
+ if( p != 0 ) {
1275
+ if( string[ c ] == '|' ) {
1276
+ ++c;
1277
+ }
1278
+ }
1279
+
1280
+ num = readCards( &string[ c ], game->numHoleCards,
1281
+ state->holeCards[ p ], &r );
1282
+ if( num == 0 ) {
1283
+ /* no cards for player p */
1284
+
1285
+ continue;
1286
+ }
1287
+ if( num != game->numHoleCards ) {
1288
+ /* read some cards, but not enough - bad! */
1289
+
1290
+ return -1;
1291
+ }
1292
+ c += r;
1293
+ }
1294
+
1295
+ return c;
1296
+ }
1297
+
1298
+ static int printAllHoleCards( const Game *game, const State *state,
1299
+ const int maxLen, char *string )
1300
+ {
1301
+ int p, c, r;
1302
+
1303
+ c = 0;
1304
+ for( p = 0; p < game->numPlayers; ++p ) {
1305
+
1306
+ /* print player separator '|' */
1307
+ if( p != 0 ) {
1308
+
1309
+ if( c >= maxLen ) {
1310
+ return -1;
1311
+ }
1312
+ string[ c ] = '|';
1313
+ ++c;
1314
+ }
1315
+
1316
+ r = printCards( game->numHoleCards, state->holeCards[ p ],
1317
+ maxLen - c, &string[ c ] );
1318
+ if( r < 0 ) {
1319
+ return -1;
1320
+ }
1321
+ c += r;
1322
+ }
1323
+
1324
+ if( c >= maxLen ) {
1325
+ return -1;
1326
+ }
1327
+ string[ c ] = 0;
1328
+
1329
+ return c;
1330
+ }
1331
+
1332
+ static int printPlayerHoleCards( const Game *game, const State *state,
1333
+ const uint8_t player,
1334
+ const int maxLen, char *string )
1335
+ {
1336
+ int p, c, r;
1337
+
1338
+ c = 0;
1339
+ for( p = 0; p < game->numPlayers; ++p ) {
1340
+
1341
+ /* print player separator '|' */
1342
+ if( p != 0 ) {
1343
+
1344
+ if( c >= maxLen ) {
1345
+ return -1;
1346
+ }
1347
+ string[ c ] = '|';
1348
+ ++c;
1349
+ }
1350
+
1351
+ if( p != player ) {
1352
+ /* don't print other player's cards unless there was a showdown
1353
+ and they didn't fold */
1354
+
1355
+ if( !stateFinished( state ) ) {
1356
+ continue;
1357
+ }
1358
+
1359
+ if( state->playerFolded[ p ] ) {
1360
+ continue;
1361
+ }
1362
+
1363
+ if( numFolded( game, state ) + 1 == game->numPlayers ) {
1364
+ continue;
1365
+ }
1366
+ }
1367
+
1368
+ r = printCards( game->numHoleCards, state->holeCards[ p ],
1369
+ maxLen - c, &string[ c ] );
1370
+ if( r < 0 ) {
1371
+ return -1;
1372
+ }
1373
+ c += r;
1374
+ }
1375
+
1376
+ if( c >= maxLen ) {
1377
+ return -1;
1378
+ }
1379
+ string[ c ] = 0;
1380
+
1381
+ return c;
1382
+ }
1383
+
1384
+ static int readBoardCards( const char *string, const Game *game,
1385
+ State *state )
1386
+ {
1387
+ int i, c, r;
1388
+
1389
+ c = 0;
1390
+ for( i = 0; i <= state->round; ++i ) {
1391
+
1392
+ /* check for round separator '/' */
1393
+ if( i != 0 ) {
1394
+ if( string[ c ] == '/' ) {
1395
+ ++c;
1396
+ }
1397
+ }
1398
+
1399
+ if( readCards( &string[ c ], game->numBoardCards[ i ],
1400
+ &state->boardCards[ bcStart( game, i ) ], &r )
1401
+ != game->numBoardCards[ i ] ) {
1402
+ /* couldn't read the required number of cards - bad! */
1403
+
1404
+ return -1;
1405
+ }
1406
+ c += r;
1407
+ }
1408
+
1409
+ return c;
1410
+ }
1411
+
1412
+ static int printBoardCards( const Game *game, const State *state,
1413
+ const int maxLen, char *string )
1414
+ {
1415
+ int i, c, r;
1416
+
1417
+ c = 0;
1418
+ for( i = 0; i <= state->round; ++i ) {
1419
+
1420
+ /* print round separator '/' */
1421
+ if( i != 0 ) {
1422
+
1423
+ if( c >= maxLen ) {
1424
+ return -1;
1425
+ }
1426
+ string[ c ] = '/';
1427
+ ++c;
1428
+ }
1429
+
1430
+ r = printCards( game->numBoardCards[ i ],
1431
+ &state->boardCards[ bcStart( game, i ) ],
1432
+ maxLen - c, &string[ c ] );
1433
+ if( r < 0 ) {
1434
+ return -1;
1435
+ }
1436
+ c += r;
1437
+ }
1438
+
1439
+ if( c >= maxLen ) {
1440
+ return -1;
1441
+ }
1442
+ string[ c ] = 0;
1443
+
1444
+ return c;
1445
+ }
1446
+
1447
+
1448
+ static int readStateCommon( const char *string, const Game *game,
1449
+ State *state )
1450
+ {
1451
+ uint32_t handId;
1452
+ int c, r;
1453
+
1454
+ /* HEADER */
1455
+ c = 0;
1456
+
1457
+ /* HEADER:handId */
1458
+ if( sscanf( string, ":%"SCNu32"%n", &handId, &r ) < 1 ) {
1459
+ return -1;
1460
+ }
1461
+ c += r;
1462
+
1463
+ initState( game, handId, state );
1464
+
1465
+ /* HEADER:handId: */
1466
+ if( string[ c ] != ':' ) {
1467
+ return -1;
1468
+ }
1469
+ ++c;
1470
+
1471
+ /* HEADER:handId:betting: */
1472
+ r = readBetting( &string[ c ], game, state );
1473
+ if( r < 0 ) {
1474
+ return -1;
1475
+ }
1476
+ c += r;
1477
+
1478
+ /* HEADER:handId:betting:holeCards */
1479
+ r = readHoleCards( &string[ c ], game, state );
1480
+ if( r < 0 ) {
1481
+ return -1;
1482
+ }
1483
+ c += r;
1484
+
1485
+ /* HEADER:handId:betting:holeCards boardCards */
1486
+ r = readBoardCards( &string[ c ], game, state );
1487
+ if( r < 0 ) {
1488
+ return -1;
1489
+ }
1490
+ c += r;
1491
+
1492
+ return c;
1493
+ }
1494
+
1495
+ int readState( const char *string, const Game *game, State *state )
1496
+ {
1497
+ int c, r;
1498
+
1499
+ /* HEADER = STATE */
1500
+ if( strncmp( string, "STATE", 5 ) != 0 ) {
1501
+ return -1;
1502
+ }
1503
+ c = 5;
1504
+
1505
+ /* read rest of state */
1506
+ r = readStateCommon( &string[ 5 ], game, state );
1507
+ if( r < 0 ) {
1508
+ return -1;
1509
+ }
1510
+ c += r;
1511
+
1512
+ return c;
1513
+ }
1514
+
1515
+ int readMatchState( const char *string, const Game *game,
1516
+ MatchState *state )
1517
+ {
1518
+ int c, r;
1519
+
1520
+ /* HEADER = MATCHSTATE:player */
1521
+ if( sscanf( string, "MATCHSTATE:%"SCNu8"%n",
1522
+ &state->viewingPlayer, &c ) < 1
1523
+ || state->viewingPlayer >= game->numPlayers ) {
1524
+ return -1;
1525
+ }
1526
+
1527
+ /* read rest of state */
1528
+ r = readStateCommon( &string[ c ], game, &state->state );
1529
+ if( r < 0 ) {
1530
+ return -1;
1531
+ }
1532
+ c += r;
1533
+
1534
+ return c;
1535
+ }
1536
+
1537
+ static int printStateCommon( const Game *game, const State *state,
1538
+ const int maxLen, char *string )
1539
+ {
1540
+ int c, r;
1541
+
1542
+ /* HEADER */
1543
+ c = 0;
1544
+
1545
+ /* HEADER:handId: */
1546
+ r = snprintf( &string[ c ], maxLen - c, ":%"PRIu32":", state->handId );
1547
+ if( r < 0 ) {
1548
+ return -1;
1549
+ }
1550
+ c += r;
1551
+
1552
+ /* HEADER:handId:betting */
1553
+ r = printBetting( game, state, maxLen - c, &string[ c ] );
1554
+ if( r < 0 ) {
1555
+ return -1;
1556
+ }
1557
+ c += r;
1558
+
1559
+ /* HEADER:handId:betting: */
1560
+ if( c >= maxLen ) {
1561
+ return -1;
1562
+ }
1563
+ string[ c ] = ':';
1564
+ ++c;
1565
+
1566
+ return c;
1567
+ }
1568
+
1569
+ int printState( const Game *game, const State *state,
1570
+ const int maxLen, char *string )
1571
+ {
1572
+ int c, r;
1573
+
1574
+ c = 0;
1575
+
1576
+ /* STATE */
1577
+ r = snprintf( &string[ c ], maxLen - c, "STATE" );
1578
+ if( r < 0 ) {
1579
+ return -1;
1580
+ }
1581
+ c += r;
1582
+
1583
+ /* STATE:handId:betting: */
1584
+ r = printStateCommon( game, state, maxLen - c, &string[ c ] );
1585
+ if( r < 0 ) {
1586
+ return -1;
1587
+ }
1588
+ c += r;
1589
+
1590
+ /* STATE:handId:betting:holeCards */
1591
+ r = printAllHoleCards( game, state, maxLen - c, &string[ c ] );
1592
+ if( r < 0 ) {
1593
+ return -1;
1594
+ }
1595
+ c += r;
1596
+
1597
+ /* STATE:handId:betting:holeCards boardCards */
1598
+ r = printBoardCards( game, state, maxLen - c, &string[ c ] );
1599
+ if( r < 0 ) {
1600
+ return -1;
1601
+ }
1602
+ c += r;
1603
+
1604
+ if( c >= maxLen ) {
1605
+ return -1;
1606
+ }
1607
+ string[ c ] = 0;
1608
+
1609
+ return c;
1610
+ }
1611
+
1612
+ int printMatchState( const Game *game, const MatchState *state,
1613
+ const int maxLen, char *string )
1614
+ {
1615
+ int c, r;
1616
+
1617
+ c = 0;
1618
+
1619
+ /* MATCHSTATE:player */
1620
+ r = snprintf( &string[ c ], maxLen - c, "MATCHSTATE:%"PRIu8,
1621
+ state->viewingPlayer );
1622
+ if( r < 0 ) {
1623
+ return -1;
1624
+ }
1625
+ c += r;
1626
+
1627
+ /* MATCHSTATE:player:handId:betting: */
1628
+ r = printStateCommon( game, &state->state, maxLen - c, &string[ c ] );
1629
+ if( r < 0 ) {
1630
+ return -1;
1631
+ }
1632
+ c += r;
1633
+
1634
+ /* MATCHSTATE:player:handId:betting:holeCards */
1635
+ r = printPlayerHoleCards( game, &state->state, state->viewingPlayer,
1636
+ maxLen - c, &string[ c ] );
1637
+ if( r < 0 ) {
1638
+ return -1;
1639
+ }
1640
+ c += r;
1641
+
1642
+ /* MATCHSTATE:player:handId:betting:holeCards boardCards */
1643
+ r = printBoardCards( game, &state->state, maxLen - c, &string[ c ] );
1644
+ if( r < 0 ) {
1645
+ return -1;
1646
+ }
1647
+ c += r;
1648
+
1649
+ if( c >= maxLen ) {
1650
+ return -1;
1651
+ }
1652
+ string[ c ] = 0;
1653
+
1654
+ return c;
1655
+ }
1656
+
1657
+ int readAction( const char *string, const Game *game, Action *action )
1658
+ {
1659
+ int c, r;
1660
+
1661
+ action->type = charToAction[ (uint8_t)string[ 0 ] ];
1662
+ if( action->type < 0 ) {
1663
+ return -1;
1664
+ }
1665
+ c = 1;
1666
+
1667
+ if( action->type == a_raise && game->bettingType == noLimitBetting ) {
1668
+ /* no-limit bet/raise needs to read a size */
1669
+
1670
+ if( sscanf( &string[ c ], "%"SCNd32"%n", &action->size, &r ) < 1 ) {
1671
+ return -1;
1672
+ }
1673
+ c += r;
1674
+ } else {
1675
+ /* size is zero for anything but a no-limit raise */
1676
+
1677
+ action->size = 0;
1678
+ }
1679
+
1680
+ return c;
1681
+ }
1682
+
1683
+ int printAction( const Game *game, const Action *action,
1684
+ const int maxLen, char *string )
1685
+ {
1686
+ int c, r;
1687
+
1688
+ if( maxLen == 0 ) {
1689
+ return -1;
1690
+ }
1691
+
1692
+ c = 0;
1693
+
1694
+ string[ c ] = actionChars[ action->type ];
1695
+ ++c;
1696
+
1697
+ if( game->bettingType == noLimitBetting && action->type == a_raise ) {
1698
+ /* 2010 AAAI no-limit format has a size for bet/raise */
1699
+
1700
+ r = snprintf( &string[ c ], maxLen - c, "%"PRId32, action->size );
1701
+ if( r < 0 ) {
1702
+ return -1;
1703
+ }
1704
+ c += r;
1705
+ }
1706
+
1707
+ if( c >= maxLen ) {
1708
+ return -1;
1709
+ }
1710
+ string[ c ] = 0;
1711
+
1712
+ return c;
1713
+ }
1714
+
1715
+ int readCard( const char *string, uint8_t *card )
1716
+ {
1717
+ char *spos;
1718
+ uint8_t c;
1719
+
1720
+ if( string[ 0 ] == 0 ) {
1721
+ return -1;
1722
+ }
1723
+ spos = strchr( rankChars, toupper( string[ 0 ] ) );
1724
+ if( spos == 0 ) {
1725
+ return -1;
1726
+ }
1727
+ c = spos - rankChars;
1728
+
1729
+ if( string[ 1 ] == 0 ) {
1730
+ return -1;
1731
+ }
1732
+ spos = strchr( suitChars, tolower( string[ 1 ] ) );
1733
+ if( spos == 0 ) {
1734
+ return -1;
1735
+ }
1736
+
1737
+ *card = makeCard( c, spos - suitChars );
1738
+
1739
+ return 2;
1740
+ }
1741
+
1742
+ int readCards( const char *string, const int maxCards,
1743
+ uint8_t *cards, int *charsConsumed )
1744
+ {
1745
+ int i, c, r;
1746
+
1747
+ c = 0;
1748
+ for( i = 0; i < maxCards; ++i ) {
1749
+
1750
+ r = readCard( &string[ c ], &cards[ i ] );
1751
+ if( r < 0 ) {
1752
+ break;
1753
+ }
1754
+ c += r;
1755
+ }
1756
+
1757
+ *charsConsumed = c;
1758
+ return i;
1759
+ }
1760
+
1761
+ int printCard( const uint8_t card, const int maxLen, char *string )
1762
+ {
1763
+ if( 3 > maxLen ) {
1764
+ return -1;
1765
+ }
1766
+
1767
+ string[ 0 ] = rankChars[ rankOfCard( card ) ];
1768
+ string[ 1 ] = suitChars[ suitOfCard( card ) ];
1769
+ string[ 2 ] = 0;
1770
+
1771
+ return 2;
1772
+ }
1773
+
1774
+ int printCards( const int numCards, const uint8_t *cards,
1775
+ const int maxLen, char *string )
1776
+ {
1777
+ int i, c, r;
1778
+
1779
+ c = 0;
1780
+
1781
+ for( i = 0; i < numCards; ++i ) {
1782
+
1783
+ r = printCard( cards[ i ], maxLen - c, &string[ c ] );
1784
+ if( r < 0 ) {
1785
+ return -1;
1786
+ }
1787
+ c += r;
1788
+ }
1789
+
1790
+ /* no need to null terminate, we know for sure that printCard does */
1791
+
1792
+ return c;
1793
+ }