The Great Poker Hand Evaluator Roundup

Introduction

This page is a listing of publically available poker hand evaluators, for Hold’em and other games, in C, C++, C#, Java, and other programming languages, with brief descriptions, sample usage, and complete source code, along with gratuitous pictures of scantily-clad ninjas. Downloading and building these hand evaluators piecemeal can be a pain in the you-know-what…

Some assembly required

…so I’ve packaged the complete source code for every evaluator into a single, easy-to-build library: XPokerEval.

[more]

If you’re a poker hand evaluation guru, some of this will be old hat to you. On the other hand, if you’re new to the subject of poker hand evaluation, it might come in handy. Enjoy.

The Pokersource Poker-Eval Evaluator

Description:

The Pokersource poker-eval library is probably the most widely-used poker hand evaluator in the galaxy.  It’s open-source, it’s fast, it’s over ten years old, and it can not only analyze your poker hands but make you a cup of coffee, interpolate the doomsday trajectory of near-Earth asteroids, and fix the grease-clot in your kitchen sink.

poker-eval is a C library to evaluate poker hands. The result of the evaluation for a given hand is a number. The general idea is that if the evaluation of your hand is lower than the evaluation of the hand of your opponent, you lose. Many poker variants are supported (draw, holdem, omaha, etc.) and more can be added. poker-eval is designed for speed so that it can be used within poker simulation software using either exhaustive exploration or Monte Carlo.

Poker-eval has a ton of functionality, including support for multiple poker variants (Hold’em, Omaha, Stud 7, etc.), non-standard decks, low and high-low games, enumerations, quarks, leptons, synchronicities, and strange attractors. It can be built on about a dozen different platforms, including Windows, *nix, and the alien mother ship OS first popularized in Independence Day and later legitimized by Jakob Nielsen.

Uploading the save-the-planet virus into the alien mother ship using the X'yg'yec'nar42 protocol

Pretty cool.

Implementation:

The Poker-Eval library is implemented in highly optimized, heavily macro’d C for unadulterated speed, but language mappings for .NET, Java, and Python are provided. Now, I’ll be honest. The first time I saw the poker-eval source code, I immediately unlearned about sixty-two months of best-practices software development:

#define INNER_LOOP_HOLDEM                                
  INNER_LOOP({                                            
    StdDeck_CardMask _hand;                              
    StdDeck_CardMask _finalBoard;                        
    StdDeck_CardMask_OR(_finalBoard, board, sharedCards);
    StdDeck_CardMask_OR(_hand, pockets[i], _finalBoard);  
    hival[i] = StdDeck_StdRules_EVAL_N(_hand, 7);        
    loval[i] = LowHandVal_NOTHING;                        
    err = 0;                                              
  })

The Pokersource library isn’t exactly going to be winning any awards for clarity or courtesy, but then again, once you understand how to use the library, it doesn’t really matter. Poker-Eval is unapologetically designed for speed. If you’ve got a problem with that, take it up with this guy:

Mr. T

Four things and four things only, in this universe:

  • bitwise manipulation
  • lookup tables
  • bitwise manipulation
  • lookup tables

Everything is expressed either as a sequence of bits on which various operations are performed, or as a lookup table from which precomputed values are grabbed, often by taking the output of an obscure but clever bitwise manipulation and treating it as an index, or otherwise doing esoteric things with code, like boiling the orange sponge donkey.

Magic, basically. This doesn’t work the same way as a game of live blackjack, that requires a post of its own.

And just as in Cactus Kev, the result of evaluation for a hand is a number (called a hand value or HandVal in Pokersource lingo) which can be compared to the number for any other hand to determine a winner.

However, unlike Cactus Kev, the number so returned is not an equivalence value.

Poker-Eval guarantees that if Hand A beats Hand B, the hand value for Hand A will be higher than the hand value for Hand B. And it guarantees that, if Hand A ties Hand B, the hand value for both hands will be equal. But the actual hand values returned by the Pokersource evaluator are different than those returned by the Cactus Kev evaluator.

Card Format:

A poker hand is (internally) represented as a sequence of 52 bits, one for each card in the deck. This is called a hand mask or card mask (and sometimes just a “hand” or a “card” or a “mask” in order to be vague) and it can be used to store N number of cards, where N is any number between 0 and 52.

Using card masks, we can represent an entire poker hand, such as the Royal Flush of Spades…

       11111000 00000000 00000000 00000000 00000000 00000000 00000000 00000000

Or we can represent a single card, such as the 7 of Diamonds…

       00000000 00000000 00000000 00000000 00000001 00000000 00000000 00000000

Another cool thing about this format is its ability to induce epileptic seizures when stared at for longer than a few seconds. Luckily, the Pokersource library provides a number of macros/functions to protect you from the underlying representation. But who’s going to protect you, gentle programmer, from the macros? That’s another question…

Usage:

There are five (that’s 0101) key abstractions you’ll want to know about before tangling with this evaluator:

  • Card Mask. A 52-bit value containing 1 bit for each card. But we have to stick it in an 8-byte integer, so 64 bits with 12 dead. Type: StdDeck_CardMask.
  • Card Index. A number between 0 (Two of Hearts) and 51 (Ace of Spades) which uniquely identifies a particular card. Simple enough. Type: int.
  • Hand Value. The value of a given poker hand, which can be tested against other HandVals to determine the winner. Type: HandVal.
  • Hand Category. The type of a poker hand, such as Two Pair or Full House. Type: int.
  • Evaluator. Just to make things as confusing as possible, the Poker-Eval evaluator has different evaluators. For example, the StdDeck_StdRules_EVAL_TYPE function is a fast N-card evaluator designed to return a hand’s category only, whereas the StdDeck_StdRules_EVAL_N function is designed to return the hand value for a hand. There are also separate evaluators for non-standard games. And then there are macros to map these back and forth in typical C-language style. Type: function.

For more information, check out the XPokerEval.Pokersource.Test project, where I’ve placed a few sample usages, and you can find numerous others out there around the net.

Limitations:

Yeah right. With support for multiple poker variants, multiple platforms, multiple language mappings, and because of its sheer speed, the Pokersource evaluator is like the bully who takes all the kids’ lunch money in the schoolyard, the bully your parents told you not to be scared of because he’d leave you alone if you only stood up to him, because all bullies are sissies in Perfect, so you stood up to him that one sunny afternoon and it turns out sorry, kid, your parents were wrong. He’s not anything like a sissy, and YOU, well, in the immortal words of Jack Handey:

If you define cowardice as running away at the first sign of danger, screaming and tripping and begging for mercy, then yes, Mr. Brave man, I guess I’m a coward

The Pokersource evaluator is, well, kind of like that (?). At least, it mops the floor with every other evaluator save one: that near-mythical potpourri of hand evaluation ninjitsu, the Two Plus Two evaluator.

Not your average ninja

But we have to walk before we can run.

Cactus Kev’s 5-Card Evaluator

Description:

A few years ago, Kevin Suffecool came up with a ridiculously freaking clever algorithm for 5-card poker hand recognition. When it was first introduced, the Cactus Kev evaluator made quite a splash, and a (private, unfortunately) 7-card version was even incorporated into commercial poker software, as Kevin describes. A slightly modified version of the Cactus Kev evaluator is also used by the Two Plus Two evaluator, not to mention Paul Senzee’s 7-card evaluator, and the original Cactus Kev equivalence tables are used in Moritz Hammer’s DAG evaluator.

