// 45UNqWe - pokr.c written by Pip Stuart to run through // Texas Hold'Em Poker hands && output XML to query for odds. // Please e-mail me if you'd like the header file (pdat.h) needed to // compile this. It's 6MB so I didn't package it with my // Games::Cards::Poker.pm but I'd be glad to ftp it to you if you have // an anonymous account somewhere && want it. The file is that big // because I traded (wasted) space for speed. I wanted to be able to // just look up any score as fast as possible && this approach was the // best I came up with. // This code is distributed under the GNU General Public License (version 2). // 2do: // port all necessary functions // + char* SortCards(char* hand) returns char[7] // + char* ShortHand(char* hand) returns char[7] // + int ScoreHand(char* shrt) loop through backwards // + int RemoveCard(int indx, char* deck) just substr? // + int FindCard(char card, char* deck) // + char* BestHand(char* hole, char* bord) returns char[6] hand // + ChooseSubsets as a fast function // + replace all char* functions to use own global pre-calloc'd mem // + mk the Choose variables global so it can pickup where it left // off && RemoveCard can be given global indices after // + mk specific versions of ChooseFlop, ChooseOpponentHole // + tk 2nd main param as which flop subset to do // + mk hole && flop shorthand datas && funcs to find index // + turn flop subset into shorthand && index // + loop turn && rivers finding shorthand index // + go through every possible flop // + ch BestHand to be BestScore for comparison // + fill data in inner loop // + benchmrk... probably about 2.5 hours per hole+flop // + dump results to XML file per hole+flop // + pre-calc totals for each step // + setup some benchmarking shell // + optimize! // + mk ScoreHands faster... some sort of hash? // + optimize!!! // + ScoreHands binary search 162secs/flop // + ScoreHands index all chars for direct scores 107secs/flop // + profile: `cc -pg -c pokr.c`, `cc -pg pokr.o` > *a.out, `a.out`, `gprof` // + imp QuickSort as ifs up to 5 // + mv big data to separate file to include // + gen hole data same as hand && mk FindHole fast too // + mk ShortHand faster // + replace ChooseFlop with selection of pre-calc'd flop groups 2do at once // + fread progress to pickup where left off // + don't store unnecessary per ohole data // + rm hdek && other extraneous stuff like shrh? // bleh... for whatever reason /un!/ lines are useless but are faster?!? // must be some goofy word-boundary alignment crap or something // + mk separate ShortOne() // + mk hpnd auto-inc at end too // + only calc BestScore for main hole + board once // + fix bug in ShortHand where 'CG is a diff suit from 'ae' // + rewrite everything from scratch to use all integers 0..51 // + fix mkPPX.pl to read h.ppx for ones to skip // + mk src test if it can read from first write of a hole && skip // + squash scoring bug && start all over // + updt web IF for XML // add oppo calc 2 cgi // add pot-odds calc 2 cgi // setup timed runs again && test doing ShortHand inside of BestScore // port to local Tk app // profile && optimize // rewrite with exact cards && start over // maybe 2do: // figure out which flops will be the same && do each unique only once // ordr: ( * = doing, + = done&&sync'd, / = left partway done&&sync'd ) // 0+== AA : 25+== KK : 48+== QQ : 69+== JJ : 88+== TT :105+== 99 : // 120+== 88 : 1+== AKs: 3+== AQs:133+== 77 : 5+== AJs: 2+== AK : // 7+== ATs: 4+== AQ : 6+== AJ : 26+== KQs: 9+== A9s: 8+== AT : // 144+== 66 : 28 == KJs: 30 == KTs: 13+== A7s: 17 == A5s: 15 == A6s: // 49+== QJs: 12+== A8 :153+== 55 : 19 == A4s: 21 == A3s: 23 == A2s: // 70+== JTs:160+== 44 : 89+== T9s:165+== 33 :106+== 98s:168+== 22 : // // 0 + AA // 1 + AKs // 2 + AK // 3 + AQs // 4 + AQ // 5 + AJs // 6 + AJ // 7 + ATs // 8 + AT // 9 + A9s // 10 + A9 // 11 + A8s // 12 + A8 // 13 + A7s // 14 + A7 // 15 + A6s // 16 + A6 // 17 + A5s // 18 + A5 // 19 + A4s // 20 + A4 // 21 + A3s // 22 + A3 // 23 + A2s // 24 + A2 // 25 + KK // 26 + KQs // 27 + KQ // 28 + KJs // 29 + KJ // 30 + KTs // 31 + KT // 32 + K9s // 33 + K9 // 34 + K8s // 35 + K8 // 36 + K7s // 37 + K7 // 38 + K6s // 39 + K6 // 40 + K5s // 41 + K5 // 42 + K4s // 43 + K4 // 44 + K3s // 45 + K3 // 46 + K2s // 47 + K2 // 48 + QQ // 49 + QJs // 50 + QJ // 51 + QTs // 52 + QT // 53 + Q9s // 54 + Q9 // 55 + Q8s // 56 + Q8 // 57 + Q7s // 58 + Q7 // 59 + Q6s // 60 + Q6 // 61 + Q5s // 62 + Q5 // 63 + Q4s // 64 + Q4 // 65 + Q3s // 66 + Q3 // 67 + Q2s // 68 + Q2 // 69 + JJ // 70 + JTs // 71 + JT // 72 + J9s // 73 + J9 // 74 + J8s // 75 + J8 // 76 + J7s // 77 + J7 // 78 + J6s // 79 + J6 // 80 + J5s // 81 + J5 // 82 + J4s // 83 + J4 // 84 + J3s // 85 + J3 // 86 + J2s // 87 + J2 // 88 + TT // 89 + T9s // 90 + T9 // 91 + T8s // 92 + T8 // 93 + T7s // 94 + T7 // 95 + T6s // 96 + T6 // 97 + T5s // 98 + T5 // 99 + T4s // 100 + T4 // 101/+ T3s // 102/+ T3 // 103 + T2s // 104/+ T2 // 105 + 99 // 106 + 98s // 107/+ 98 // 108 + 97s // 109 + 97 // 110 + 96s // 111 + 96 // 112 + 95s // 113 + 95 // 114 + 94s // 115 + 94 // 116 + 93s // 117 + 93 // 118 + 92s // 119 + 92 // 120 + 88 // 121/+ 87s // 122 + 87 // 123 + 86s // 124 + 86 // 125 + 85s // 126 + 85 // 127 + 84s // 128 + 84 // 129 + 83s // 130 + 83 // 131 + 82s // 132 + 82 // 133 + 77 // 134 + 76s // 135 + 76 // 136 + 75s // 137 + 75 // 138 + 74s // 139 + 74 // 140 + 73s // 141 + 73 // 142 + 72s // 143 + 72 // 144 + 66 // 145/+ 65s // 146 + 65 // 147 + 64s // 148 + 64 // 149 + 63s // 150 + 63 // 151 + 62s // 152 + 62 // 153 + 55 // 154/+ 54s // 155 + 54 // 156 + 53s // 157 + 53 // 158 + 52s // 159 + 52 // 160 + 44 // 161 + 43s // 162 + 43 // 163 + 42s // 164 + 42 // 165 + 33 // 166 + 32s // 167 + 32 // 168 + 22 #include #include #include #include "pdat.h" // Debug printing flag //#define DBUG const unsigned int mjvr = 1; // MaJor VeRsion number const unsigned int mnvr = 0; // MiNor VeRsion number const unsigned char *ptvr = "46QCejV"; // PipTime VeRsion string const unsigned char *auth = "Pip Stuart "; // me =) const unsigned char *rnkz = "AKQJT98765432"; unsigned char *fprm = ""; // flop index parameter unsigned char *hprm = ""; // hole index parameter unsigned int fpnd = 0; // actual flop index unsigned int hpnd = 0; // actual hole index unsigned int rslt[741][13][13][3]; // fat results data ~1.5MB unsigned int bord[7]; // community board cards unsigned int shnd[6]; // short/score hand indices unsigned int fndx; // chosen flop shorthand index void usag() { // display command usage && exit w/ error status fprintf(stderr, " pokr v%d.%d.%s - by %s\n\n", mjvr, mnvr, ptvr, auth); fprintf(stderr, "usage: pokr \n"); exit(1); } void SortCards() { // sorts global shnd[5] quickly unsigned int swap; if(shnd[0] > shnd[1]) { swap = shnd[0]; shnd[0] = shnd[1]; shnd[1] = swap;} if(shnd[3] > shnd[4]) { swap = shnd[3]; shnd[3] = shnd[4]; shnd[4] = swap;} if(shnd[1] > shnd[3]) { swap = shnd[1]; shnd[1] = shnd[3]; shnd[3]=swap; if(shnd[0] > shnd[1]) { swap = shnd[0]; shnd[0] = shnd[1]; shnd[1]=swap;} if(shnd[3] > shnd[4]) { swap = shnd[3]; shnd[3] = shnd[4]; shnd[4]=swap;} if(shnd[1] > shnd[3]) { swap = shnd[1]; shnd[1] = shnd[3]; shnd[3]=swap;} } if (shnd[2] > shnd[3]) { swap = shnd[2]; shnd[2] = shnd[3]; shnd[3]=swap; if(shnd[3] > shnd[4]) { swap = shnd[3]; shnd[3] = shnd[4]; shnd[4]=swap;} } else if(shnd[1] > shnd[2]) { swap = shnd[1]; shnd[1] = shnd[2]; shnd[2]=swap; if(shnd[0] > shnd[1]) { swap = shnd[0]; shnd[0] = shnd[1]; shnd[1]=swap;} } } void ShortHand() { // uses global shnd[5] cards && assigns indices of 'AKQJTs' unsigned int fsut = rkst[shnd[0]][1], sutd = 1, ndxc; SortCards(); for(ndxc = 0; ndxc < 5; ndxc++) { if(fsut != rkst[shnd[ndxc]][1]) { sutd = 0; } shnd[ndxc] = rkst[shnd[ndxc]][0]; } if(sutd) { shnd[5] = 0; } else { shnd[5] = 1; } } unsigned int BestScore() { int bscr = 7462; int tndx, cndx, tscr = bscr; for(tndx = 0; tndx < 21; tndx++) { // loop through best sets for(cndx = 0; cndx < 5; cndx++) { // loop through cards shnd[cndx] = bord[bnds[tndx][cndx]]; } ShortHand(); tscr = hndi[shnd[0]][shnd[1]][shnd[2]][shnd[3]][shnd[4] - 1][shnd[5]]; if(tscr < bscr) { bscr = tscr; } } return(bscr); } void LoadProgressIndex() { // read progress.txt FILE *fptr = fopen("progress.txt", "r"); int tmph, tmpf; if(fptr) { fseek(fptr, 5, SEEK_SET); fscanf(fptr, "%3d", &tmph); hpnd = (char)tmph; fseek(fptr, 6, SEEK_CUR); fscanf(fptr, "%5d", &tmpf); fpnd = (short)tmpf; fclose(fptr); } } void WriteProgressIndex(int indx) { // dump progress.txt FILE *fptr = fopen("progress.txt", "w"); if(fptr) { fprintf(fptr, "hpnd:%3d fpnd:%5d", hpnd, indx + 1); fclose(fptr); } } unsigned int ReadFlopXML() { // check if flop XML file can be read from unsigned int wndx = 0; char fnam[31]; FILE *fptr; fnam[wndx++] = 'h'; fnam[wndx++] = holz[hpnd][0]; fnam[wndx++] = holz[hpnd][1]; if((int)strlen(holz[hpnd]) == 3) { fnam[wndx++] = holz[hpnd][2]; } fnam[wndx++] = '/';//'\\'; fnam[wndx++] = 'f'; fnam[wndx++] = flpz[fndx][0]; fnam[wndx++] = flpz[fndx][1]; fnam[wndx++] = flpz[fndx][2]; if((int)strlen(flpz[fndx]) == 4) { fnam[wndx++] = flpz[fndx][3]; } fnam[wndx++] = '.'; fnam[wndx++] = 'p'; fnam[wndx++] = 'p'; fnam[wndx++] = 'x'; // adding .ppx filename extension (for Pip's Poker XML) fnam[wndx] = '\0'; // null-terminate fptr = fopen(fnam, "r"); if(fptr) { wndx = 1; fclose(fptr); } else { wndx = 0; } return(wndx); } void WriteFlopXML() { // dump data to the flop XML file unsigned int jndx, kndx, lndx, wndx = 0; char fnam[31]; FILE *fptr; unsigned int totr[13][13][3]; unsigned int tott[13][3]; unsigned int totl[3]; fnam[wndx++] = 'h'; fnam[wndx++] = holz[hpnd][0]; fnam[wndx++] = holz[hpnd][1]; if((int)strlen(holz[hpnd]) == 3) { fnam[wndx++] = holz[hpnd][2]; } // printf("mkdir %s\n", fnam); // mkdir taken care of by mkHoleDirz.pl fnam[wndx++] = '/';//'\\'; fnam[wndx++] = 'f'; fnam[wndx++] = flpz[fndx][0]; fnam[wndx++] = flpz[fndx][1]; fnam[wndx++] = flpz[fndx][2]; if((int)strlen(flpz[fndx]) == 4) { fnam[wndx++] = flpz[fndx][3]; } fnam[wndx++] = '.'; fnam[wndx++] = 'p'; fnam[wndx++] = 'p'; fnam[wndx++] = 'x'; // adding .ppx filename extension (for Pip's Poker XML) fnam[wndx] = '\0'; // null-terminate printf("mkfil %s\n", fnam); for( jndx = 0; jndx < 13; jndx++) { // init totals empty for( kndx = 0; kndx < 13; kndx++) { for(lndx = 0; lndx < 3; lndx++) { totr[jndx][kndx][lndx] = 0; } } for( lndx = 0; lndx < 3; lndx++) { tott[jndx][lndx] = 0; } } for( lndx = 0; lndx < 3; lndx++) { totl[lndx] = 0; } for( jndx = 0; jndx < 13; jndx++) { // pre-calc totals for( kndx = 0; kndx < 13; kndx++) { for(lndx = 0; lndx < 3; lndx++) { totr[jndx][kndx][lndx] = rslt[fndx][jndx][kndx][lndx]; } for(lndx = 0; lndx < 3; lndx++) { tott[jndx][lndx] += totr[jndx][kndx][lndx]; } } for( lndx = 0; lndx < 3; lndx++) { totl[lndx] += tott[jndx][lndx]; } } fptr = fopen(fnam, "w"); fprintf(fptr, "\n"); fprintf(fptr, "\n", flpz[fndx], totl[0], totl[1], totl[2]); for( jndx = 0; jndx < 13; jndx++) { if(tott[jndx][0] || tott[jndx][1] || tott[jndx][2]) { fprintf(fptr, " \n", rnkz[jndx], tott[jndx][0], tott[jndx][1], tott[jndx][2]); for(kndx = 0; kndx < 13; kndx++) { if(totr[jndx][kndx][0] || totr[jndx][kndx][1] || totr[jndx][kndx][2]) { fprintf(fptr, " \n", rnkz[kndx], totr[jndx][kndx][0], totr[jndx][kndx][1], totr[jndx][kndx][2]); } } fprintf(fptr, " \n", rnkz[jndx]); } } fprintf(fptr, "", flpz[fndx]); fclose(fptr); } int main(int argc, char *argv[]) { unsigned int indx, jndx, kndx, lndx, mndx, mscr, oscr; unsigned int flim = 22100; // (22100|19600) if (argc > 3) { usag(); } // call usage if wrong arg# else if(argc == 3) { fprm = argv[2]; // save flop index param hprm = argv[1]; // save hole index param fpnd = atoi(fprm); // obtain integer flop index hpnd = atoi(hprm); } // obtain integer hole index else if(argc == 2) { hprm = argv[1]; // save hole index param hpnd = atoi(hprm); } // obtain integer index else { LoadProgressIndex(); } // load last progress 4!params //hpnd = 0; fpnd = 0; flim = 25; if(1) { while(hpnd < 169) { for( indx = 0; indx < 741; indx++) { for( jndx = 0; jndx < 13; jndx++) { for( kndx = 0; kndx < 13; kndx++) { for(lndx = 0; lndx < 3; lndx++) { rslt[indx][jndx][kndx][lndx] = 0; // init empty results } } } } printf("Running hole index:%3d flop index:%5d...\n", hpnd, fpnd); for(indx = fpnd; indx < flim; indx++) { // flops up to flop-limit if(flpg[indx][0] != hoiz[hpnd][0] && flpg[indx][0] != hoiz[hpnd][1] && flpg[indx][1] != hoiz[hpnd][0] && flpg[indx][1] != hoiz[hpnd][1] && flpg[indx][2] != hoiz[hpnd][0] && flpg[indx][2] != hoiz[hpnd][1]) { fndx = flpg[indx][3]; bord[0] = flpg[indx][0]; bord[1] = flpg[indx][1]; bord[2] = flpg[indx][2]; for(jndx = 0; jndx < 52; jndx++) { if(jndx != hoiz[hpnd][0] && jndx != hoiz[hpnd][1] && jndx != flpg[indx][0] && jndx != flpg[indx][1] && jndx != flpg[indx][2]) { bord[3] = jndx; for(kndx = 0; kndx < 52; kndx++) { if(kndx != hoiz[hpnd][0] && kndx != hoiz[hpnd][1] && kndx != flpg[indx][0] && kndx != flpg[indx][1] && kndx != flpg[indx][2] && kndx != jndx) { bord[4] = kndx; bord[5] = hoiz[hpnd][0]; bord[6] = hoiz[hpnd][1]; mscr = BestScore(); for(lndx = 0; lndx < 51; lndx++) { if(lndx != hoiz[hpnd][0] && lndx != hoiz[hpnd][1] && lndx != flpg[indx][0] && lndx != flpg[indx][1] && lndx != flpg[indx][2] && lndx != jndx && lndx != kndx) { bord[5] = lndx; for(mndx = lndx + 1; mndx < 52; mndx++) { if(mndx != hoiz[hpnd][0] && mndx != hoiz[hpnd][1] && mndx != flpg[indx][0] && mndx != flpg[indx][1] && mndx != flpg[indx][2] && mndx != jndx && mndx !=kndx){ bord[6] = mndx; oscr = BestScore(); if (mscr < oscr) { // win rslt[fndx][rkst[jndx][0]][rkst[kndx][0]][0]++; } else if(mscr == oscr) { // tie rslt[fndx][rkst[jndx][0]][rkst[kndx][0]][1]++; } else { // loss rslt[fndx][rkst[jndx][0]][rkst[kndx][0]][2]++; } } } } } } } } } printf("Completed: hpnd:%3d shrh:%-3s fndx:%5d shrf:%s\n", hpnd, holz[hpnd], indx, flpz[fndx]); if(indx == 22099 || fndx != flpg[indx + 1][3]) { WriteProgressIndex(indx); // write out latest progress mndx = ReadFlopXML(); // try to read the XML file first if(mndx) { indx = flim; } // if it's readable, skip to next else { WriteFlopXML(); } // write out XML for completed flop set //return(0); // test just a single block } } } hpnd++; fpnd = 0; } return(0); // && exit }