Question

Currently I'm trying to port Keith Rule's Texas Holdem Hand Evaluator to Omaha Hi:

After thinking more about the algorithm, I found a solution which gives me the right percentages for the hands and everything is fine..

But it's really really slow. How can I speed things up?

As the only thing I do right now is to look-up a normal five card hands, a LUT might be right for me. Anyone integrated one before?

static void Main(string[] args)
    {
        long count = 0;
        double player1win = 0.0, player2win=0.0;
        ulong player1 = Hand.ParseHand("Ad Kd As Ks");
        ulong player2 = Hand.ParseHand("Th 5c 2c 7d");
        foreach (ulong board in Hand.Hands(0, player1 | player2, 5))
        {
            uint maxplayer1value = 0, maxplayer2value = 0;
            foreach (ulong boardcards in Hand.Hands(0, ulong.MaxValue ^ board, 3))
            {
                foreach (ulong player1hand in Hand.Hands(0Ul, ulong.MaxValue ^ player1, 2))
                {
                    uint player1value = Hand.Evaluate(player1hand | boardcards, 5);
                    if (player1value > maxplayer1value) maxplayer1value = player1value;

                }
            }
            foreach (ulong boardcards in Hand.Hands(0, ulong.MaxValue ^ board, 3))
            {
                foreach (ulong player2hand in Hand.Hands(0UL, ulong.MaxValue ^ player2, 2))
                {
                    uint player2value = Hand.Evaluate(player2hand | boardcards, 5);
                    if (player2value > maxplayer2value) maxplayer2value = player2value;

                }
            }

            if (maxplayer1value > maxplayer2value)
            {
                player1win += 1.0;
            }
            else if (maxplayer2value > maxplayer1value)
            {
                player2win += 1.0;
            }
            else
            {
                player1win += 0.5;
                player2win += 0.5;
            }
            count++;
        }
        Console.WriteLine("Player1: {0:0.0000} Player2: {1:0.0000} Count: {2}", player1win / count * 100, player2win / count * 100, count);
        Console.ReadLine();       
    }
Was it helpful?

Solution

Looks like you're trying to create equity calculator. I've done this as well, but not for Omaha (Texas Hold'em instead). With then players to evaluate, I've got about ~200K hands per second, which gives accurate result enough in no time. If there only two players to evaluate, I can get up to 4 million evaluations per second.

I used bitmasks for hands. One 64-bit integer to represent card, hand or entire board. You only need actually 52 of it, obviously. By using bitwise-operators, things get going rather quickly. Here's a quick sample from my project (in C++ tho). It's using 2 + 2 evaluator for fast look-ups:


        while (trial < trials) {
                /** I use here a linked list over the hand-distributions (players).
                  * This is kind of natural as well, as circle is the basic
                  * shape of poker.
                  */
                pDist = pFirstDist;

                unsigned __int64 usedCards = _deadCards;
                bool collision;

                /** Here, we choose random distributions for the comparison.
                  * There is a chance, that two separate distributions has
                  * the same card being picked-up. In that case, we have a collision,
                  * so do the choosing again.
                  */
                do {
                        pDist->Choose(usedCards, collision);

                        /** If there is only one hand in the distribution (unary),
                          * there is no need to check over collision, since it's been
                          * already done in the phase building them (distributions).
                          */
                        if (pDist->_isUnary)
                                collision = false;

                        pDist = pDist->_pNext;
                } while (pDist != pFirstDist && !collision);

                if (collision) {
                        /** Oops! Collision occurred! Take the next player (hand-
                          * distribution and do this all over again.
                          *
                          */
                        pFirstDist = pDist->_pNext;

                        continue;
                }

                unsigned __int64 board = 0;

                /** Pick a board from the hashed ones, until it's unique compared to
                  * the distributions.
                  *
                  */
                do {
                        if (count == 1) {
                                board = boards[0];
                                collision = false;
                        } else {
                                board = boards[Random()];
                                collision = (board & usedCards) != 0;
                        }
                } while (collision);

                board |= _boardCards;

                int best = 0, s = 1;

                do {
                        pDist->_currentHand |= board;

                        unsigned long i, l = static_cast<unsigned long>(pDist->_currentHand >> 32);
                        int p;
                        bool f = false;

                        /** My solution to find out the set bits.
                          * Since I'm working on a 32-bit environment, the "64-bit"
                          * variable needs to be split in to parts.
                          */
                        if (_BitScanForward(&i, l)) {
                                p = _evaluator->_handRanks[53 + i + 32]; // Initial entry to the 2 + 2 evaluator hash.
                                l &= ~(static_cast<unsigned long>(1) << i);
                                f = true;
                        }

                        if (f)
                                while (_BitScanForward(&i, l)) {
                                        l &= ~(static_cast<unsigned long>(1) << i);
                                        p = _evaluator->_handRanks[p + i + 32];
                                }

                        l = static_cast<unsigned long>(pDist->_currentHand & 0xffffffff);

                        if (!f) {
                                _BitScanForward(&i, l);

                                p = _evaluator->_handRanks[53 + i];
                                l &= ~(static_cast<unsigned long>(1) << i);
                        }

                        while (_BitScanForward(&i, l)) {
                                l &= ~(static_cast<unsigned long>(1) <<_handRanks[p + i];
                        }

                        pDist->_rank = p;

                        /** Keep the statistics up. Please do remember, that
                          * equity consist of ties as well, so it's not a percentual
                          * chance of winning.
                          */
                        if (p > best) {
                                pWinner = pDist;
                                s = 1;
                                best = p;
                        } else if (p == best)
                                ++s;

                        pDist = pDist->_pNext;
                } while (pDist != pFirstDist);

                if (s > 1) {
                        for (unsigned int i = 0; i _rank == best) {
                                        _handDistributions[i]->_ties += 1.0f / s;
                                        _handDistributions[i]->_equity += 1.0f / s;
                                }
                } else {
                        ++pWinner->_wins;
                        ++pWinner->_equity;
                }

                ++trial;

                pFirstDist = pDist->_pNext;
        }

Please refer to the 2 + 2 evaluator, which is quite easy to adapt in your own needs.

OTHER TIPS

This might help:

An example of a ready made Objective-C (and Java) Texas Hold'em 7- and 5-card evaluator can be found here and further explained here. It "adds" up hands to generate an index that sufficiently characterises the hand for determining rank.

All feedback welcome at the e-mail address found therein

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top