This evaluator gets around, baby. Like a record.

Implementation:

The Cactus Kev evaluator uses prime numbers, bitwise manipulation, lookup tables, and bilatitudinal quasi-isometric spin widgets in order to map a collection of five cards to an equivalence class between 1 (Royal Flush) and 7,462 (7-high). Like most of the other evaluators in this roundup, the Cactus Kev evaluator converts a poker hand to a number which can be compared to other poker hands. But the Cactus Kev evaluator was the first to use formal equivalence class values for those numbers, i.e., a consecutive, 1-based ordering of hands from most powerful to least.

Central to the Cactus Kev algorithm is the idea of associating a prime number with each card rank:

After a lot of thought, I had a brainstorm to use prime numbers. I would assign a prime number value to each of the thirteen card ranks, in this manner:

Rank Deuce Trey Four Five Six Seven Eight Nine Ten Jack Queen King Ace
Prime 2 3 5 7 11 13 17 19 23 29 31 37 41

 

The beauty of this system is that if you multiply the prime values of the rank of each card in your hand, you get a unique product, regardless of the order of the five cards. In my above example, the King High Straight hand will always generate a product value of 14,535,931. Since multiplication is one of the fastest calculations a computer can make, we have shaved hundreds of milliseconds off our time had we been forced to sort each hand before evaluation.

The prime number is then embedded into a special 4-byte representation of the card…

Cactus Kev's 4-byte card format

…after which a variety of bitwise operations and lookup tables are applied to map the five-card poker hand to a specific equivalence class. I won’t rehash the details of his algorithm here, but they’re well worth reading, as the Cactus Kev evaluator is used and referenced all over the place.

Card Format:

The Cactus Kev evaluator uses a 4-byte integer to represent each card, with bits set according to the format above.

Usage:

First, you’ll want to get your cards into the Cactus Kev format. You can do this either manually or by calling the init_deck function:

// Initialize the deck with Cactus Kev-style card values
int deck[52];
init_deck(deck);

Second, create an array of five cards and pass it into the eval_5hand function. This will return the hand’s official equivalence value. You can get the hand category from the equivalence value by calling the hand_rank function, if necessary:

// Let the hand[5] array be an array of five 4-byte integers,
// each representing a single card in Cactus Kev’s 4-byte card
// format.
int hand[5] = { /* Cactus Kev card values */ };
int eqValue = eval_5hand( hand );
int handCategory = hand_rank(eqValue);

Here’s what a typical hand comparison might look like using the Cactus Kev evaluator:

int lookupHand(int[] theHand)
{
   return eval_5hand( theHand );
}

// Return 1 if hand1 > hand2, -1 if hand1 < hand2
// or zero (0) if they are equal.
int compareTwoHands(int[] hand1, int[] hand2)
{
   int hand1Value = lookupHand(hand1);
   int hand2Value = lookupHand(hand2);

   if (hand1Value < hand2Value)
      return 1;
   else if (hand1Value > hand2Value)
      return -1;
   else
      return 0; // the hands are equal!
}

The only thing to keep in mind: the Cactus Kev evaluator orders hands from 1 (strongest) to 7,462 (weakest) so a hand with value 2302 beats a hand with value 3402.

Limitations:

The Cactus Kev evaluator only handles 5-card poker hands, making it unsuitable for 7-card games such as Hold’em or Omaha. The Cactus Kev source code does include a 7-card evaluation function but it’s unoptimized (as the author admits) and should be avoided in favor of faster 7-card evaluators. Also, the Cactus Kev evaluator should never be used as-is; always include Paul Senzee’s perfect hash optimization.

Cactus Kev’s 5-Card Evaluator with Perfect Hash

Description:

After reading about the Cactus Kev evaluator, a programmer by the name of Paul Senzee took up the source code and made it even faster.

…I came upon Cactus Kev’s Poker Hand Evaluator which is a killer fast five card hand evaluator. Reading through his algorithm you’ll notice that the last step for any yet unclassified hand is a binary search through a list of values. Most hands end up in that search which is the most time-consuming part of the algorithm.

An Optimization

Replacing the binary search with a precomputed perfect hash for the 4888 values in the list yields a significant improvement over the original. The original test code included with Kevin’s source (using eval_5hand) runs in 172 milliseconds on my machine and with my eval_5hand_fast it runs in 63 milliseconds. Yay, an improvement of 2.7 times!

Programmers: forever trying to one-up each other. A 2.7 times improvement is nothing to sneeze at, but we need 1.21 gigawatts of power to blow this pop-stand and head back to the future. Otherwise the evaluator is identical to the original Cactus Kev evaluator described above. In fact, whenever we say “Cactus Kev’s evaluator” we really mean “Cactus Kev’s evaluator with Paul Senzee’s optimization”. Never use the Cactus Kev evaluator without the Senzee optimization. And by the way, Paul also has a 7-card evaluator. Don’t get them confused.

Implementation:

Exactly as in the original Cactus Kev evaluator, except that Paul Senzee’s code replaces Suffecool’s binary search with a perfect hash technique which I’ll show here for novelty’s sake:

// magic
unsigned find_fast(unsigned u)
{
   unsigned a, b, r;
   u += 0xe91aaa35;
   u ^= u >> 16;
   u += u << 8;
   u ^= u >> 4;
   b  = (u >> 8) & 0x1ff;
   a  = (u + (u << 2)) >> 19;
   r  = a ^ hash_adjust[b];
   return r;
}

// Paul Senzee’s optimized version of Kevin Suffecool’s eval_5cards function
int eval_5hand_fast(int c1, int c2, int c3, int c4, int c5)
{
   int q = (c1 | c2 | c3 | c4 | c5) >> 16;
   short s;

   // check for flushes and straight flushes
   if (c1 & c2 & c3 & c4 & c5 & 0xf000) return flushes[q];

   // check for straights and high card hands
   if ((s = unique5[q])) return s;

   // otherwise use hash-based lookup
   return hash_values[find_fast((c1&0xff)*(c2&0xff)*(c3&0xff)*(c4&0xff)*(c5&0xff))];
}
 

The hashing technique is based on Bob “the Hashmaster” Jenkin’s perfect hashing algorithm which I believe Bob, who’s as smart as any ten people, brought with him from his home planet of Xy’torrrrn, where it was used in interdimensional wormhole calibration. Good for a little light reading by the fireplace.

Card Format:

Same as in the original Cactus Kev evaluator.

Usage:

As for the Cactus Kev evaluator, but instead of calling eval_5hand, plug in Senzee’s replacement function, eval_5hand_fast.

Limitations:

Same as per the original Cactus Kev evaluator.

Cactus Kev’s 5-Card Evaluator with Perfect Hash in C#

Description:

Shortly after Paul Senzee published his improvement to the Cactus Kev evaluator, a .NET programmer by the name of Mike Benson came along and ported it all to C#.

Some of you know that I have been playing around with writing poker calculators and poker game simulations. These days, my preferred language is C# so I decided to undertake my project in C#. I happened to run across Cactus Kev’s Poker Hand Evaluator and it looked pretty slick. I have already written my own evaluator in C# and it was pretty fast but this looked like a screamer.

I did the port of the calculator including the modification written by Paul Senzee over to C#. This did not prove to be too difficult and it was done in about 4 hours.

