// Filename: aces.cpp
// Last updated: Nov 4, 2003
// Author: Barry Greenstein
// Purpose: This program estimates the odds are of getting a pair of Aces in
// the big blind if the everyone folds to you in a nine-handed game
// 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 TOTALHANDS 1000000L
#define SEED 4 // 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
int tableentry, player, firstcard, secondcard, i;
int cardstaken[52]; // 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
// Instead of writing a Monte Carlo Simulation, I would have liked to go
// through all possible deals of nine-handed hold'em and see how many times
// someone with two Aces gets a walk in the big blind.
// There are (52 choose 2)(50 choose 2) ... (36 choose 2) combinations.
// That equals (1326)(1225)(1128)(1035)(946)(861)(780)(703)(630), which
// equals 533,597,550,452,438,349,477,600,000 (a 27 digit number)
// Computers are not fast enough to handle checking that many cases.
// (I could cut it down to a 24 digit number of cases with some cleverness.)
long walks = 0L; // keep track of times no one enters the pot
long pairaces = 0L; // number of pairs of aces for all walks
srand(SEED); // activate random number generator
// We deal hands to eight players; then if no one has opened we will look
// at all combinations of the remaining 36 cards left for the big blind.
for (long handsdealt = 0L; handsdealt < TOTALHANDS; handsdealt++)
{
int opener = 0; // no one has entered the pot yet
cardstaken[0] = -1; // start each deal with a fresh deck
for (player = 1; (opener == 0) && (player <= 8); player++){ // one player at a time
firstcard = dealacard(cardstaken); // first card of next player's hand
secondcard = dealacard(cardstaken); // second card of next player's hand
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 (firstrank > secondrank)
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 > 2)
opener = 1;
break;
case 3: // hand is playable in late postion
if (player > 4)
opener = 1;
break;
case 4:
if (player > 6) // hand is playable on the button
opener = 1;
break;
case 5: // hand is playable in the small blind
if (player == 8)
opener = 1;
break;
}
} // end of "for" loop; hands were dealt to eight players
if (opener == 0){ // none of the first eight players entered the pot
int aces = 4; // tracks how many Aces are left in the deck
for (i = 0; cardstaken[i] >= 0; i++)
if ((cardstaken[i] % 13) == 12) // is this an Ace?
aces--; // one less Ace is in the deck
// We can calculate by hand how many times out of the (36 choose 2)
// possible two card combinations, the big blind will get a pair of Aces
// Note that (36 choose 2) is (36 * 35)/2, which equals 630
// If there is 0 or 1 Ace left, we can't get a pair of Aces in the big blind.
// If 2 Aces are left, there is 1 way to get a pair of Aces out of 630.
// If 3 Aces are left, there are 3 ways to get a pair of Aces out of 630.
// If 4 Aces are left, there are 6 ways to get a pair of Aces out of 630.
walks++; // we got a walk
if (aces == 2)
pairaces++;
if (aces == 3)
pairaces += 3L;
if (aces == 4)
pairaces += 6L;
}
} // end of "for" loop counting hands dealt
printf("The number of hands dealt is %ld.\n", handsdealt);
printf("The number of walks in the big blind is %ld.\n", walks);
printf("There were %ld pairs of Aces out of %ld combinations.\n", pairaces, walks * 630L);
if (pairaces != 0) { // when I was testing the program with TOTALHANDS
// set at 1, pairaces might have been 0
float acesratio = (float)walks * 630.0/(float)pairaces; // chance of Aces
printf("When getting a walk in the big blind, the odds of having Aces is %4.2f to 1.\n",
acesratio - 1.0);
float increase = (float)(pairaces - walks * 630.0/221.0)/
((float)walks * 630.0/221.0);
// normally we get a pair of Aces once in 221, since 1/13 x 1/17 = 1/221
printf("This is %4.2f percent more than normal.\n", increase * 100.0);
}
} // 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
}