poker_eval 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,981 @@
1
+ #include "ruby.h"
2
+
3
+ /*
4
+ *
5
+ * Corbright (C) 2007, 2008 Loic Dachary <loic@dachary.org>
6
+ * Corbright (C) 2004, 2005, 2006 Mekensleep
7
+ *
8
+ * Mekensleep
9
+ * 24 rue vieille du temple
10
+ * 75004 Paris
11
+ * licensing@mekensleep.com
12
+ *
13
+ * This program is free software; you can redistribute it and/or modify
14
+ * it under the terms of the GNU General Public License as published by
15
+ * the Free Software Foundation; either version 3 of the License, or
16
+ * (at your option) any later version.
17
+ *
18
+ * This program is distributed in the hope that it will be useful,
19
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
20
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21
+ * GNU General Public License for more details.
22
+ *
23
+ * You should have received a corb of the GNU General Public License
24
+ * along with this program; if not, write to the Free Software
25
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
26
+ *
27
+ * Authors:
28
+ * Loic Dachary <loic@dachary.org>
29
+ *
30
+ */
31
+
32
+
33
+ /* enumerate.c -- functions to compute pot equity by enumerating outcomes
34
+ Exports:
35
+ enumExhaustive() exhaustive enumeration of outcomes
36
+ enumGameParams() look up rule parameters by game type
37
+ enumResultClear() clear enumeration result object
38
+ enumResultPrint() print enumeration result object
39
+ enumResultPrintTerse() print enumeration result object, tersely
40
+ enumSample() monte carlo sampling of outcomes
41
+
42
+ Michael Maurer, Apr 2002
43
+ */
44
+
45
+ #include "poker_defs.h"
46
+ #include "inlines/eval.h"
47
+ #include "inlines/eval_low.h"
48
+ #include "inlines/eval_low8.h"
49
+ #include "inlines/eval_joker_low.h"
50
+ #include "inlines/eval_omaha.h"
51
+ #include "deck_std.h"
52
+ #include "rules_std.h"
53
+
54
+ #include "enumerate.h"
55
+ #include "enumdefs.h"
56
+
57
+ /* INNER_LOOP is executed in every iteration of the combinatorial enumerator
58
+ macros DECK_ENUMERATE_n_CARDS_D() and DECK_ENUMERATE_PERMUTATIONS_D. It
59
+ evaluates each player's hand based on the enumerated community cards and
60
+ accumulates statistics on wins, ties, losses, and pot equity.
61
+
62
+ Macro argument:
63
+ evalwrap -- code that evaluates pockets[i], board, sharedCards, and/or
64
+ unsharedCards[i] as a poker hand, then stores the result
65
+ in hival[i] and loval[i] and stores an error code in err
66
+ Loop variable: either of
67
+ StdDeck_CardMask sharedCards;
68
+ StdDeck_CardMask unsharedCards[];
69
+ Inputs:
70
+ StdDeck_CardMask pockets[];
71
+ StdDeck_CardMask board;
72
+ int npockets;
73
+ Outputs:
74
+ enum_result_t *result;
75
+ */
76
+
77
+ #define INNER_LOOP(evalwrap) \
78
+ do { \
79
+ int i; \
80
+ HandVal hival[ENUM_MAXPLAYERS]; \
81
+ LowHandVal loval[ENUM_MAXPLAYERS]; \
82
+ HandVal besthi = HandVal_NOTHING; \
83
+ LowHandVal bestlo = LowHandVal_NOTHING; \
84
+ int hishare = 0; \
85
+ int loshare = 0; \
86
+ double hipot, lopot; \
87
+ /* find winning hands for high and low */ \
88
+ for (i=0; i<sizeToDeal-1; i++) { \
89
+ int err; \
90
+ { evalwrap } \
91
+ if (err != 0) \
92
+ return 1000 + err; \
93
+ if (hival[i] != HandVal_NOTHING) { \
94
+ if (hival[i] > besthi) { \
95
+ besthi = hival[i]; \
96
+ hishare = 1; \
97
+ } else if (hival[i] == besthi) { \
98
+ hishare++; \
99
+ } \
100
+ } \
101
+ if (loval[i] != LowHandVal_NOTHING) { \
102
+ if (loval[i] < bestlo) { \
103
+ bestlo = loval[i]; \
104
+ loshare = 1; \
105
+ } else if (loval[i] == bestlo) { \
106
+ loshare++; \
107
+ } \
108
+ } \
109
+ } \
110
+ /* now award pot fractions to winning hands */ \
111
+ if (bestlo != LowHandVal_NOTHING && \
112
+ besthi != HandVal_NOTHING) { \
113
+ hipot = 0.5 / hishare; \
114
+ lopot = 0.5 / loshare; \
115
+ } else if (bestlo == LowHandVal_NOTHING && \
116
+ besthi != HandVal_NOTHING) { \
117
+ hipot = 1.0 / hishare; \
118
+ lopot = 0; \
119
+ } else if (bestlo != LowHandVal_NOTHING && \
120
+ besthi == HandVal_NOTHING) { \
121
+ hipot = 0; \
122
+ lopot = 1.0 / loshare; \
123
+ } else { \
124
+ hipot = lopot = 0; \
125
+ } \
126
+ for (i=0; i<sizeToDeal-1; i++) { \
127
+ double potfrac = 0; \
128
+ int H = 0, L = 0; \
129
+ if (hival[i] != HandVal_NOTHING) { \
130
+ if (hival[i] == besthi) { \
131
+ H = hishare; \
132
+ potfrac += hipot; \
133
+ if (hishare == 1) \
134
+ result->nwinhi[i]++; \
135
+ else \
136
+ result->ntiehi[i]++; \
137
+ } else { \
138
+ result->nlosehi[i]++; \
139
+ } \
140
+ } \
141
+ if (loval[i] != LowHandVal_NOTHING) { \
142
+ if (loval[i] == bestlo) { \
143
+ L = loshare; \
144
+ potfrac += lopot; \
145
+ if (loshare == 1) \
146
+ result->nwinlo[i]++; \
147
+ else \
148
+ result->ntielo[i]++; \
149
+ } else { \
150
+ result->nloselo[i]++; \
151
+ } \
152
+ } \
153
+ result->nsharehi[i][H]++; \
154
+ result->nsharelo[i][L]++; \
155
+ result->nshare[i][H][L]++; \
156
+ if (potfrac > 0.99) \
157
+ result->nscoop[i]++; \
158
+ result->ev[i] += potfrac; \
159
+ } \
160
+ result->nsamples++; \
161
+ } while (0);
162
+
163
+ #define INNER_LOOP_ANY_HIGH \
164
+ INNER_LOOP({ \
165
+ StdDeck_CardMask _hand; \
166
+ StdDeck_CardMask _finalBoard; \
167
+ StdDeck_CardMask_RESET(_hand); \
168
+ StdDeck_CardMask_RESET(_finalBoard); \
169
+ StdDeck_CardMask_OR(_finalBoard, board, cardsDealt[0]); \
170
+ StdDeck_CardMask_OR(_hand, pockets[i], _finalBoard); \
171
+ StdDeck_CardMask_OR(_hand, _hand, cardsDealt[i + 1]); \
172
+ hival[i] = StdDeck_StdRules_EVAL_N(_hand, 7); \
173
+ loval[i] = LowHandVal_NOTHING; \
174
+ err = 0; \
175
+ })
176
+
177
+ #define INNER_LOOP_ANY_HILO \
178
+ INNER_LOOP({ \
179
+ StdDeck_CardMask _hand; \
180
+ StdDeck_CardMask _finalBoard; \
181
+ StdDeck_CardMask_RESET(_hand); \
182
+ StdDeck_CardMask_RESET(_finalBoard); \
183
+ StdDeck_CardMask_OR(_finalBoard, board, cardsDealt[0]); \
184
+ StdDeck_CardMask_OR(_hand, pockets[i], _finalBoard); \
185
+ StdDeck_CardMask_OR(_hand, _hand, cardsDealt[i + 1]); \
186
+ hival[i] = StdDeck_StdRules_EVAL_N(_hand, 7); \
187
+ loval[i] = StdDeck_Lowball8_EVAL(_hand, 7); \
188
+ err = 0; \
189
+ })
190
+
191
+ #define INNER_LOOP_OMAHA \
192
+ INNER_LOOP({ \
193
+ StdDeck_CardMask _hand; \
194
+ StdDeck_CardMask _finalBoard; \
195
+ StdDeck_CardMask_RESET(_hand); \
196
+ StdDeck_CardMask_RESET(_finalBoard); \
197
+ StdDeck_CardMask_OR(_finalBoard, board, cardsDealt[0]); \
198
+ StdDeck_CardMask_OR(_hand, pockets[i], cardsDealt[i + 1]); \
199
+ err = StdDeck_OmahaHiLow8_EVAL(_hand, _finalBoard, \
200
+ &hival[i], NULL); \
201
+ loval[i] = LowHandVal_NOTHING; \
202
+ })
203
+
204
+ #define INNER_LOOP_OMAHA8 \
205
+ INNER_LOOP({ \
206
+ StdDeck_CardMask _hand; \
207
+ StdDeck_CardMask _finalBoard; \
208
+ StdDeck_CardMask_RESET(_hand); \
209
+ StdDeck_CardMask_RESET(_finalBoard); \
210
+ StdDeck_CardMask_OR(_finalBoard, board, cardsDealt[0]); \
211
+ StdDeck_CardMask_OR(_hand, pockets[i], cardsDealt[i + 1]); \
212
+ err = StdDeck_OmahaHiLow8_EVAL(_hand, _finalBoard, \
213
+ &hival[i], &loval[i]); \
214
+ })
215
+
216
+ #define INNER_LOOP_7STUDNSQ \
217
+ INNER_LOOP({ \
218
+ StdDeck_CardMask _hand; \
219
+ StdDeck_CardMask_OR(_hand, pockets[i], cardsDealt[i + 1]); \
220
+ hival[i] = StdDeck_StdRules_EVAL_N(_hand, 7); \
221
+ loval[i] = StdDeck_Lowball_EVAL(_hand, 7); \
222
+ err = 0; \
223
+ })
224
+
225
+ #define INNER_LOOP_RAZZ \
226
+ INNER_LOOP({ \
227
+ StdDeck_CardMask _hand; \
228
+ StdDeck_CardMask_OR(_hand, pockets[i], cardsDealt[i + 1]); \
229
+ hival[i] = HandVal_NOTHING; \
230
+ loval[i] = StdDeck_Lowball_EVAL(_hand, 7); \
231
+ err = 0; \
232
+ })
233
+
234
+ #define INNER_LOOP_5DRAW \
235
+ INNER_LOOP({ \
236
+ JokerDeck_CardMask _hand; \
237
+ JokerDeck_CardMask_OR(_hand, pockets[i], cardsDealt[i + 1]); \
238
+ hival[i] = JokerDeck_JokerRules_EVAL_N(_hand, 5); \
239
+ loval[i] = LowHandVal_NOTHING; \
240
+ err = 0; \
241
+ })
242
+
243
+ #define INNER_LOOP_5DRAW8 \
244
+ INNER_LOOP({ \
245
+ JokerDeck_CardMask _hand; \
246
+ JokerDeck_CardMask_OR(_hand, pockets[i], cardsDealt[i + 1]); \
247
+ hival[i] = JokerDeck_JokerRules_EVAL_N(_hand, 5); \
248
+ loval[i] = JokerDeck_Lowball8_EVAL(_hand, 5); \
249
+ err = 0; \
250
+ })
251
+
252
+ #define INNER_LOOP_5DRAWNSQ \
253
+ INNER_LOOP({ \
254
+ JokerDeck_CardMask _hand; \
255
+ JokerDeck_CardMask_OR(_hand, pockets[i], cardsDealt[i + 1]); \
256
+ hival[i] = JokerDeck_JokerRules_EVAL_N(_hand, 5); \
257
+ loval[i] = JokerDeck_Lowball_EVAL(_hand, 5); \
258
+ err = 0; \
259
+ })
260
+
261
+ #define INNER_LOOP_LOWBALL \
262
+ INNER_LOOP({ \
263
+ JokerDeck_CardMask _hand; \
264
+ JokerDeck_CardMask_OR(_hand, pockets[i], cardsDealt[i + 1]); \
265
+ hival[i] = HandVal_NOTHING; \
266
+ loval[i] = JokerDeck_Lowball_EVAL(_hand, 5); \
267
+ err = 0; \
268
+ })
269
+
270
+ #define INNER_LOOP_LOWBALL27 \
271
+ INNER_LOOP({ \
272
+ StdDeck_CardMask _hand; \
273
+ StdDeck_CardMask_OR(_hand, pockets[i], cardsDealt[i + 1]); \
274
+ hival[i] = HandVal_NOTHING; \
275
+ loval[i] = StdDeck_StdRules_EVAL_N(_hand, 5); \
276
+ err = 0; \
277
+ })
278
+
279
+ static int
280
+ rbenumExhaustive(enum_game_t game, StdDeck_CardMask pockets[],
281
+ int numToDeal[],
282
+ StdDeck_CardMask board, StdDeck_CardMask dead,
283
+ int sizeToDeal, enum_result_t *result) {
284
+ int totalToDeal = 0;
285
+ int i;
286
+ enumResultClear(result);
287
+ StdDeck_CardMask cardsDealt[ENUM_MAXPLAYERS + 1];
288
+ memset(cardsDealt, 0, sizeof(StdDeck_CardMask) * (ENUM_MAXPLAYERS + 1));
289
+ if (sizeToDeal - 1 > ENUM_MAXPLAYERS)
290
+ return 1;
291
+ for(i = 0; i < sizeToDeal; i++)
292
+ totalToDeal += numToDeal[i];
293
+
294
+ /*
295
+ * Cards in pockets or in the board must not be dealt
296
+ */
297
+ StdDeck_CardMask_OR(dead, dead, board);
298
+ for(i = 0; i < sizeToDeal - 1; i++) {
299
+ StdDeck_CardMask_OR(dead, dead, pockets[i]);
300
+ }
301
+
302
+ if (game == game_holdem) {
303
+ if(totalToDeal > 0) {
304
+ DECK_ENUMERATE_COMBINATIONS_D(StdDeck, cardsDealt,
305
+ sizeToDeal, numToDeal,
306
+ dead, INNER_LOOP_ANY_HIGH);
307
+ } else {
308
+ INNER_LOOP_ANY_HIGH;
309
+ }
310
+ } else if (game == game_holdem8) {
311
+ if(totalToDeal > 0) {
312
+ DECK_ENUMERATE_COMBINATIONS_D(StdDeck, cardsDealt,
313
+ sizeToDeal, numToDeal,
314
+ dead, INNER_LOOP_ANY_HILO);
315
+ } else {
316
+ INNER_LOOP_ANY_HILO;
317
+ }
318
+ } else if (game == game_omaha) {
319
+ if(totalToDeal > 0) {
320
+ DECK_ENUMERATE_COMBINATIONS_D(StdDeck, cardsDealt,
321
+ sizeToDeal, numToDeal,
322
+ dead, INNER_LOOP_OMAHA);
323
+ } else {
324
+ INNER_LOOP_OMAHA;
325
+ }
326
+ } else if (game == game_omaha8) {
327
+ if(totalToDeal > 0) {
328
+ DECK_ENUMERATE_COMBINATIONS_D(StdDeck, cardsDealt,
329
+ sizeToDeal, numToDeal,
330
+ dead, INNER_LOOP_OMAHA8);
331
+ } else {
332
+ INNER_LOOP_OMAHA8;
333
+ }
334
+ } else if (game == game_7stud) {
335
+ if(totalToDeal > 0) {
336
+ DECK_ENUMERATE_COMBINATIONS_D(StdDeck, cardsDealt,
337
+ sizeToDeal, numToDeal,
338
+ dead, INNER_LOOP_ANY_HIGH);
339
+ } else {
340
+ INNER_LOOP_ANY_HIGH;
341
+ }
342
+ } else if (game == game_7stud8) {
343
+ if(totalToDeal > 0) {
344
+ DECK_ENUMERATE_COMBINATIONS_D(StdDeck, cardsDealt,
345
+ sizeToDeal, numToDeal,
346
+ dead, INNER_LOOP_ANY_HILO);
347
+ } else {
348
+ INNER_LOOP_ANY_HILO;
349
+ }
350
+ } else if (game == game_7studnsq) {
351
+ DECK_ENUMERATE_COMBINATIONS_D(StdDeck, cardsDealt,
352
+ sizeToDeal, numToDeal,
353
+ dead, INNER_LOOP_7STUDNSQ);
354
+ } else if (game == game_razz) {
355
+ DECK_ENUMERATE_COMBINATIONS_D(StdDeck, cardsDealt,
356
+ sizeToDeal, numToDeal,
357
+ dead, INNER_LOOP_RAZZ);
358
+ } else if (game == game_lowball27) {
359
+ DECK_ENUMERATE_COMBINATIONS_D(StdDeck, cardsDealt,
360
+ sizeToDeal, numToDeal,
361
+ dead, INNER_LOOP_LOWBALL27);
362
+ } else {
363
+ return 1;
364
+ }
365
+
366
+ result->game = game;
367
+ result->nplayers = sizeToDeal - 1;
368
+ result->sampleType = ENUM_EXHAUSTIVE;
369
+ return 0;
370
+ }
371
+
372
+ static int
373
+ rbenumSample(enum_game_t game, StdDeck_CardMask pockets[],
374
+ int numToDeal[],
375
+ StdDeck_CardMask board, StdDeck_CardMask dead,
376
+ int sizeToDeal, int iterations, enum_result_t *result) {
377
+ int i;
378
+ enumResultClear(result);
379
+ StdDeck_CardMask cardsDealt[ENUM_MAXPLAYERS + 1];
380
+ memset(cardsDealt, 0, sizeof(StdDeck_CardMask) * (ENUM_MAXPLAYERS + 1));
381
+ if (sizeToDeal - 1 > ENUM_MAXPLAYERS)
382
+ return 1;
383
+
384
+ /*
385
+ * Cards in pockets or in the board must not be dealt
386
+ */
387
+ StdDeck_CardMask_OR(dead, dead, board);
388
+ for(i = 0; i < sizeToDeal - 1; i++) {
389
+ StdDeck_CardMask_OR(dead, dead, pockets[i]);
390
+ }
391
+
392
+ if (game == game_holdem) {
393
+ DECK_MONTECARLO_PERMUTATIONS_D(StdDeck, cardsDealt,
394
+ sizeToDeal, numToDeal,
395
+ dead, iterations, INNER_LOOP_ANY_HIGH);
396
+ } else if (game == game_holdem8) {
397
+ DECK_MONTECARLO_PERMUTATIONS_D(StdDeck, cardsDealt,
398
+ sizeToDeal, numToDeal,
399
+ dead, iterations, INNER_LOOP_ANY_HILO);
400
+ } else if (game == game_omaha) {
401
+ DECK_MONTECARLO_PERMUTATIONS_D(StdDeck, cardsDealt,
402
+ sizeToDeal, numToDeal,
403
+ dead, iterations, INNER_LOOP_OMAHA);
404
+ } else if (game == game_omaha8) {
405
+ DECK_MONTECARLO_PERMUTATIONS_D(StdDeck, cardsDealt,
406
+ sizeToDeal, numToDeal,
407
+ dead, iterations, INNER_LOOP_OMAHA8);
408
+ } else if (game == game_7stud) {
409
+ DECK_MONTECARLO_PERMUTATIONS_D(StdDeck, cardsDealt,
410
+ sizeToDeal, numToDeal,
411
+ dead, iterations, INNER_LOOP_ANY_HIGH);
412
+ } else if (game == game_7stud8) {
413
+ DECK_MONTECARLO_PERMUTATIONS_D(StdDeck, cardsDealt,
414
+ sizeToDeal, numToDeal,
415
+ dead, iterations, INNER_LOOP_ANY_HILO);
416
+ } else if (game == game_7studnsq) {
417
+ DECK_MONTECARLO_PERMUTATIONS_D(StdDeck, cardsDealt,
418
+ sizeToDeal, numToDeal,
419
+ dead, iterations, INNER_LOOP_7STUDNSQ);
420
+ } else if (game == game_razz) {
421
+ DECK_MONTECARLO_PERMUTATIONS_D(StdDeck, cardsDealt,
422
+ sizeToDeal, numToDeal,
423
+ dead, iterations, INNER_LOOP_RAZZ);
424
+ } else if (game == game_lowball27) {
425
+ DECK_MONTECARLO_PERMUTATIONS_D(StdDeck, cardsDealt,
426
+ sizeToDeal, numToDeal,
427
+ dead, iterations, INNER_LOOP_LOWBALL27);
428
+ } else {
429
+ return 1;
430
+ }
431
+
432
+ result->game = game;
433
+ result->nplayers = sizeToDeal - 1;
434
+ result->sampleType = ENUM_SAMPLE;
435
+ return 0;
436
+ }
437
+
438
+ #define NOCARD 255
439
+
440
+ static int rbList2CardMask(VALUE object, CardMask* cardsp)
441
+ {
442
+ CardMask cards;
443
+ int cards_size = 0;
444
+ int valid_cards_size = 0;
445
+
446
+ if (TYPE(object) != T_ARRAY)
447
+ {
448
+ rb_fatal("expected a list of cards");
449
+ }
450
+
451
+ valid_cards_size = cards_size = RARRAY_LENINT(object);
452
+ CardMask_RESET(cards);
453
+
454
+ int card;
455
+ int i;
456
+ for(i = 0; i < cards_size; i++) {
457
+ card = -1;
458
+ char* card_string = RSTRING_PTR(rb_ary_entry(object, i));
459
+
460
+ if(!strcmp(card_string, "__"))
461
+ card = 255;
462
+ else
463
+ if(Deck_stringToCard(card_string, &card) == 0)
464
+ rb_fatal("card %s is not a valid card name", card_string);
465
+
466
+ if(card == NOCARD)
467
+ valid_cards_size--;
468
+ else
469
+ CardMask_SET(cards, card);
470
+ }
471
+
472
+ *cardsp = cards;
473
+
474
+ return valid_cards_size;
475
+ }
476
+
477
+ static VALUE
478
+ CardMask2SortedRbList(CardMask hand, int low)
479
+ {
480
+ int i;
481
+ HandVal handval;
482
+ VALUE result = rb_ary_new();
483
+
484
+ if(StdDeck_CardMask_IS_EMPTY(hand)) {
485
+ rb_ary_push(result, rb_str_new2("Nothing"));
486
+ return result;
487
+ }
488
+
489
+ if(low) {
490
+ handval = Hand_EVAL_LOW8(hand, 5);
491
+ } else {
492
+ handval = Hand_EVAL_N(hand, 5);
493
+ }
494
+
495
+ int htype = HandVal_HANDTYPE(handval);
496
+ {
497
+ rb_ary_push(result, rb_str_new2(StdRules_handTypeNames[htype]));
498
+ }
499
+
500
+ if(!low || htype != LowHandVal_NOTHING) {
501
+ if (StdRules_nSigCards[htype] >= 1) {
502
+ int rank = HandVal_TOP_CARD(handval);
503
+ if(low) rank = LOWRANK2RANK(rank);
504
+
505
+ if(htype == HandType_STRAIGHT || htype == HandType_STFLUSH) {
506
+ for(i = rank; rank - i < 5; i--) {
507
+ int rank_modulo = i < 0 ? StdDeck_Rank_ACE : i;
508
+ rb_ary_push(result, INT2NUM(findanddelete(&hand, rank_modulo)));
509
+ /* PyObject* pyvalue = Py_BuildValue("i", findanddelete(&hand, rank_modulo));*/
510
+ /* PyList_Append(result, pyvalue);*/
511
+ /* Py_DECREF(pyvalue);*/
512
+ }
513
+ } else {
514
+ int count;
515
+ switch(htype) {
516
+ case HandType_ONEPAIR:
517
+ case HandType_TWOPAIR:
518
+ count = 2;
519
+ break;
520
+ case HandType_TRIPS:
521
+ case HandType_FULLHOUSE:
522
+ count = 3;
523
+ break;
524
+ case HandType_QUADS:
525
+ count = 4;
526
+ break;
527
+ default:
528
+ count = 1;
529
+ break;
530
+ }
531
+ for(i = 0; i < count; i++) {
532
+ rb_ary_push(result, INT2NUM(findanddelete(&hand, rank)));
533
+ /* PyObject* pyvalue = Py_BuildValue("i", findanddelete(&hand, rank));*/
534
+ /* PyList_Append(result, pyvalue);*/
535
+ /* Py_DECREF(pyvalue);*/
536
+ }
537
+ }
538
+ }
539
+ if (StdRules_nSigCards[htype] >= 2) {
540
+ int rank = HandVal_SECOND_CARD(handval);
541
+ int count = 1;
542
+ if(low) rank = LOWRANK2RANK(rank);
543
+ if(htype == HandType_TWOPAIR ||
544
+ htype == HandType_FULLHOUSE)
545
+ count = 2;
546
+
547
+ for(i = 0; i < count; i++) {
548
+ rb_ary_push(result, INT2NUM(findanddelete(&hand, rank)));
549
+ /* PyObject* pyvalue = Py_BuildValue("i", findanddelete(&hand, rank));*/
550
+ /* PyList_Append(result, pyvalue);*/
551
+ /* Py_DECREF(pyvalue);*/
552
+ }
553
+ }
554
+
555
+ if (StdRules_nSigCards[htype] >= 3) {
556
+ int rank = HandVal_THIRD_CARD(handval);
557
+ if(low) rank = LOWRANK2RANK(rank);
558
+ rb_ary_push(result, INT2NUM(findanddelete(&hand, rank)));
559
+ /* PyObject* pyvalue = Py_BuildValue("i", findanddelete(&hand, rank));*/
560
+ /* PyList_Append(result, pyvalue);*/
561
+ /* Py_DECREF(pyvalue);*/
562
+ }
563
+
564
+ if (StdRules_nSigCards[htype] >= 4) {
565
+ int rank = HandVal_FOURTH_CARD(handval);
566
+ if(low) rank = LOWRANK2RANK(rank);
567
+ rb_ary_push(result, INT2NUM(findanddelete(&hand, rank)));
568
+ /* PyObject* pyvalue = Py_BuildValue("i", findanddelete(&hand, rank));*/
569
+ /* PyList_Append(result, pyvalue);*/
570
+ /* Py_DECREF(pyvalue);*/
571
+ }
572
+
573
+ if (StdRules_nSigCards[htype] >= 5) {
574
+ int rank = HandVal_FIFTH_CARD(handval);
575
+ if(low) rank = LOWRANK2RANK(rank);
576
+ rb_ary_push(result, INT2NUM(findanddelete(&hand, rank)));
577
+ /* PyObject* pyvalue = Py_BuildValue("i", findanddelete(&hand, rank));*/
578
+ /* PyList_Append(result, pyvalue);*/
579
+ /* Py_DECREF(pyvalue);*/
580
+ }
581
+
582
+ }
583
+
584
+ /*
585
+ * Append remaining cards, highest first
586
+ */
587
+ for(i = Deck_N_CARDS - 1; i >= 0; i--) {
588
+ if (StdDeck_CardMask_CARD_IS_SET(hand, i)) {
589
+ rb_ary_push(result, INT2NUM(i));
590
+ /* PyObject* pyvalue = Py_BuildValue("i", i);*/
591
+ /* PyList_Append(result, pyvalue);*/
592
+ /* Py_DECREF(pyvalue);*/
593
+ }
594
+ }
595
+
596
+ return result;
597
+ }
598
+
599
+ /*
600
+ * Find the card with highest suit matching rank in hand
601
+ * and remove it from hand. The removed card is returned.
602
+ */
603
+ int findanddelete(CardMask* hand, int rank)
604
+ {
605
+ int suit;
606
+ for(suit = StdDeck_Suit_LAST; suit >= StdDeck_Suit_FIRST; suit--) {
607
+ int card = StdDeck_MAKE_CARD(rank, suit);
608
+ if(CardMask_CARD_IS_SET(*hand, card)) {
609
+ CardMask_UNSET(*hand, card);
610
+ return card;
611
+ }
612
+ }
613
+ return -1;
614
+ }
615
+
616
+ static VALUE
617
+ t_card2Rbstring(VALUE self, VALUE args)
618
+ {
619
+ int card = 0;
620
+
621
+ card = NUM2INT(args);
622
+
623
+ /* if (!PyArg_ParseTuple(args, "i", &card))*/
624
+ /* return NULL;*/
625
+
626
+ if(card == 255) {
627
+ return rb_str_new2("__");
628
+ } else {
629
+ /*
630
+ * Avoid using GenericDeck_cardString as long as it insists
631
+ * on using the "static thread" hack (see lib/deck.c).
632
+ */
633
+ char tmp[16];
634
+ StdDeck.cardToString(card, tmp);
635
+ rb_str_new2(tmp);
636
+ }
637
+ }
638
+
639
+ static int
640
+ OmahaHiLow8_Best(StdDeck_CardMask hole, StdDeck_CardMask board,
641
+ HandVal *hival, LowHandVal *loval,
642
+ StdDeck_CardMask *hicards, StdDeck_CardMask *locards) {
643
+ StdDeck_CardMask allcards;
644
+ LowHandVal allval;
645
+ HandVal curhi, besthi;
646
+ LowHandVal curlo, bestlo;
647
+ StdDeck_CardMask hole1[OMAHA_MAXHOLE];
648
+ StdDeck_CardMask board1[OMAHA_MAXBOARD];
649
+ StdDeck_CardMask n1, n2, n3, n4, n5;
650
+ int nhole, nboard;
651
+ int eligible = 0;
652
+ int i, h1, h2, b1, b2, b3;
653
+
654
+ /* pluck out individual cards from hole and board masks, save in arrays */
655
+ nhole = nboard = 0;
656
+ for (i=0; i<StdDeck_N_CARDS; i++) {
657
+ if (StdDeck_CardMask_CARD_IS_SET(hole, i)) {
658
+ if (nhole >= OMAHA_MAXHOLE)
659
+ return 1; /* too many hole cards */
660
+ StdDeck_CardMask_RESET(hole1[nhole]);
661
+ StdDeck_CardMask_SET(hole1[nhole], i);
662
+ nhole++;
663
+ }
664
+ if (StdDeck_CardMask_CARD_IS_SET(board, i)) {
665
+ if (StdDeck_CardMask_CARD_IS_SET(hole, i)) /* same card in hole and board */
666
+ return 2;
667
+ if (nboard >= OMAHA_MAXBOARD)
668
+ return 3; /* too many board cards */
669
+ StdDeck_CardMask_RESET(board1[nboard]);
670
+ StdDeck_CardMask_SET(board1[nboard], i);
671
+ nboard++;
672
+ }
673
+ }
674
+
675
+ if (nhole < OMAHA_MINHOLE || nhole > OMAHA_MAXHOLE)
676
+ return 4; /* wrong # of hole cards */
677
+ if (nboard < OMAHA_MINBOARD || nboard > OMAHA_MAXBOARD)
678
+ return 5; /* wrong # of board cards */
679
+
680
+ /* quick test in case no low is possible with all 9 cards */
681
+ if (loval != NULL) {
682
+ StdDeck_CardMask_OR(allcards, hole, board);
683
+ allval = StdDeck_Lowball8_EVAL(allcards, nhole + nboard);
684
+ eligible = (allval != LowHandVal_NOTHING);
685
+ }
686
+
687
+ /* loop over all combinations of hole with board (60 for 4 hole cards
688
+ and 5 board cards). */
689
+ besthi = HandVal_NOTHING;
690
+ bestlo = LowHandVal_NOTHING;
691
+ /* {h1,h2} loop over all hole card combinations */
692
+ for (h1=0; h1<nhole-1; h1++) {
693
+ StdDeck_CardMask_RESET(n1);
694
+ StdDeck_CardMask_OR(n1, n1, hole1[h1]);
695
+ for (h2=h1+1; h2<nhole; h2++) {
696
+ StdDeck_CardMask_OR(n2, n1, hole1[h2]);
697
+ /* {b1,b2,b3} loop over all board card combinations */
698
+ for (b1=0; b1<nboard-2; b1++) {
699
+ StdDeck_CardMask_OR(n3, n2, board1[b1]);
700
+ for (b2=b1+1; b2<nboard-1; b2++) {
701
+ StdDeck_CardMask_OR(n4, n3, board1[b2]);
702
+ for (b3=b2+1; b3<nboard; b3++) {
703
+ if (hival != NULL) {
704
+ StdDeck_CardMask_OR(n5, n4, board1[b3]);
705
+ curhi = StdDeck_StdRules_EVAL_N(n5, 5);
706
+ if (curhi > besthi || besthi == HandVal_NOTHING) {
707
+ besthi = curhi;
708
+ *hicards = n5;
709
+ }
710
+ }
711
+ if (loval != NULL && eligible) {
712
+ curlo = StdDeck_Lowball8_EVAL(n5, 5);
713
+ if (curlo < bestlo || bestlo == LowHandVal_NOTHING) {
714
+ bestlo = curlo;
715
+ *locards = n5;
716
+ }
717
+ }
718
+ }
719
+ }
720
+ }
721
+ }
722
+ }
723
+ if (hival != NULL) *hival = besthi;
724
+ if (loval != NULL) *loval = bestlo;
725
+ return 0;
726
+ }
727
+
728
+ static VALUE
729
+ t_eval_hand(VALUE self, VALUE args)
730
+ {
731
+ VALUE result = 0;
732
+ VALUE rbboard = 0;
733
+ VALUE rbhand = 0;
734
+ char* hilow_string = 0;
735
+
736
+ hilow_string = RSTRING_PTR(rb_hash_aref(args, rb_str_new2("side")));
737
+ rbboard = rb_hash_aref(args, rb_str_new2("board"));
738
+ rbhand = rb_hash_aref(args, rb_str_new2("hand"));
739
+
740
+ int low = 0;
741
+ CardMask hand;
742
+ CardMask board;
743
+ int board_size = 0;
744
+ CardMask best;
745
+ HandVal best_handval;
746
+
747
+ StdDeck_CardMask_RESET(best);
748
+
749
+ if(!strcmp(hilow_string, "low")) {
750
+ low = 1;
751
+ }
752
+
753
+ if(rbList2CardMask(rbhand, &hand) < 0)
754
+ rb_fatal("empty hand given");
755
+
756
+ if( !NIL_P(rbboard))
757
+ {
758
+ board_size = rbList2CardMask(rbboard, &board);
759
+ }
760
+
761
+ if(board_size > 0) {
762
+ CardMask hicards;
763
+ CardMask locards;
764
+ HandVal hival = 0;
765
+ HandVal loval = 0;
766
+ StdDeck_CardMask_RESET(hicards);
767
+ StdDeck_CardMask_RESET(locards);
768
+ OmahaHiLow8_Best(hand, board, &hival, &loval, &hicards, &locards);
769
+ if(low) {
770
+ best_handval = loval;
771
+ if(best_handval != LowHandVal_NOTHING)
772
+ best = locards;
773
+ } else {
774
+ best = hicards;
775
+ best_handval = hival;
776
+ }
777
+ } else {
778
+ CardMask cards;
779
+ CardMask dead;
780
+
781
+ StdDeck_CardMask_RESET(best);
782
+
783
+ StdDeck_CardMask_RESET(dead);
784
+ StdDeck_CardMask_OR(dead, dead, hand);
785
+ StdDeck_CardMask_NOT(dead, dead);
786
+
787
+ if(low) {
788
+ best_handval = LowHandVal_NOTHING;
789
+ } else {
790
+ best_handval = HandVal_NOTHING;
791
+ }
792
+
793
+ ENUMERATE_N_CARDS_D(cards, 5, dead,
794
+ {
795
+ HandVal handval;
796
+
797
+ if(low) {
798
+ handval = Hand_EVAL_LOW8(cards, 5);
799
+ } else {
800
+ handval = Hand_EVAL_N(cards, 5);
801
+ }
802
+
803
+ if(low ? (handval < best_handval) : (handval > best_handval)) {
804
+ best = cards;
805
+ best_handval = handval;
806
+ }
807
+ }
808
+ );
809
+ }
810
+
811
+ if(StdDeck_CardMask_IS_EMPTY(best)) {
812
+ best_handval = low ? 0x0FFFFFFF : 0;
813
+ }
814
+
815
+ result = rb_hash_new();
816
+ rb_hash_aset(result, rb_str_new2("value"), INT2NUM(best_handval));
817
+ rb_hash_aset(result, rb_str_new2("combination"), CardMask2SortedRbList(best, low));
818
+
819
+ return result;
820
+ }
821
+
822
+ static VALUE
823
+ t_eval(VALUE self, VALUE args)
824
+ {
825
+ int i;
826
+ int pockets_size;
827
+ int iterations = 0;
828
+ VALUE rbpockets = 0;
829
+ VALUE rbboard = 0;
830
+ VALUE rbdead = 0;
831
+ VALUE rbiterations = 0;
832
+ char* game = 0;
833
+ enum_gameparams_t* params = 0;
834
+
835
+ game = RSTRING_PTR(rb_hash_aref(args, rb_str_new2("game")));
836
+ rbpockets = rb_hash_aref(args, rb_str_new2("pockets"));
837
+ rbboard = rb_hash_aref(args, rb_str_new2("board"));
838
+ rbdead = rb_hash_aref(args, rb_str_new2("dead"));
839
+ rbiterations = rb_hash_aref(args, rb_str_new2("iterations"));
840
+
841
+ if( !NIL_P(rbiterations))
842
+ {
843
+ iterations = FIX2INT(rbiterations);
844
+ }
845
+
846
+ StdDeck_CardMask pockets[ENUM_MAXPLAYERS];
847
+ int numToDeal[ENUM_MAXPLAYERS];
848
+ CardMask dead_cards;
849
+ CardMask board_cards;
850
+
851
+ VALUE result = 0;
852
+
853
+ if(!strcmp(game, "holdem")) {
854
+ params = enumGameParams(game_holdem);
855
+ } else if(!strcmp(game, "holdem8")) {
856
+ params = enumGameParams(game_holdem8);
857
+ } else if(!strcmp(game, "omaha")) {
858
+ params = enumGameParams(game_omaha);
859
+ } else if(!strcmp(game, "omaha8")) {
860
+ params = enumGameParams(game_omaha8);
861
+ } else if(!strcmp(game, "7stud")) {
862
+ params = enumGameParams(game_7stud);
863
+ } else if(!strcmp(game, "7stud8")) {
864
+ params = enumGameParams(game_7stud8);
865
+ } else if(!strcmp(game, "7studnsq")) {
866
+ params = enumGameParams(game_7studnsq);
867
+ } else if(!strcmp(game, "razz")) {
868
+ params = enumGameParams(game_razz);
869
+ } else if(!strcmp(game, "5draw")) {
870
+ params = enumGameParams(game_5draw);
871
+ } else if(!strcmp(game, "5draw8")) {
872
+ params = enumGameParams(game_5draw8);
873
+ } else if(!strcmp(game, "5drawnsq")) {
874
+ params = enumGameParams(game_5drawnsq);
875
+ } else if(!strcmp(game, "lowball")) {
876
+ params = enumGameParams(game_lowball);
877
+ } else if(!strcmp(game, "lowball27")) {
878
+ params = enumGameParams(game_lowball27);
879
+ }
880
+
881
+ if(params == 0)
882
+ rb_fatal("game %s is not a valid value (holdem, holdem8, omaha, omaha8, 7stud, 7stud8, 7studnsq, razz, 5draw, 5draw8, 5drawnsq, lowball, lowball27)", game);
883
+
884
+ if (TYPE(rbpockets) != T_ARRAY)
885
+ rb_fatal("pockets must be list");
886
+
887
+ pockets_size = RARRAY_LENINT(rbpockets);
888
+
889
+ {
890
+ for(i = 0; i < pockets_size; i++) {
891
+ int count;
892
+ CardMask_RESET(pockets[i]);
893
+ VALUE rbpocket = rb_ary_entry(rbpockets, i);
894
+
895
+ count = rbList2CardMask(rbpocket, &pockets[i]);
896
+
897
+ if(count < 0)
898
+ goto err;
899
+ if(count < RARRAY_LEN(rbpocket))
900
+ numToDeal[i + 1] = RARRAY_LENINT(rbpocket) - count;
901
+ else
902
+ numToDeal[i + 1] = 0;
903
+ }
904
+ }
905
+
906
+
907
+ {
908
+ int count;
909
+ count = rbList2CardMask(rbboard, &board_cards);
910
+ if(count < 0)
911
+ goto err;
912
+ if(count < RARRAY_LENINT(rbboard))
913
+ numToDeal[0] = RARRAY_LENINT(rbboard) - count;
914
+ else
915
+ numToDeal[0] = 0;
916
+ }
917
+
918
+ if(!NIL_P(rbdead) && RARRAY_LEN(rbdead) > 0) {
919
+ if(rbList2CardMask(rbdead, &dead_cards) < 0){
920
+ rb_fatal("dead cards error");
921
+ }
922
+ }
923
+ else {
924
+ CardMask_RESET(dead_cards);
925
+ }
926
+
927
+ {
928
+ enum_result_t cresult;
929
+ int err;
930
+ memset(&cresult, '\0', sizeof(enum_result_t));
931
+
932
+ if(iterations > 0) {
933
+ err = rbenumSample(params->game, pockets, numToDeal, board_cards, dead_cards, pockets_size + 1, iterations, &cresult);
934
+ } else {
935
+ err = rbenumExhaustive(params->game, pockets, numToDeal, board_cards, dead_cards, pockets_size + 1, &cresult);
936
+ }
937
+ if(err != 0) {
938
+ rb_fatal("poker-eval: rbenum returned error code %d", err);
939
+ }
940
+
941
+ result = rb_hash_new();
942
+
943
+ VALUE info = rb_hash_new();
944
+ rb_hash_aset(info, rb_str_new2("samples"), INT2NUM(cresult.nsamples));
945
+ rb_hash_aset(info, rb_str_new2("haslopot"), INT2NUM(params->haslopot));
946
+ rb_hash_aset(info, rb_str_new2("hashipot"), INT2NUM(params->hashipot));
947
+
948
+ rb_hash_aset(result, rb_str_new2("info"), info);
949
+
950
+ VALUE list = rb_ary_new();
951
+ for(i = 0; i < pockets_size; i++) {
952
+ VALUE tmp = rb_hash_new();
953
+ rb_hash_aset(tmp, rb_str_new2("scoop"), INT2NUM(cresult.nscoop[i]));
954
+ rb_hash_aset(tmp, rb_str_new2("winhi"), INT2NUM(cresult.nwinhi[i]));
955
+ rb_hash_aset(tmp, rb_str_new2("losehi"), INT2NUM(cresult.nlosehi[i]));
956
+ rb_hash_aset(tmp, rb_str_new2("tiehi"), INT2NUM(cresult.ntiehi[i]));
957
+ rb_hash_aset(tmp, rb_str_new2("winlo"), INT2NUM(cresult.nwinlo[i]));
958
+ rb_hash_aset(tmp, rb_str_new2("loselo"), INT2NUM(cresult.nloselo[i]));
959
+ rb_hash_aset(tmp, rb_str_new2("tielo"), INT2NUM(cresult.ntielo[i]));
960
+ rb_hash_aset(tmp, rb_str_new2("ev"), INT2NUM((cresult.ev[i] / cresult.nsamples) * 1000));
961
+ rb_ary_push(list, tmp);
962
+ tmp = 0;
963
+ }
964
+ rb_hash_aset(result, rb_str_new2("eval"), list);
965
+ }
966
+
967
+ err:
968
+ return result;
969
+ }
970
+
971
+ VALUE cPokerEval;
972
+
973
+ void
974
+ Init_poker_eval_api()
975
+ {
976
+ cPokerEval = rb_define_class("PokerEval", rb_cObject);
977
+ rb_define_singleton_method(cPokerEval, "eval", t_eval, 1);
978
+ rb_define_singleton_method(cPokerEval, "eval_hand", t_eval_hand, 1);
979
+ rb_define_singleton_method(cPokerEval, "card2string", t_card2Rbstring, 1);
980
+ }
981
+