Even if you don’t plan on using the Cactus Kev evaluator, Mike’s post is worth a read as he touches on some interesting performance differences between C++ and C# such as yes C/C++ is still faster than C#. Sorry, people.

The Cactus Kev method does not use logical operators and the C++ version is only 6% faster than the C# version. However, the C++ version using the Paul Senzee modification with the chunk of logical operators is 37% faster in C++ than in C#. That’s quite a difference.

As if one wasn’t enough, Mike actually wrote two ports of the evaluator: one in C# and one in C++, both of which can be downloaded from http://thebensons.org/blog/2006/11/05/c-vs-c-performance-part-ii (you’ll see the links toward the bottom of the page), and exactly one-half of which are included in the XPokerEval project which accompanies this article.

Implementation:

It’s a direct port of the Cactus Kev Improved Hash evaluator from C to pure C#, perfectly performed. What more could you want?

Card Format:

Same as in the original Cactus Kev evaluator.

Usage:

Same as in the original Cactus Kev evaluator, except Suffecool’s original C methods have become static methods inside the PokerLib class:

int [] deck = new int[52];
int [] hand = new int[5];
int [] freq = new int[10];

// Init the deck in the Cactus Kev format..
PokerCalculator.PokerLib.init_deck(deck);

int a, b, c, d, e, handCategory;
ushort handValue;

// loop over every possible five-card hand
for(a=0;a<48;a++) {
   hand[0] = deck[a];
   for(b=a+1;b<49;b++) {
      hand[1] = deck[b];
      for(c=b+1;c<50;c++) {
         hand[2] = deck[c];
         for(d=c+1;d<51;d++) {
            hand[3] = deck[d];
            for(e=d+1;e<52;e++) {
               hand[4] = deck[e];

               // Get the hand’s equivalence class
               handValue = PokerCalculator.PokerLib.eval_5hand_fast(hand);
               // Get the hand’s category..
               handCategory = PokerCalculator.PokerLib.hand_rank(handValue);

               freq[handCategory]++;
            }
         }
      }
   }
}

Sort of the “ah hell, I don’t really want to build a 26-object hierarchy to represent this C-level API so I’ll just create a single class facade and hammer together a few static methods” approach to porting. Good enough for me, and good enough for you, and honi soit qui mal y pense!

Limitations:

Same as the original Cactus Kev evaluator.

The Pokersource Poker-Eval Evaluator for C#

Description:

A C# interface to the Pokersource Poker-Eval evaluator. Written by Johan Euphrosine and included with recent Poker-Eval distributions. Useful for .NET programmers who want to use Pokersource, but who hate (with a fiery Dracula passion) the C-language macro-ized version of it. But if that’s you, consider using the Keith Rule evaluator as it has a richer feature set.

Implementation:

The native C Pokersource code is packaged into a C++ wrapper DLL which can be accessed from a .NET assembly via P/Invoke. As this evaluator is really a thin wrapper around the Pokersource evaluator, it has roughly the same implementation characteristics as that evaluator.

Card Format:

Same as in the original Pokersource evaluator.

Usage:

Here’s how you’d perform a typical hand-vs.-hand analysis:

public void TestPokenum()
{
    // Set up a hand with pockets aces
    StdDeck.CardMask pocket1 = new StdDeck.CardMask();
    pocket1.Set(“As”);
    pocket1.Set(“Ac”);

    // Set up another hand with pocket Queens
    StdDeck.CardMask pocket2 = new StdDeck.CardMask();
    pocket2.Set(“Qs”);
    pocket2.Set(“Qc”);
    StdDeck.CardMask[] pockets = { pocket1, pocket2 };

    // …on a board of Ks Kc Kh
    StdDeck.CardMask board = new StdDeck.CardMask();
    board.Set(“Ks”);
    board.Set(“Kc”);
    board.Set(“Kh”);

    // Don’t include any of the above cards in the enumeration!
    StdDeck.CardMask dead = new StdDeck.CardMask();
    dead.Set(“As”);
    dead.Set(“Ac”);
    dead.Set(“Qs”);
    dead.Set(“Qc”);
    dead.Set(“Ks”);
    dead.Set(“Kc”);
    dead.Set(“Kh”);

    // Enumerate all possible hands!
    int npockets = 2;
    int nboard = 3;
    int niter = 1;
    int orderflag = 0;
    EnumResult result = Enum.Sample(Game.holdem, pockets, board, dead,
                                    npockets, nboard, niter, orderflag);
}

This code is considerably cleaner than the equivalent code written against the native C-language Pokersource routines, and marginally slower, but otherwise, good stuff.

Limitations:

Probably the biggest single problem with this evaluator is that it requires you to package the native Pokersource library as a DLL and export various methods that can be called through P/Invoke. Now hear me well: depending on the platform, compiler, and poker variant you’re targeting, this (building Pokersource as a DLL rather than a static LIB) can be about as much fun as repeatedly bashing your forehead into a brick wall. Pokersource wants to be built as a static library even though it’s perfectly capable of being built as a DLL.

I could ramble on about why this is so, but to heck with it. The code is haunted. I’m out.

Me, after a 32-hour poker session

The Pokersource Java API (Enumeration, Evaluation, and SAIE)

Description:

The Pokersource Java API is a collection of Java source code included with certain versions of the Pokersource Poker-Eval distribution:

The PokerSource Java API gives Java programs the ability to use the fast poker hand evaluator and enumerators in the poker-eval C library. The Java layer also defines higher-level structures that aren’t available in the C library and provides algorithms for working with these structures. The most significant concept available only in the Java layer is the probabilistic hand distribution. The packages provide algorithms for computing pot equity based on subjective belief probabilities of hand distributions.

This is necessary if you want to court Java developers, because no Java developer in his right mind would ever use the C-language version of Pokersource. You would have to handcuff him to a desk, deny him food and drink, perhaps bring out the old Chinese water torture gag. But anyway, the API is divided into three packages. Quoting from the documentation:

  • org.pokersource.enum. Provides classes that enumerate or sample the possible outcomes of a poker hand, define hand distributions, define subjective belief probabilities over hand distributions, and compute subjective pot equity based on these beliefs.
  • org.pokersource.eval. Provides access to the fast poker hand evaluators in the C poker library.
  • org.pokersource.game. Provides utilities for encoding poker cards and hands and converting to and from string representations.

The ability to compute hand vs. hand-range equities across multiple opponents out of the box makes this a win for Java developers. The only problem is that finding the Java API can be a little tough. For whatever reason, it’s not included in the latest Pokersource distribution (poker-eval-134.0.tar.gz, as of this writing). Instead you have to go back to poker-eval-src-121.tar.gz.

poker-eval distributions

Just to make things as confusing as possible, those version numbers will probably change sometime after this article is published, and knowing me, I’ll be too lazy to go in and update this section. So do a cursory check to make sure you’re downloading the latest and greatest.

The Java API is also included in the XPokerEval library which accompanies this article. You want the XPokerEval/XPokerEval.Pokersource/java directory:

There’s even some JavaDoc stuff in there to help you get started.

Implementation:

We’ll examine the implementation of these libraries more closely in a future update as this goes beyond basic hand recognition and into the world of hand-range analysis across multiple opponents. (And yes, that’s Coding-the-Wheel-ese for “I don’t really want to plunge into a two-page explanation of this topic right now, since this post is already longer than I am tall.”)

