I started to learn C language on my own and decided to build a program that calculates poker equities. I'm trying to calculate equity with Monte Carlo, but I get wrong results.
So here is an example: I'm holding JsTs (Jack of spades and 10 of spades). I have two opponents who I'm assigning specific hand ranges. First opponent plays only with AA (any Ace-Ace pocket, 6 different combinations in total), the second plays with KK+ (any Ace-Ace or King-King pocket). So the calculation process starts by randomly selecting a range from opponent ranges (for opponent 1 this is always AA). Then I'm determining different combos in that range (Ah Ac, Ah Ad, Ah As ... etc) and randomly select one of the combos in the range. So I do this for both opponents. Then I randomly choose five board cards and evaluate player hand and opponent hands. And then I see if I win or tie and keep tally of the results.
So I'm doing this 10 million times and my equity comes 20,5%, but it should be 19,1%. Here is the main() function of my code:
int main()
{
randctx rctx;
Deck[4][13];
randinit(&rctx, TRUE);
numberOfOpponents = 2;
//opponent ranges selected
rangeIsSelected[0][0]= 1;
rangeIsSelected[1][0]= 1;
rangeIsSelected[1][14]= 1;
//player cards
Player_Card_Flush[0] = 0;
Player_Card_Rank[0] = 8;
Player_Card_Flush[1] = 0;
Player_Card_Rank[1] = 9;
//insert player cards to dealt cards
Deck[Player_Card_Flush[0]][Player_Card_Rank[0]] = 1;
Deck[Player_Card_Flush[1]][Player_Card_Rank[1]] = 1;
checkForErrors(0);
if (impossibleError==1) {
printf("Impossible to calculate equity");
return;
}
gamesSimulated = 0;
totalTies = 0;
totalWins = 0;
int opponentToBeDealt = 0;
//let's see what ranges are selected by opponents
for (int i=0; i<numberOfOpponents; i++) {
findSelectedRanges(i);
}
//beginning of Monte Carlo method
while (gamesSimulated<maxTrials) {
int b = 0;
int opponentsDealt = 0;
//randomly select hand for opponents
while (opponentsDealt<numberOfOpponents) {
opponentCardsForMonteCarlo(opponentToBeDealt);
opponentsDealt += 1;
if (opponentsDealt==numberOfOpponents) break;
if (opponentToBeDealt==numberOfOpponents-1) {
opponentToBeDealt = 0;
}
else {
opponentToBeDealt += 1;
}
}
//randomly choose 5 board cards
while (b<5) {
int randomCardTag = rand(&rctx) % 52;
randomCardFlush[b] = randomCardTag / 13;
randomCardRank[b] = randomCardTag % 13;
//if this card hasn't been dealt then add to dealt cards
if (Deck[randomCardFlush[b]][randomCardRank[b]]==0) {
Deck[randomCardFlush[b]][randomCardRank[b]] = 1;
b++;
}
}
//evaluate hands (this function also removes random opponent hands when it's done)
calculateMonteCarloEquity();
//remove random board cards from dealt cards
for (int x=0; x<b; x++){
Deck[randomCardFlush[x]][randomCardRank[x]]=0;
}
}
Because I have written my own evaluation code I suspected that first, but when I do exhaustive enumeration with the exact same code I get correct results (confirmed with PokerStove). Then I started to look if there's any bias in the way I deal the cards for my opponents. This is my output:
Opponent 1 hands As Ac: 1665806 times As Ah: 1667998 times As Ad: 1666631 times Ac Ah: 1665767 times Ac Ad: 1666595 times Ah Ad: 1667203 times
Opponent 2 hands As Ac: 833847 times As Ah: 833392 times As Ad: 832396 times Ac Ah: 833406 times Ac Ad: 834542 times Ah Ad: 833703 times Ks Kc: 832585 times Ks Kh: 835641 times Ks Kd: 832483 times Kc Kh: 833013 times Kc Kd: 831558 times Kh Kd: 833434 times
This looks pretty random to me. I also looked at the board cards and there doesn't seem to be any bias also, basically all cards are dealt approximately 1,08xxxx million times except As - 271 812 times, Ac - 272 856 times, Ah - 271 898 times, Ad - 272 062 times, Ks - 815 113, Kc - 816 871, Kh - 814 955 times, Kd - 814 866 times and of course Js - 0 times and Ts - 0 times. I also tried to create an array of undealt cards so my random board card won't be rand(&rctx) % 52, but depending on the situation rand(&rctx) % 46, rand(&rctx) % 45 etc (basically I only choose from undealt cards). However this doesn't change the results very much.
I'm using ISAAC random number generator, although I almost get the same result with the built-in rand() function. I've tried to seed it with time like so randinit(&rctx, time(NULL))
but not much difference in end results. Yeah, I know time is a bad seed for cryptographic purposes, but should be OK for simulations like this one.
So I've run out of ideas, maybe someone can see something that I am missing?
Edit Here's my equity calculation code
void calculateMonteCarloEquity() {
opponentsBeaten = 0;
opponentsTied = 0;
opponentsLost = 0;
//remove all opponent cards from dealt cards, because we need 7 dealt cards to evaluate hand
for (int x=0; x<numberOfOpponents; x++) {
Deck[opponentCardFlush[x][0]][opponentCardRank[x][0]] = 0;
Deck[opponentCardFlush[x][1]][opponentCardRank[x][1]] = 0;
}
//at this point we have 5 board cards and 2 player cards left in dealt cards
//so let's evaluate that hand
Evaluate_Hand();
playerHandScore = Hand_Score;
//now remove player hand form dealt cards
Deck[Player_Card_Flush[0]][Player_Card_Rank[0]] = 0;
Deck[Player_Card_Flush[1]][Player_Card_Rank[1]] = 0;
//let's evaluate opponent hands and save their scores
for (int x=0; x<numberOfOpponents; x++) {
//insert opponent x hand to dealt cards
Deck[opponentCardFlush[x][0]][opponentCardRank[x][0]] = 1;
Deck[opponentCardFlush[x][1]][opponentCardRank[x][1]] = 1;
Evaluate_Hand();
opponentHandScore[x] = Hand_Score;
//remove opponent x hand from dealt cards when evaluated
Deck[opponentCardFlush[x][0]][opponentCardRank[x][0]] = 0;
Deck[opponentCardFlush[x][1]][opponentCardRank[x][1]] = 0;
}
//compare opponent hand scores with player hand score
for (int x=0; x<numberOfOpponents; x++) {
if (playerHandScore > opponentHandScore[x]) {
opponentsBeaten += 1;
continue;
}
else if (playerHandScore == opponentHandScore[x]) {
opponentsTied += 1;
continue;
}
else if (playerHandScore < opponentHandScore[x]) {
opponentsLost += 1;
continue;
}
}
//if player beats all opponents he wins the hand
if (opponentsBeaten==numberOfOpponents) {
totalWins += 1;
}
//if player doesn't beat all the opponents, but neither loses to anyone, there must be a tie
if (opponentsLost==0 && opponentsBeaten!=numberOfOpponents) {
totalTies += 1/(opponentsTied+1);
}
//one game has been evaluated
gamesSimulated += 1;
playerEquity = (totalWins+totalTies)/gamesSimulated;
//let's insert player cards back to dealt cards
Deck[Player_Card_Flush[0]][Player_Card_Rank[0]] = 1;
Deck[Player_Card_Flush[1]][Player_Card_Rank[1]] = 1;
if (gamesSimulated>=maxTrials) return;
}
You have assigned equal probability for AA and KK for opponent 2.
In real life, AA KK is more probable than AA AA. There are 6 kombinations with KK and only one with AA.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With