/* * holdodds.c -- Show hold'em odds. * Copyright (c) 2006 by James Dow Allen * * This program can be distributed or modified subject to * the terms of the GNU General Public License (version 2 * or, at your option, any later version) as published by * the Free Software Foundation. * * Joker is "jo" (code 0xff) * Code assumes 32-bit int's -- sorry. */ #include #include /* Following can be 1, higher values not well supported */ /* (Frankly, don't recall testing single joker thoroughly) */ #define NUMJOKER 0 typedef int Card; #define NUMSUIT 4 #define NUMRANK 13 #define XRANK(x) ((x) & 0xf) #define XSUIT(x) ((x) >> 4) #define DECKSIZE (NUMSUIT*NUMRANK + NUMJOKER) char name_rank[] = "--23456789TJQKAj"; char name_suit[] = "-SH-D---C------o"; #define DEUCE 2 #define JOKER 15 Card Deck[DECKSIZE]; char *name_card(char *out, Card x) { out[0] = name_rank[XRANK(x)]; out[1] = name_suit[XSUIT(x)]; out[2] = '\0'; return out; } int s2i(char *inp) { char *index(); char *s, *r; r = index(name_rank, inp[0]); s = index(name_suit, inp[1]); if (s && r) return (((s - name_suit) << 4) + r - name_rank); fprintf(stderr, "Unrecognized card *%s*\n", inp); exit(1); } void initdeck() { int i, j; Card *dp = Deck; for (i = 0; i < NUMRANK; i++) for (j = 0; j < NUMSUIT; j++) *dp++ = i + DEUCE + (1 << j + 4); for (i = 0; i < NUMJOKER; i++) *dp++ = 0xf0 | JOKER; } /* The "sample application" herein doesn't call shuffle() */ void shuffle() { int i, j, t; for (i = 0; i < DECKSIZE; i++) { j = random() % (DECKSIZE - i) + i; t = Deck[j]; Deck[j] = Deck[i]; Deck[i] = t; } } char *valnames[] = { /* Codes for hand types */ /* 0 */ "no pair", /* 1 */ "1 pair", /* 2 */ "2 pair", /* 3 */ "triplets", /* 4 */ "straight", /* 5 */ "flush", /* 6 */ "full house", /* 7 */ "4-of-a-kind", /* 8 */ "str flush", /* 9 */ "5-of-a-kind", }; /* Poker hand ranking. * Return TBccccc with T type, B tiebreaker (e.g. pair rank) * and ccccc usually the sorted cards (except for 2-pair * where they are needed for tie-breaking on second-pair.) */ int pokval(Card c0, Card c1, Card c2, Card c3, Card c4) { register int ghand; register int t, h0, h1, h2, h3, h4; int isflush; int numpair, numtrip; int i; /* Detect flush and clear suit bits */ isflush = c0 & c1 & c2 & c3 & c4 & 0xf0; h0 = c0 & 15; h1 = c1 & 15; h2 = c2 & 15; h3 = c3 & 15; h4 = c4 & 15; #define CSWAP(a, b) if (a < b) t = a, a = b, b = t CSWAP(h0, h1); CSWAP(h1, h2); CSWAP(h2, h3); CSWAP(h3, h4); CSWAP(h0, h1); CSWAP(h1, h2); CSWAP(h2, h3); CSWAP(h0, h1); CSWAP(h1, h2); CSWAP(h0, h1); /* Check adjacent cards for pairs */ numpair = (h0 == h1) + (h1 == h2) + (h2 == h3) + (h3 == h4); /* Check near-adjacent cards for triplets */ numtrip = (h0 == h2) + (h1 == h3) + (h2 == h4); if (h0 == JOKER) { if (numpair == 0) { i = h1 - h4; if (i == 3) { ghand = (isflush ? 8 : 4) << 24 | (h1 == DEUCE + 12 ? h1 : h1 + 1); goto finished; } else if (i == 4) { ghand = (isflush ? 8 : 4) << 24 | h1; goto finished; } else if (h1 == DEUCE + 12 && h2 <= DEUCE + 3) { goto fivestr; } else if (isflush) { h0 = DEUCE + 12; if (h1 == DEUCE + 12) if (h2 == --h1) if (h3 == --h2) if (h4 == --h3) --h4; goto doflush; } } h0 = DEUCE + 12; numpair += h1 == DEUCE + 12; numtrip += h2 == DEUCE + 12; } else if (numpair == 0) { i = h0 - h4; if (i == 4) { ghand = (isflush ? 8 : 4) << 24 | h0; goto finished; } else if (i == 12 && h1 == DEUCE + 3) { fivestr: ghand = (isflush ? 8 : 4) << 24 | (DEUCE + 3); goto finished; } else if (isflush) { doflush: ghand = (5) << 24; ghand |= h0 << 16 | h1 << 12 | h2 << 8 | h3 << 4 | h4; goto finished; } } /* Switch on hand type */ switch (numpair + numtrip) { case 0: /* No pair */ ghand = (0) << 24; ghand |= h0 << 16 | h1 << 12 | h2 << 8 | h3 << 4 | h4; break; case 1: /* One pair */ ghand = (1) << 24; ghand |= h0 << 16 | h1 << 12 | h2 << 8 | h3 << 4 | h4; /* Forgot where the pair is; find it again for tiebreaker */ if (h0 == h1 || h1 == h2) ghand |= h1 << 20; else ghand |= h3 << 20; break; case 2: /* Two pair */ ghand = (2) << 24; ghand |= h1 << 16 | h3 << 12 | h0 << 8 | h2 << 4 | h4; break; case 3: /* Triplets */ ghand = (3) << 24; tiebreak: ghand |= h2 << 20 | h0 << 16 | h1 << 12 | h2 << 8 | h3 << 4 | h4; break; case 4: /* Full house */ ghand = (6) << 24; goto tiebreak; case 5: /* Four-of-kind */ ghand = (7) << 24; goto tiebreak; case 7: /* Five-of-kind */ ghand = (9) << 24; goto tiebreak; default: printf("numpair = %d numtrip = %d\n", numpair, numtrip); exit(1); } finished: return ghand; } /* The "sample application" herein doesn't call pcards() */ void pcards(Card *han, int cnt) { int i; for (i = 0; i < cnt; i++) { char cardname[3]; name_card(cardname, han[i]); printf("%s ", cardname); } } /* The "sample application" herein doesn't call phand() */ void phand(char *msg, Card *han) { int val; pcards(han, 5); val = pokval(han[0], han[1], han[2], han[3], han[4]); printf(" ( %08x %s ) -- %s\n", val, valnames[val >> 24], msg); } /* Find best 5-hand from set of 7. * Do it the brute-force obvious way. */ int eval7(Card c0, Card c1, Card *rest) { int best, i; best = pokval(rest[0], rest[1], rest[2], rest[3], rest[4]); if ((i = pokval(c0, c1, rest[0], rest[1], rest[2])) > best) best = i; if ((i = pokval(c0, c1, rest[0], rest[1], rest[3])) > best) best = i; if ((i = pokval(c0, c1, rest[0], rest[1], rest[4])) > best) best = i; if ((i = pokval(c0, c1, rest[0], rest[2], rest[3])) > best) best = i; if ((i = pokval(c0, c1, rest[0], rest[2], rest[4])) > best) best = i; if ((i = pokval(c0, c1, rest[0], rest[3], rest[4])) > best) best = i; if ((i = pokval(c0, c1, rest[1], rest[2], rest[3])) > best) best = i; if ((i = pokval(c0, c1, rest[1], rest[2], rest[4])) > best) best = i; if ((i = pokval(c0, c1, rest[1], rest[3], rest[4])) > best) best = i; if ((i = pokval(c0, c1, rest[2], rest[3], rest[4])) > best) best = i; if ((i = pokval(c0, rest[0], rest[1], rest[2], rest[3])) > best)best=i; if ((i = pokval(c0, rest[0], rest[1], rest[2], rest[4])) > best)best=i; if ((i = pokval(c0, rest[0], rest[1], rest[3], rest[4])) > best)best=i; if ((i = pokval(c0, rest[0], rest[2], rest[3], rest[4])) > best)best=i; if ((i = pokval(c0, rest[1], rest[2], rest[3], rest[4])) > best)best=i; if ((i = pokval(c1, rest[0], rest[1], rest[2], rest[3])) > best)best=i; if ((i = pokval(c1, rest[0], rest[1], rest[2], rest[4])) > best)best=i; if ((i = pokval(c1, rest[0], rest[1], rest[3], rest[4])) > best)best=i; if ((i = pokval(c1, rest[0], rest[2], rest[3], rest[4])) > best)best=i; if ((i = pokval(c1, rest[1], rest[2], rest[3], rest[4])) > best)best=i; return best; } int excluded(int i, Card *a, Card *b) { i = Deck[i]; if (i != a[0] && i != a[1] && i != b[0] &&i != b[1]) return i; else return 0; } long thisto[2][10]; int main(int argc, char **argv) { Card handa[2], handb[2], rest[5]; int i1, i2, i3, i4, i5; long awin, bwin, draw; unsigned int aval, bval; setlinebuf(stdout); initdeck(); if (argc != 5) { printf("Usage: holdodds #A1 #A2 #B1 #B2 -- compare two hold'em hands\n"); printf("\tCards are '9S', 'KD', etc.\n"); exit(1); } awin = bwin = draw = 0; handa[0] = s2i(argv[1]); handa[1] = s2i(argv[2]); handb[0] = s2i(argv[3]); handb[1] = s2i(argv[4]); for (i1 = 0; i1 < DECKSIZE; i1++) if (rest[0] = excluded(i1, handa, handb)) for (i2 = i1+1; i2 < DECKSIZE; i2++) if (rest[1] = excluded(i2, handa, handb)) for (i3 = i2+1; i3 < DECKSIZE; i3++) if (rest[2] = excluded(i3, handa, handb)) for (i4 = i3+1; i4 < DECKSIZE; i4++) if (rest[3] = excluded(i4, handa, handb)) for (i5 = i4+1; i5 < DECKSIZE; i5++) if (rest[4] = excluded(i5, handa, handb)) { aval = eval7(handa[0], handa[1], rest); bval = eval7(handb[0], handb[1], rest); ++thisto[0][aval >> 24]; ++thisto[1][bval >> 24]; if (aval > bval) { ++awin; } else if (aval < bval) { ++bwin; } else { ++draw; } } printf("A wins = %f%%\n", awin * 100.0 / (awin + bwin + draw)); printf("B wins = %f%%\n", bwin * 100.0 / (awin + bwin + draw)); printf("Drawn = %f%%\n", draw * 100.0 / (awin + bwin + draw)); for (i1 = 0; i1 < 2; i1++) for (i2 = 0; i2 < 10; i2++) if (i3 = thisto[i1][i2]) printf("Player %c gets %s with prob %f%%\n", "AB"[i1], valnames[i2], i3 * 100.0 / (awin + bwin + draw)); exit(0); }