Card Format:

Same as in the original Pokersource evaluator.

Usage:

Each of the three packages includes a handful of JUnit-compatible tests. These are probably your best resource for learning how to use this evaluator. Here’s a good one:

public void testPotEquity()
{
   // Compare to “pokenum -h ks kh ad td 9c 8c — kd jd th / As 2h”.
   double[] ev = new double[pocketRanks.length];
   Enumerate.PotEquity(Enumerate.GAME_HOLDEM, 0, pocketRanks, pocketSuits,
                  boardRanks, boardSuits, deadRanks, deadSuits, ev);
   assertEquals(0.531707317073, ev[0], 1e-10);
   assertEquals(0.392682926829, ev[1], 1e-10);
   assertEquals(0.075609756098, ev[2], 1e-10);

   ev = new double[pockets.length];
   Enumerate.PotEquity(Enumerate.GAME_HOLDEM, 0, pockets, board, dead, ev);
   assertEquals(0.531707317073, ev[0], 1e-10);
   assertEquals(0.392682926829, ev[1], 1e-10);
   assertEquals(0.075609756098, ev[2], 1e-10);
}

Full-fledged computation of SAIE (subjective all-in equity) in a dozen lines of code, give or take. Java programmers: make sure to lord this over your C++ and C# counterparts, who have to hand-roll a lot of this functionality.

Limitations:

Few to none. With all of the power of the Pokersource library and some of its speed, and with the ability to perform SAIE computation, not to mention leaping tall buildings in a single bound, this library is a strong choice for Java developers, especially those who want robust SAIE computation.

Keith Rule’s C# Port of the Pokersource Evaluator

Description:

One of my favorite all-time CodeProject riffs is Keith Rule’s Fast Texas Hold’em Evaluation and Analysis.

Recently, I was laid up with a prolonged illness. During that time, I needed to entertain myself. I quickly determined that daytime TV was not worth watching. Instead, I started playing Texas Holdem online. A few thousand hands later, I determined that the medication I was taking was interfering with my ability to concentrate. This limited the skill level that I could consistently play at. So instead of continuing to play Texas Holdem poorly, I decided to write a software to analyze poker.

The first thing I realized I needed was a fast way to iterate through and evaluate Texas Holdem hands. After searching the net and trying several libraries, I found that nothing met my needs. Native C# code was too slow, and the best C library (poker-eval) was very difficult to connect to C# using interop. So I started writing my own C# library.

After a few days of work, I was able to evaluate a few hundred thousand hands a second. This was several orders of magnitude slower than I needed. So I looked at poker-eval again. After working through this gnarly, heavily macroed and table driven C library, I realized that the techniques they were using should work with C#. I ported the portion of the tables and evaluation functions that I needed to analyze Texas Holdem. The resulting code is definitely fast enough for most of my needs.

Here’s the “rule”: if you’re building in C#, and you want to use the Pokersource evaluator, and your game is Texas Hold’em, use Keith Rule or you’re fired. Fired from this site. While it’s true that the Pokersource library includes a perfectly good P/Invoke interface for C#, Keith’s code, especially in later incarnations, offers a lot more functionality when it comes to the game of Hold’em.

Implementation:

Keith’s evaluator packages the flat, C-level functionality of the Pokersource evaluator into higher-level abstractions (such as the Hand class) while retaining the low-level, bit-shifting and table-lookup retro disco-dancing goodness of the original. (And you thought encapsulation was just a word they used in classrooms.)

Card Format:

As in the original Pokersource evaluator.

Usage:

The Rule evaluator is documented so well I can’t add much of value other than to give you a taste for the client-side usage. Here’s how you’d decompose a Hold’em hand into its Pokersource hand value:

// Pocket Aces in the hole, with a board of 2d 3d 4d 5d Ac (= A2345 straight flush)
HoldemHand.Hand hand = new HoldemHand.Hand(“Ah Ad”, “2d 3d 4d 5d Ac”);
uint handVal = hand.HandValue;

The Rule evaluator also allows you to compute the equity of two or more hands, either preflop or given some combination of board cards:

// Compare the equity of AhAd vs. Tc2c preflop

string[] pockets = { “AdAh”, “Tc2c” };
long[] wins = new long[2];
long[] ties = new long[2];
long[] losses = new long[2];
long totalHands = 0;

HoldemHand.Hand.HandOdds(pockets, “”, “AdAh2cTc”, wins, ties, losses, ref totalHands);

This really only scratches the surface, of course. Check out Keith’s CodeProject article for the details.

Limitations:

Unlike the Pokersource evaluator on which it’s based, the Rule evaluator only supports Texas Hold’em.

Steve Brecher’s HandEval Evaluator

Description:

Steve Brecher’s open-source Hold’em Showdown tool uses an enumeration/evaluation library called HandEval:

Hold’Em Showdown is a program that you can download and then run on your desktop.   It prompts for information from you which specifies a Texas Hold’Em poker “all-in” situation for two or more players, and then gives you the chances of each player winning (or tying). It works by enumeration rather than simulation. Thus its results are a tabulation of all possibilities of remaining board cards and are exact, rather than an approximation based on an arbitrary number of simulated deals.

Steve played a crucial role in the development of the Two Plus Two evaluator. In fact, the de facto summation of the Two Plus Two algorithm is a test harness in which the Two Plus Two evaluator runs side-by-side with two other evaluators, one of which is the Pokersource evaluator and the other of which is…you guessed it…Steve Brecher’s HandEval. (Check out the XPokerEval.Test3 project to see this in action.)

Unfortunately, the HandEval library is somewhat out of date. In Steve’s words:

Although Hold ‘Em Showdown is more than adequate for typical usage on hands with specific hole cards, it is obsolete for more general scenarios involving ranges of hands (example:  any pair, any suited connectors 98 or better, any two Broadway cards) or scenarios involving players with “random” hands.  (Hold ‘Em Showdown can do enumerations involving up to two players with “random” hole cards, but it can take a long time.)

Every so often I stop by Steve’s site to see what’s cooking, hoping to see an update, and each time I’m disappointed. Maybe Steve will stumble across this post and give us an update.

Implementation:

I’ve never had the time to take a microscope to Steve’s code, so I’m not ashamed to tell you I have no clue how it works

/* This macro uses the variables: Mask_T ranks, c, d, h, s */
#define mStraightAndOrFlush(N)                              
    j = 0;                                                  
    mFlushOrStraightFlush(c,N) else                        
    mFlushOrStraightFlush(d,N) else                        
    mFlushOrStraightFlush(h,N) else                        
        /* total cards in other suits <= N-5; spade flush:*/
        if (!(i = straightValue[s]))                       
            return Value(FLUSH) | hi5RanksMask[s];         
        else                                                
            return (Value(STRAIGHT_FLUSH) - Value(STRAIGHT)) + i;
    if ((i = straightValue[ranks]) != 0)                   
        return i;

#define hand0 ((int)hand & 0x1FFF)
#define hand1 (((int)hand >> 13) & 0x1FFF)
#define hand2 ((int)(hand >> 26) & 0x1FFF)
#define hand3 ((int)(hand >> 39))

…but one thing’s for sure: if you enjoyed dissecting the Pokersource code, you’ll love poking through the innards of the HandEval library. Good times, good times.

