// Filename: aktest.cpp // Last updated: Nov 4, 2003 // Author: Barry Greenstein // Purpose: This program figures out the probability of AK vs. a pair in // situations where those two hands are in the blinds and everyone // else has folded. The program is written for a variable amount of // players, so that the two player case gives results for the matchup // when other players' hands are not taken into consideration. // // When no one has entered the pot, pot-entry is classified as follows: // 0 indicates hand will be folded in all postions // 1 indicates hand is playable in early position: first and second to act // 2 indicates hand is playable in middle position: next two positions // 3 indicates hand is playable in late position: one or two to right of button // 4 indicates hand is playable on the button // 5 indicates hand is playable in the small blind // 169 hold'em hands: Entries above the diagonal are suited; below are offsuit. // Think of the 169 hands as an ordered pair of ranks: when the first rank is // higher than the second, the combination is suited, otherwise unsuited. // This table represents typical basic strategy. It is not computer generated. // A K Q J 10 9 8 7 6 5 4 3 2 // A 1 1 1 1 1 1 1 1 1 1 1 1 1 // K 1 1 1 1 2 2 3 3 3 3 3 3 3 // Q 1 2 1 2 2 2 3 3 3 3 3 3 3 // J 1 2 2 1 2 2 3 4 4 4 4 4 4 // 10 2 2 2 2 1 2 3 3 4 5 5 5 5 // 9 3 3 3 2 2 1 3 3 4 5 0 0 0 // 8 3 4 4 4 3 3 1 3 4 4 0 0 0 // 7 3 4 5 4 4 4 4 1 4 5 0 0 0 // 6 3 4 5 0 5 4 4 4 2 5 5 0 0 // 5 3 4 5 0 0 0 5 5 5 2 5 0 0 // 4 3 4 5 0 0 0 0 0 0 0 2 5 0 // 3 3 4 5 0 0 0 0 0 0 0 0 2 0 // 2 3 4 5 0 0 0 0 0 0 0 0 0 2 #include // standard input/output; this allows us to output results #include // includes definition of the random() function #define PLAYERS 9 // set to 9 for full game // set to 2 for comparison independent of other players' hands #define TOTALHANDS 5000L // 5000 takes eight hours with 3.0 Ghz processor #define SEED 1 // random numbers stay the same if seed is unchanged for debugging purposes void main(){ int dealacard(int []); // this function will deal a random card from a depleted deck unsigned handeval(int[]); // this function will evaluate 7-card hands int tableentry, player, firstcard, secondcard, i; int samesuit; // number of cards in the pair that are the same suits as the AK // same suit is 0 or 1 for AK suited, and 0, 1, or 2 for AK offsuit int aksuited; // 1 if the AK is suited, 0 if it is unsuited int board[5]; // these are the cards numbers of the flop, turn, and river // plus we will alternate putting AK and pair in last two spots int evalarray[7]; // this will contain the board and either AK or the pair int cardstaken[25]; // for each hand, this will store cards that have been dealt // fill in pot-entry array from table above (smallest card to largest here) int potentry[169]= { 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 4, 3, // Deuce 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 5, 4, 3, // Three 0, 5, 2, 0, 0, 0, 0, 0, 0, 0, 5, 4, 3, // Four 0, 0, 5, 2, 5, 5, 5, 0, 0, 0, 5, 4, 3, // Five 0, 0, 5, 5, 2, 4, 4, 4, 5, 0, 5, 4, 3, // Six 0, 0, 0, 5, 4, 1, 4, 4, 4, 4, 5, 4, 3, // Seven 0, 0, 0, 4, 4, 3, 1, 3, 3, 4, 4, 4, 3, // Eight 0, 0, 0, 5, 4, 3, 3, 1, 2, 2, 3, 3, 3, // Nine 5, 5, 5, 5, 4, 3, 3, 2, 1, 2, 2, 2, 2, // Ten 4, 4, 4, 4, 4, 4, 3, 2, 2, 1, 2, 2, 1, // Jack 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 1, 2, 1, // Queen 3, 3, 3, 3, 3, 3, 3, 2, 2, 1, 1, 1, 1, // King 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}; // Ace int aceking[2]; // holds card numbers of the Ace and the King int pairhand[2]; // holds card number for the pair srand(SEED); // activate random number generator for (int pairrank = 0; pairrank < 13; pairrank++){ // try all pairs // 0 represents Deuce, 1 represents Three, etc. for (aksuited = 0; aksuited <= 1; aksuited++){// first do AK unsuited, then suited for (samesuit = 0; samesuit <= 2; samesuit++){// suits of pair in the AK's suit(s) if ((aksuited == 1) && (samesuit == 2)) // not possible continue; // can't have both pair cards in suit of AK suited double long akwins = 0; // keeps track of wins for AK double long pairwins = 0; // keeps track of wins for pair // using "double long" since "long" uses 32 bits for storage, // which gives numbers in the billions // If we have 10000 TOTALHANDS and over 200000 board combinations // for each, we need to handle values in the trillions. if (aksuited){ aceking[0] = 51; aceking[1] = 50; // AK of spades pairhand[0] = pairrank; // take club for first card if ((pairrank >= 11) && (samesuit == 1)) // Ace or King continue; // not possible pairhand[1] = 26 + samesuit * 13 + pairrank; // either spade or heart } else{ // AK offsuit aceking[0] = 51; aceking[1] = 37;// Ace of spades, King of hearts if (samesuit == 2){ // Both pair cards in suits of AK offsuit? if (pairrank >= 11) // Dealing with Aces or Kings? continue; // not possible pairhand[0] = 39 + pairrank; // first pair card is spade pairhand[1] = 26 + pairrank; // second pair card is heart } else if (samesuit == 1){ if (pairrank == 12) // pair of Aces pairhand[0] = 38; // Ace of hearts: in King's suit else pairhand[0] = 39 + pairrank; // first pair card is spade pairhand[1] = pairrank; // second pair card is club } else{ // neither pair card is in suit of Ace or King pairhand[0] = 13 + pairrank; // first pair card is diamond pairhand[1] = pairrank; // second pair card is club } } for (long handsdealt = 0L; handsdealt < TOTALHANDS; handsdealt++){ if (PLAYERS == 2) handsdealt = TOTALHANDS; // We don't need a simulation of folded // hands when there are two players, since // there are no other players who may fold. // We will have determined an exact value // for the matchup after going through this // "for" loop once. int opener = 0; // no one has entered the pot yet // Take AK and pair out of deck cardstaken[0] = aceking[0]; cardstaken[1] = aceking[1]; cardstaken[2] = pairhand[0]; cardstaken[3] = pairhand[1]; cardstaken[4] = -1; // four cards removed so far for (player = 1; (opener == 0) && (player <= PLAYERS - 2); player++){ // go one player at a time seeing if anyone opens firstcard = dealacard(cardstaken); // first card of this player secondcard = dealacard(cardstaken); // second card of this player int firstrank = firstcard % 13; // rank of firstcard int secondrank = secondcard % 13; // rank of secondcard if (firstcard/13 == secondcard/13){ // are cards of the same suit? if (firstcard > secondcard) tableentry = firstrank * 13 + secondrank; // get to suited entry else // switch order in calculation to get suited entry tableentry = secondrank * 13 + firstrank; } else{ // cards are not the same suit if (firstrank > secondrank) tableentry = secondrank * 13 + firstrank; // get to unsuited entry else // switch order in calculation to get unsuited entry tableentry = firstrank * 13 + secondrank; } switch (potentry[tableentry]){ // case 0 is unplayable hand; we will keep going case 1: // hand is playable in all positions opener = 1; break; case 2: // hand is playable in middle position or later if (player > (PLAYERS - 7)) opener = 1; break; case 3: // hand is playable in late postion if (player > (PLAYERS - 5)) opener = 1; break; case 4: if (player > (PLAYERS - 3)) // hand is playable on the button opener = 1; break; case 5: // hand is playable in the small blind // This case doesn't exist in this program, // since small blind is AK or pair. if (player == (PLAYERS - 1)) opener = 1; break; } // end of switch } // end of "for" loop; hands were dealt to eight players if (opener == 1) continue; // deal another hand; someone opened // When no one opens, we card go through all five card boards. // For PLAYERS == 2, there are (48 choose 5) combinations. // (48 choose 5) is 1712304. // For PLAYERS == 9, there are (34 choose 5) combinations. // (34 choose 5) is 278256. // We will find out exactly how many wins for AK and how many for the pair. int used[52]; // 1 indicates used[cardnum] is taken; 0 if not taken // having cards in order will allow faster calculation of evalarray for (i = 0; i < 52; i++) used[i] = 0; // start with fresh array for (i = 0; i < PLAYERS * 2; i++) used[cardstaken[i]] = 1; // set positions that represent taken cards for (board[0] = 4; board[0] < 52 - PLAYERS * 2; board[0]++) // first flop card for (board[1] = 3; board[1] < board[0]; board[1]++) // second flop card for (board[2] = 2; board[2] < board[1]; board[2]++) // third flop card for (board[3] = 1; board[3] < board[2]; board[3]++) // turn for (board[4] = 0; board[4] < board[3]; board[4]++){ // river // The board now contains relative card positions. // We need to make them into actual positions by skipping // cards that have already been taken. int bcnum = 4; // start with last card since board // cards are in descending order int emptynum = 0; // counts 0's in used array for (i = 0; bcnum >= 0; i++){ if (used[i] == 0){ // position not taken if (board[bcnum] == emptynum++) // step to correct zero evalarray[bcnum--] = i;// element i is the location of the // board[bcnum]th unused, counting starting from 0 } } evalarray[5] = aceking[0]; // evaluate using Ace evalarray[6] = aceking[1]; // and King unsigned handwithak = handeval(evalarray); evalarray[5] = pairhand[0]; // evaluate using pair evalarray[6] = pairhand[1]; unsigned handwithpair = handeval(evalarray); if (handwithak > handwithpair) akwins += 2; // keeping track double since there may be ties else { // either tie or pair is better if (handwithak == handwithpair){ akwins++; pairwins++; } else // pair wins pairwins += 2; } } // end of 5 nested "for" loops that go through all // combinations for the five board cards } // end of "for" loop counting hands dealt if (akwins != 0){ // if TOTALHANDS is low, there may be no walks float akpercent = ((float)akwins * 100.0)/(float)(akwins + pairwins); int suitoface = aceking[0]/13; // suit of Ace int suitofking = aceking[1]/13; // suit of King int suit0 = pairhand[0]/13; // suit of first pair card int suit1 = pairhand[1]/13; // suit of second pair card char suitchars[4] = {'c', 'd', 'h', 's'}; char rankchars[13] = {'2','3','4','5','6','7','8','9','T','J','Q','K','A'}; printf("A%cK%c wins %6.4f%%. %c%c% c%c wins %6.4f%%.\n", suitchars[suitoface], suitchars[suitofking], akpercent, rankchars[pairrank], suitchars[suit0], rankchars[pairrank], suitchars[suit1], 100.0 - akpercent); } } // end of "for" loop on the suits of paired cards in the AK's suits } // end of "for" loop on whether the AK is suited or not printf("\n"); // skip a line between output for each pair } // end of "for" loop on pairs } // end of main program // dealacard() returns the value of a randomly dealt card from a deck that may // have some cards already dealt out of it, and stores the card in the array that // has been passed. int dealacard(int dealtcards[]){ int i, j; int taken = 0; // used to count how many cards are out of deck for (taken = 0; dealtcards[taken] >= 0; taken++); int cardnum = random(52 - taken); // randomly choose a card left in the deck // this is the relative location in the cards that have not been dealt for (i = 0; i < taken; i++){ // see which cards are lower than cardnum if (dealtcards[i] <= cardnum){ cardnum++; // card value needs to be one more for (j = 0; j < i; j++){ // backtrack and see if we passed a value // that should now be skipped if (dealtcards[j] == cardnum) cardnum++; // increase actual card value } } } dealtcards[taken] = cardnum; // this card is now taken dealtcards[taken + 1] = -1; // indicate new end of list return cardnum; // this is the next randomly dealt card }