poker_eval 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/COPYING +56 -0
- data/COPYING.ja +51 -0
- data/Gemfile +4 -0
- data/History.txt +3 -0
- data/README.txt +9 -0
- data/Rakefile +23 -0
- data/VERSION +1 -0
- data/ext/poker_eval_api/extconf.rb +4 -0
- data/ext/poker_eval_api/poker_eval.c +981 -0
- data/lib/poker_eval.rb +76 -0
- data/poker_eval.gemspec +55 -0
- data/tasks/jeweler.rake +25 -0
- data/tasks/native.rake +30 -0
- data/test/test_poker_eval.rb +37 -0
- metadata +82 -0
@@ -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
|
+
|