Card Format:

Steve’s library uses a format very similar to the format used by the Pokersource and Senzee7 evaluators: a sequence of 52 bits, one for each card. Quoting from the comments in the source code:

A hand is 0 or more cards represented in four 13-bit masks, one mask per suit, in the low-order 52 bits of a long (64 bits). In each mask, bit 0 set (0×0001) for a deuce, …, bit 12 set (0×1000) for an ace. Each mask denotes the ranks present in one of the suits.

If you’d rather not know the gory details, you can use the Encode(rank, suit) macro which is defined as follows:

#define Encode(rank, suit) (1i64 << (suit*13 + rank - 2))

And you’re off! 

Usage:

The best way to learn how to use HandEval is to take a look at the two places where it’s used:

  • In the Hold’em Showdown tool
  • In Steve Brecher’s side-by-side test of the Two Plus Two, Pokersource, and HandEval evaluators

Full source code for both are, you guessed it, included with the XPokerEval distribution accompanying this article.

Limitations:

As noted above, the Brecher evaluator is obsolete when it comes to performing hand range computations. However the Brecher evaluator does offer support for multiple games, which very few of the other standalone evaluators do.

Moritz Hammer’s DAG evaluator

Description:

In A Hand Evaluator for 7-Card Poker Games, Moritz Hammer describes how he used a directed acyclic graph to perform speedy 7-card evaluation.

Cactus Kev has published a very interesting hand evaluator for 5-card games, which assigns each 5-card-hand to an equivalence class which identifies the “worth” of the hand - see the webpage for a very good explanation. A purportedly faster approach uses perfect hashing. I did not want to come up with a perfect hashing for 7-card games (frankly, I would not have known how to do it), but followed a more direct approach that employs a directed acyclic graph (DAG)

 

This is a relatively new evaluator and I don’t know how much time Moritz has had to optimize it, but it’s valuable as a clever exposition of a classic computer science technique which has a ton of practical applications. In fact, the infamous Two Plus Two evaluator described below uses a similar approach.

Implementation:

Take a look at the original post (linked above). There, Moritz explains how a DAG might be constructed for a simple three-card poker game. Extrapolate that outwards to a 52-card deck, and you’ll have a good idea of how this evaluator works. Sort of like figuring out how the 4th dimension works, by looking at the relationship between the 2nd and 3rd dimensions. By the way, just in case it’s not clear from Moritz’s post: The Hammer requires two files:

  • A file, eqcllist, containing the 7,462 poker hand equivalence classes, adapted from the Cactus Kev evaluator.
  • A file, carddag, containing the directed acyclic graph (DAG).

The Hammer ships with both of the above files, as well as the Java code to generate the carddag file, as it’s several megabytes in size. Other than that, the core evaluation code is C++.

Card Format:

Integers, with values between 0 and 51.

Usage:

Assuming you have the eqcllist and carddag files in place, you can call the handeval_init function to initialize the evaluator, and then call the calculate_equivalence_class method as necessary to evaluate hands.

// Load the 2 files needed by the evaluator…
// I’ve modified this function to take 2 filenames
// (in the original code these filenames were hardened)
handeval_init(“eqcllist”, “carddag”);

// Init counters and hand category frequencies…
int count = 0;
int freq[9];
memset(freq, 0, sizeof(freq));

// Used to store our 7-card hand
char hand[7];
handeval_eq_class* eqClass = NULL;

printf(“Enumerating and evaluating all 133,784,560 possible 7-card poker hands… );

for (hand[0] = 0; hand[0] < 46; hand[0]++) {
   for (hand[1] = hand[0]+1; hand[1] < 47; hand[1]++) {
      for (hand[2] = hand[1]+1; hand[2] < 48; hand[2]++) {
         for (hand[3] = hand[2]+1; hand[3] < 49; hand[3]++) {
            for (hand[4] = hand[3]+1; hand[4] < 50; hand[4]++) {
               for (hand[5] = hand[4]+1; hand[5] < 51; hand[5]++) {
                  for (hand[6] = hand[5]+1; hand[6] < 52; hand[6]++)
                  {
                     // Get the hand’s equivalence class
                     eqClass = calculate_equivalence_class(hand);

                     // eqClass->type yields the hand’s category
                     freq[eqClass->type]++;
                     count++;
                  }
               }
            }
         }
      }
   }
}

Note that rather than returning a single number, the evaluator returns a pointer to a handeval_eq_class object which contains various information such as the hand’s number and its human-readable description.

Limitations:

7-card games only.

Timmy’s PokerSim Library

Description:

I love the pokerai.org forums, mainly because of threads like these:

Well, I’m going to make my simulation library open source. This started out as a static library for my own use, but I figured I could make it a DLL and help some folks out.

Anyway, here are the features.
-Written in C++
-Uses the poker-eval library for speed and low memory usage
-Exposes a raw hand rank method
-Includes enumeration functions and Monte Carlo functions
-Can tell you about your hand, such as pair, top pair, flush draw, can an opponent have a straight, etc
-Includes usage example in java
-Includes full source code, compiled DLL (for any real language), and compiled java DLL (uh, for java ;) )
-VERY simple interface
-Can be used for anything you want (although I would like if you gave me credit)

Hey, free code!

Introducing the PokerSim library, a relatively recent, still mostly unknown addition to the poker hand evaluation roundup. This library has some cool functionality, though on the whole it feels like a work in progress. But if, for example, you were wanting to see how poker enumeration and simulation is done in C++, or if you were thinking about building a wrapper of some sort around the Pokersource evaluator, this would be a good place to start.

Implementation:

The PokerSim library is implemented in C++ (but can be used in Java and other languages), and uses the Pokersource Poker-Eval evaluator internally. The code is fairly easy to follow if you’re familiar with how Poker-Eval works:

// PokerSim uses the poker-eval evaluator internally…
unsigned int RankHand(const Hand& shand)
{
    CardMask e; //Used to hold a hand we are evaluating.
    CardMask_OR(e, shand.ours, shand.common);
    return Hand_EVAL_N(e, shand.size);
}

The enumeration and Monte Carlo code is a little trickier, but still pretty much business as usual.

Card Format:

The PokerSim evaluator uses the Pokersource evaluator internally, so it can work with those mask-and-integer card formats. But it’s easier to specify your cards using standard card notation (“AsAc” for example) as shown below.

Usage:

Gotta love any evaluator which lets you compute equity vs. a random opponent in one line of code:

// How does 9c9h fare against a single random opponent?
SimResults r;
SimulateHand(“9c 9h”, &r);
printf(“9c9h wins %.1f%% of the time.”, r.winSd * 100);
// OUTPUT: “9c9h wins 71.7% of the time.

The evaluator can perform hand vs. hand and hand vs. random hand evaluation for a single opponent, and hand vs. hand (but not hand vs. hand range) evaluation against multiple opponents. It also knows how to extract tactical hand elements into a PostFlopState structure.

///General info about a post flop hand.
struct PostFlopState
{
    ///Do we use both of our hole cards?
    bool UsesBoth: 1;
    bool UsesOne: 1;
    bool UsesNone: 1;

    ///What is our actual hand rank?
    bool IsNoPair: 1;
    bool IsOnePair: 1;
    bool IsTwoPair: 1;
    bool IsTrips: 1;
    bool IsStraight: 1;
    bool IsFlush: 1;
    bool IsFullHouse: 1;
    bool IsQuads: 1;
    bool IsStFlush: 1;

