Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Monte Carlo method for calculating poker equities

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;
}
like image 333
deville Avatar asked Oct 02 '22 22:10

deville


1 Answers

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.

like image 83
Klas Lindbäck Avatar answered Oct 12 '22 09:10

Klas Lindbäck