    bool IsTopPair: 1;
    bool IsMiddlePair: 1;
    bool IsBottomPair: 1;
    bool IsOverPair: 1;
    bool IsOverCards: 1;
    bool IsStraightDrawPossible: 1;
    bool IsStraightPossible: 1;

    bool IsFlushDrawPossible: 1;
    bool IsFlushPossible: 1;
    bool IsFullHousePossible: 1;

    bool Is3Flush: 1; ///<Do we have exactly 3 cards to a flush?
    bool Is4Flush: 1; ///<Do we have exactly 4 cards to a flush?

    unsigned int FlushOuts: 4;
    unsigned int StraightOuts: 4;
    unsigned int BetterOuts: 4;
};

This starts to bridge the gap between rote hand evaluation and hand recognition, in which we program a piece of software to “understand” a hand in the same way a human might. The above structure parallels that understanding in a basic way. 

Limitations:

Only works with Texas Hold’em.

The Senzee7 Evaluator

Description:

Paul Senzee is well known, in poker-programming circles, for his perfect hash optimization to the original Cactus Kev evaluator and for being an all-around programming BAMF. Not many people are aware that he also has a working 7-card evaluator:

Inspired by the interest in my 5-card poker hand code that plugs into Cactus Kev’s evaluator, I’ve decided to revisit my unholy 7-card evaluator and make a faster?, cleaner one that I can then post up here.

The Senzee7 evaluator, as I like to call it, hasn’t gotten as much attention as it deserves, probably because it takes some work to get up and running, and possibly because it’s somewhat slower than (for example) the Two Plus Two evaluator. But it’s a brilliant example of the power of hashing, which is way more powerful than any single programming technique has a right to be.

Implementation:

The Senzee7 evaluator represents a poker hand as a sequence of 52 bits, of which exactly 7 bits are set—one for each card.

        01100000 00000000 00011000 00001000 00000000 00000000 0101

If you do that, and you treat this bit sequence as a number (for example, an 8-byte integer), you’ll end up with a unique value for each of the 133,784,560 combinations of 7-card poker hands. The largest possible value would be 4,468,415,255,281,664—that’s four-and-a-half thousand trillion gazillion or roughly four-and-a-half quadrillion—corresponding to this bit-pattern:

        11111110 00000000 00000000 00000000 00000000 00000000 0000

The smallest possible value would be the humble 127, corresponding to this bit pattern:

        00000000 00000000 00000000 00000000 00000000 00000111 1111

Given sufficient hardware, you could simply use these 52-bit hand values to index into a lookup table containing the hand’s equivalence class, as Paul explains:

Now, if we had unlimited memory, we could just use this number as an index into an enormous and very sparse array. Unfortunately, this array would have 2^52 (4.5 quadrillion) entries. Assuming two bytes per entry, that would require 9 petabytes of memory! So we need to somehow hash this number into a much smaller space. It turns out that the number of possible combinations of 7 items among 52 is about 133 million (52 choose 7), so ideally, we could somehow hash the 52 bit number into a number between 0 and 133 million that uniquely identifies a given hand.

In other words, you could theoretically recognize any 7-card hand by:

  1. Converting it to a 52-bit number as shown above.
  2. Taking this number as an index into an enormous precomputed lookup table with 4.5 quadrillion entries, most of which are empty.
  3. The value at the index would be the official equivalence class of the hand.

Easy! But until the people at Area 51 decode the trick of peta-scale memory from top-secret alien hardware, that approach is not going to work. Instead we have to compact the size of the lookup table to something we can manage on a typical multi-gigabyte system. And there are only (approximately) 133 million 7-card poker hands, so why not size our lookup table at 133 million members?

This is the reason for hashing: to convert the raw 52-bit hand values into consecutive quantities between 0 and 133 million (approximately). We can then take this hashed quantity and use it to index into a smaller (still large at ~266MB, but feasible) precomputed lookup table containing our hand equivalence values. Our revised 7-card recognition algorithm then looks like this:

  1. Convert the hand to a 52-bit number.
  2. Hash this number to an index between 0 and roughly 133 million.
  3. Use this index to grab a value from a 266MB (133 million entries, 2 bytes per entry) lookup table.
  4. The value so obtained is the official equivalence class of the hand.

Let’s see how it works in practice.

Usage:

Some assembly required!

The Senzee7 evaluator isn’t really a hand evaluator per se, it’s a set of instructions for building a hand evaluator around a particular hashing method. A single file is provided, index52c7.h, which contains a single function of the same name: index52c7. The purpose of this function is to perform the hashing described above, i.e., massaging a 52-bit hand mask into a number between 0 and 133 million.

That’s all. The rest of the code you have to write yourself:

  • The code to generate the 266MB lookup table and populate it with equivalence values
  • The code to use the 266MB lookup table
  • The code to massage hand values into a 52-bit format

But fear not. A full version of this code is provided in the XPokerEval.Senzee7 project accompanying this article. Here’s how you’d go about building that big ol’ 266MB lookup table:

// Allocate memory for 133,784,560 two-byte entries…
short int* hand_lookup = new short int[LOOKUP_TABLE_SIZE];

// Initialize a deck of cards using a 64-bit integer
// (having exactly one bit set) for each card.
__int64 virginDeck[52];
for (int c = 0; c < 52; c++)
    virginDeck[c] = (0x1LL << c);

// Counters & card masks…
int c0, c1, c2, c3, c4, c5, c6;
__int64 h0, h1, h2, h3, h4, h5, h6;
int cactuskev_hand[7];

// Enumerate all 7-card hands…
for (c0 = 0; c0 < 46; c0++) {
   h0 = virginDeck[c0]; // first card
   cactuskev_hand[0] = DeckIndexToCactusKevCard(c0);
   for (c1 = c0+1; c1 < 47; c1++) {
      h1 = h0 | virginDeck[c1]; // 2nd card
      cactuskev_hand[1] = DeckIndexToCactusKevCard(c1);
      for (c2 = c1+1; c2 < 48; c2++) {
         h2 = h1 | virginDeck[c2]; // 3rd card
         cactuskev_hand[2] = DeckIndexToCactusKevCard(c2);
         for (c3 = c2+1; c3 < 49; c3++) {
            h3 = h2 | virginDeck[c3]; // 4th card
            cactuskev_hand[3] = DeckIndexToCactusKevCard(c3);
            for (c4 = c3+1; c4 < 50; c4++) {
               h4 = h3 | virginDeck[c4]; // 5th card
               cactuskev_hand[4] = DeckIndexToCactusKevCard(c4);
               for (c5 = c4+1; c5 < 51; c5++) {
                  h5 = h4 | virginDeck[c5]; // 6th card
                  cactuskev_hand[5] = DeckIndexToCactusKevCar d(c5);
                  for (c6 = c5+1; c6 < 52; c6++) {
                     h6 = h5 | virginDeck[c6]; // 7th card
                     cactuskev_hand[6] = DeckIndexToCactusKevCard(c6);

                     int hashedIndex = index52c7(h6);
                     hand_lookup[hashedIndex] = eval_7hand(cactuskev_hand);
                  }
               }
            }
         }
      }
   }
}

// Okay, the 266MB lookup table has been assembled. Save it.
// (using retro C-style IO here, replace as necessary…)
FILE * fout = fopen(“SENZEE7.DAT”, “wb”);
if (fout)
{
   fwrite(hand_lookup, 2, LOOKUP_TABLE_SIZE, fout);
   fclose(fout);
}

Note that we’re using Cactus Kev’s original (unoptimized!) eval_7hand function to compute the equivalence class for each 7-card hand. That’s fine as the lookup table generation code doesn’t have to be performant since we’ll only be generating this file one time.

Once we’ve got our 266MB lookup table built and saved, we’re ready to actually use the evaluator. Here’s how you’d go about enumerating and evaluating all possible 7-card poker hands:

// Load the SENZEE7.DAT file, or build it if it can’t be found…
short int* theTable = load_table(“SENZEE7.DAT”);
if (!theTable)
   return -1;

// Set up a new deck. Let each card be a 52-bit sequence with
// exactly one bit set. The “0x1LL << c” sets the cth bit.
__int64 virginDeck[52];
for (int c = 0; c < 52; c++)
   virginDeck[c] = (0x1LL << c);

// Store hand category (flush, two pair, etc) frequencies here..
int freq[9];
memset(freq, 0, sizeof(freq));

// Counters and card masks
int c0, c1, c2, c3, c4, c5, c6;
__int64 h0, h1, h2, h3, h4, h5, h6;

printf( Enumerating and evaluating all 133,784,560 million possible 7-card hands… );

for (c0 = 0; c0 < 46; c0++) {
   h0 = virginDeck[c0]; // 1st card
   for (c1 = c0+1; c1 < 47; c1++) {
      h1 = h0 | virginDeck[c1]; // 2nd card
      for (c2 = c1+1; c2 < 48; c2++) {
         h2 = h1 | virginDeck[c2]; // 3rd card
         for (c3 = c2+1; c3 < 49; c3++) {
            h3 = h2 | virginDeck[c3]; // 4th card
            for (c4 = c3+1; c4 < 50; c4++) {
               h4 = h3 | virginDeck[c4]; // 5th card
               for (c5 = c4+1; c5 < 51; c5++) {
                  h5 = h4 | virginDeck[c5]; // 6th card
                  for (c6 = c5+1; c6 < 52; c6++) {
                     h6 = h5 | virginDeck[c6]; // 7th card

                     // Hash the raw hand value to a good index
                     // using Paul Senzee’s index52c7 method.
                     int hashedIndex = index52c7(h6);
                     // Fetch the hand’s equivalence class using this index
                     int eqClass = theTable[hashedIndex];
                     // Fetch the hand’s category using Cactus Kev’s hand_rank
                     int handCategory = hand_rank(eqClass);
                     // Increment the appropriate spot in the hand category array
                     freq[handCategory-1]++;

                     // Above 4 lines of code can be combined:
                     //freq[ hand_rank(theTable[index52c7(h6)])-1 ]++;
                  }
               }
            }
         }
      }
   }
}

Again, keep in mind that the only function provided by the Senzee7 evaluator is index52c7. The other functions such as load_table and so forth have to be written by you. (And again, you can find sample implementations in the XPokerEval.Senzee7 project.)

Limitations:

The biggest problem with this evaluator is a) the fact that you have to write some code to complete it and b) its performance relative to the Two Plus Two and Pokersource evaluators.

The Two Plus Two Evaluator

Description:

Way back in 2006 a newcomer to the 2+2 poker forums opened Pandora’s box by asking the following question:

Hi all, new user but was told this was a good poker forum!

Not sure if this is the right place to post, please move if it is not.

Anyway, I’ve finished writing a 7 card hand evaluator for poker, and I’m managing to get around 14-15 million hands evaluated per second (14,000 to 15,000 per millisecond). I’ve had a look around, and is anyone aware of any software that can beat this?

Tests where done on a P4 2.4ghz PC with 1GB Ram.

Thanks for your time!

The result was an epic, twenty-four page discussion which should be required reading for every programmer. That discussion yielded one of the cleverest pieces of software in approximately forever, and what is arguably the fastest publically available poker evaluator in the world: the Two Plus Two evaluator, also referred to as the “RayW evaluator” after Ray Wotton, who first put together the reference version of the code, though as near as I can tell, the credit should go like this:

  • Ray Wotton. Reference version of the code.
  • mykey1961. Suggested the table-driven approach.
  • Steve Brecher. Side-by-side test harness, etc.
  • jukofyork. Combinadics support, Bose-Nelson.
  • Kevin Suffecool. Equivalence classes.
  • Andrew Prock. For participating, and for writing PokerStove.
  • D&L. For keeping the discussion going with some good ideas.
  • Various others on the 2+2 list…

In the Wild West of poker evaluation code, this one is a six-gun slinging, dual-wielding, down and dirty son of a Booch. And don’t you forget it.

I'm your huckleberry

Implementation:

The Two Plus Two evaluator consists of a large lookup table containing some thirty-two million entries (32,487,834 to be precise).

That’s all! Class dismissed.

In order to lookup a given 7-card poker hand, you trace a path through this table, performing one lookup per card. When you get to the last card, the value so obtained is the official equivalence value of the hand. (Note: the lookup table can also be used to perform 5-card and 6-card evaluation.)

Imagine:

You’re standing on the edge of a chessboard which stretches to the far horizon. Instead of 64 squares, there are, eh, around 32 million. Someone deals you a random 7-card poker hand. You look at your first card, which happens to be the Seven of Hearts. Looking around you, you notice that there are 52 squares nearby, each of which is labeled with a specific card in the deck. So you move to the square labeled “Seven of Hearts” because that’s what your first card was.

You then look at your second card, which happens to be the Ace of Diamonds. Well, if you look down at your feet, you’ll notice that the square you’re on contains a set of directions:

  1. If your second card is the Ace of Spades, go to Square #43,072.
  2. If your second card is the Ace of Hearts, go to Square #43,073.
  3. If your second card is the Ace of Diamonds, go to Square #43,074.
  4. And so on, for each of the remaining cards.

So you follow the directions, and move on over to Square #43,073. When you get there, you take a look at your third card, which happens to be a lowly Deuce of Clubs. Once again, you look down at your feet:

  1. If your third card is the Ace of Spades, go to Square #192,093.
  2. If your third card is the Ace of Hearts, go to Square #192,094.
  3. …and so forth
  4. If your third card is the Deuce of Clubs, go to Square #293,304.

Once again, you follow the directions, and head over to square 293,304, which takes a couple days. Here you look at your fourth card, follow the directions taking you to yet another square, where you look at your fifth card, and so forth, until you’ve gotten to the square for the seventh and last card. Glancing down at your feet one last time, you see a number, glowing crimson and shooting out sparks of electricity:

1582

That number tells you everything you need to know about everything. It is (you guessed it) the official Cactus Kev-ian equivalence value of your 7-card hand! (Okay, slight simplification here. In practice, this number is actually the hand’s equivalence value, merged with the hand’s category. But you get the point).

Expressing the above “chessboard metaphor” in code, we get something like this: a dozen of the most succinct, aggressively optimized lines you will ever lay eyes on:

// The “chessboard” / lookup table.
int HR[32487834];

// Navigate the lookup table
int GetHandValue(int* pCards)
{
    int p = HR[53 + *pCards++];
    p = HR[p + *pCards++];
    p = HR[p + *pCards++];
    p = HR[p + *pCards++];
    p = HR[p + *pCards++];
    p = HR[p + *pCards++];
    return HR[p + *pCards++];
}

A lookup table, and seven array lookups, to evaluate any 7-card poker hand in any order in no time flat. Somebody call Dr. Masaaki Hatsumi, because this is straight software development ninjitsu.

Yet another ninja

See, I promised you scantily-clad ninjas and I delivered.

Usage:

Before you can use the Two Plus Two evaluator, you have to generate the HANDRANKS.DAT file which contains the lookup table. At 123 megabytes, this file is too large to casually pass around; so instead you have to run some code to generate it on your machine. This will only need to be done once.

If you’re using the XPokerEval library, you can find the Two Plus Two table generation code in the XPokerEval.TwoPlusTwo project. Build and run this project (it will take a few minutes) and you’re good to go.

Once that’s done, using the evaluator is easy:

// The one and only lookup table.
int HR[32487834];

// Initialize the 2+2 evaluator by loading the HANDRANKS.DAT file and
// mapping it to our 32-million member HR array. Call this once and
// forget about it.
int InitTheEvaluator()
{
    memset(HR, 0, sizeof(HR));
    FILE * fin = fopen(“HANDRANKS.DAT”, “rb”);
    // Load the HANDRANKS.DAT file data into the HR array
    size_t bytesread = fread(HR, sizeof(HR), 1, fin);
    fclose(fin);
}

// Given a group of 7 cards, return the hand category & rank. Let
// pCards be (a pointer to) an array of seven integers, each with
// a value between 1 and 52.
int GetHandValue(int* pCards)
{
    int p = HR[53 + *pCards++];
    p = HR[p + *pCards++];
    p = HR[p + *pCards++];
    p = HR[p + *pCards++];
    p = HR[p + *pCards++];
    p = HR[p + *pCards++];
    return HR[p + *pCards++];
}

// Set up a 7-card poker hand, perform the lookup into the table, and
// extract the category (full house, two pair, flush, etc.) and rank
// (within that category) of the hand. These numbers can be used to
// compare the hand to other hands.
void DoSomeWork()
{
    int myCards[] = { 2, 6, 12, 14, 23, 26, 29 };
    int handInfo = GetHandValue(myCards);
    int handCategory = handInfo >> 12;
    int rankWithinCategory = handInfo & 0x00000FFF;
}

One more thing: although the Two Plus Two evaluator uses equivalence classes, it tweaks the format slightly. Cactus Kev’s equivalence classes establish an ordering of hands from 1 to 7,462. The Two Plus Two evaluator reorders these 7,462 equivalence classes within hand categories: flush, full house, two pair, and so forth. So for each evaluated hand you end up with two pieces of information: 

  • A hand category 
  • A rank within that category

And that’s why you’ll frequently see this, to retrieve the hand category:

    int handCategory = handInfo >> 12;

And this, to retrieve the rank within the category:

    int rankWithinCategory = handInfo & 0x00000FFF;

Just a slightly different way of structuring the same information.

Limitations:

The Two Plus Two evaluator only supports 5-card, 6-card, and 7-card evaluation.

Naive Hand Evaluators

Description:

No poker hand evaluator roundup would be complete without mentioning what is probably the most common type of poker hand evaluator: the naive hand evaluator.

Also known as: any hand evaluator which tries to evaluate a poker hand in a way which intuitively makes sense. Thousands of naive evaluators have been written, thanks to end-of-chapter programming exercises like this one:

Write a program to deal 1,000 random 5-card poker hands, and for each hand dealt, determine the type of poker hand it constitutes: high card, one pair, two pair, three of a kind, straight, flush, full house, four of a kind, straight flush, and royal flush.

You might even have written one or two of these yourself. I know I have.

Implementation:

Naive hand evaluators follow the common-sense approach to hand evaluation. If your hand evaluator…

  • Sorts the hand, prior to evaluating it.
  • Iterates across the hand, collecting rank and suit information as you go.
  • Makes specific tests to check if the hand is a certain type of hand, such as a Flush.
  • When hands are compared, first compares the hand category, and when the hand categories are equal, compares the individual “pieces” of the hand.

…then your hand evaluator might be a redneck naive.

If you want to see a perfect specimen of naive hand recognition, check out some old hand recognition code by K.N. King. Now, obviously K.N. King wasn’t trying to build a performant hand evaluator: he was trying to demonstrate the C programming language. And there’s nothing wrong with “naive” code, just so long as it’s not so time-consuming as to restrict your ability to perform enumerations and simulations on the fly, in a real-time poker bot or strategy tool setting.

Card Format:

Varies.

Usage:

Varies.

Limitations:

Naive hand evaluators are slow, plain and simple, at least compared to other evaluators. All that sorting, iterating, and conditional branching takes time. While naive evaluators can be built which are fast enough for basic Monte-Carlo style analysis, there’s probably never a reason to use them, considering there’s so much solid, highly-optimized code available for free.

The XPokerEval Library

Download the XPokerEval source code (1.8MB).

Well, I hope it’s clear that there’s a lot of hand evaluation source code out there. Finding, downloading, and building this source code can be a lot of fun, if fixing obscure compiler errors and platform dependency issues into the wee hours of the morning, growing steadily more and more enraged, is your idea of fun.

If it’s not your idea of fun, then you might want a clean, easy-to-build library which contains tested source code for multiple poker hand evaluators. You might want something you can download, build, and use, without fussing around with the fact that the Cactus Kev evaluator uses a drand48 function not found on Windows, or that you have to scrape the 2+2 evaluator source code, like roadkill, from an obscure forum archive.

The purpose of the XPokerEval library is to take all this open-source code and group it into an easy-to-build Visual Studio solution for Windows platforms. Now, I know what you non-Visual Studio, non-Windows types are thinking: we get the shaft, again. But you haven’t been forgotten. The XPokerEval distribution includes the original Java sources, just not as formal parts of the Visual Studio solution. And although the C/C++ code uses Windows-specific constructs, it does so in a superficial way.

  • For example, I’ve used GetTickCount to provide basic evaluator timing (poor man’s benchmarking).
  • For example, I’ve replaced the default RNG used by many evaluators with a Mersenne Twister implementation which may or may not be platform-independent. Haven’t checked.

So you would need to go through the code and spot-replace whatever doesn’t work. But if you build software on *nix, you’ve probably gotten pretty good at this. What can I say, hand evaluation code is liquid and organic stuff, forever requiring tweaking.

Conclusion

This article will be updated from time to time, as new evaluators appear, and as changes are made to existing evaluators. If you know of an evaluator not included in this list, or you are the author of such an evaluator and want it included or removed, let me know.

Apologies for the C, C++, and C# language bias in this article, and I hope I’ve made it clear that most of these evaluators, including the Two Plus Two evaluator, exist in multiple languages. If you’re a Java programmer, I recommend you check out some recent pokerai.org hand evaluation contests, where you’ll find a plethora of excellent evaluators for Java, in addition to those mentioned here.

One day soon we’ll discuss how to take all this hand evaluation code and use it to perform full-on SAIE analysis for multiple opponents and hand ranges and in general, take over the planet with our poker software. Until then, good luck, and leave us a comment if you have liked or disliked what you’ve witnessed here today.