A Poker Hand Evaluator based on a Perfect Hash Algorithm
Efficiently evaluating a poker hand has been an interesting and challenging problem. Given two different poker hands, how to determine which one is stronger? Or more generally, given one poker hand, can we assign a score to it indicating its strength?
Cactus Kev once gave an answer for a five-card poker hand evaluation. With smart encoding, it ranks each hand to 7462 distinct values.
Still, Kev's solution is specific for a five-card hand. To evaluate a seven-card poker hand (which is more popular because of Texas Hold'em) using Kev's algorithm, one brute force solution is to iterate all 7 choose 5 combination, running his five-card evaluation algorithm 21 times to find the best answer, which is apparently too time-inefficient. Omaha poker would be even more complicated, as it requires picking exactly two cards from four player's cards, and exactly three cards from five community cards. Using brute force, it would take 60 iterations (5 choose 3 multiplied by 4 choose 2) of Kev's 5-card evaluation algorithm.
PH Evaluator is designed for evaluating poker hands with more than 5 cards. Instead of traversing all the combinations, it uses a perfect hash algorithm to get the hand strength from a pre-computed hash table, which only costs very few CPU cycles and considerably small memory (~100kb for the 7 card evaluation). With slight modification, the same algorithm can be also applied to evaluating Omaha poker hands.
This documentation has the description of the underlying algorithm.
The cpp subdirectory has the C/C++ implementation of the algorithm, offering evaluation from 5-card hands to 7-card hands, as well as Omaha poker hands, including PLO4, PLO5, and PLO6.
One of the latest benchmark report generated by Google Benchmark:
$ ./benchmark_phevaluator
2023-09-02T11:51:57+10:00
Running ./benchmark_phevaluator
Run on (12 X 2600 MHz CPU s)
CPU Caches:
L1 Data 32 KiB
L1 Instruction 32 KiB
L2 Unified 256 KiB (x6)
L3 Unified 12288 KiB
Load Average: 2.17, 2.68, 2.67
-------------------------------------------------------------------
Benchmark Time CPU Iterations
-------------------------------------------------------------------
EvaluateAllFiveCards 33412347 ns 33377333 ns 21
EvaluateAllSixCards 286893486 ns 286658500 ns 2
EvaluateAllSevenCards 2229689783 ns 2224943000 ns 1
EvaluateRandomFiveCards 1376 ns 1375 ns 501339
EvaluateRandomSixCards 1550 ns 1549 ns 432192
EvaluateRandomSevenCards 1778 ns 1777 ns 379830
EvaluateRandomPlo4Cards 3054 ns 3014 ns 227197
EvaluateRandomPlo5Cards 3300 ns 3202 ns 221414
EvaluateRandomPlo6Cards 3441 ns 3313 ns 210607
Number of Hands | Time Used | Hands per Second | |
---|---|---|---|
All 5-card Hands | 2598960 | 33412347 ns | 77 M/s |
All 6-card Hands | 20358520 | 286893486 ns | 71 M/s |
All 7-card Hands | 133784560 | 2229689783 ns | 60 M/s |
Random 5-card Hands | 100 | 1376 ns | 72 M/s |
Random 6-card Hands | 100 | 1550 ns | 64 M/s |
Random 7-card Hands | 100 | 1778 ns | 56 M/s |
Random PLO4 Hands | 100 | 3054 ns | 32 M/s |
Random PLO5 Hands | 100 | 3300 ns | 30 M/s |
Random PLO6 Hands | 100 | 3441 ns | 29 M/s |
- The performance on random samples are slightly worse due to the overhead of accessing the pre-generated random samples in the memory.
The memory usage is measured by pmap
.
Library | Memory Used |
---|---|
pheval5 | 60k |
pheval6 | 84k |
pheval7 | 144k |
pheval | 648k |
phevalplo4 | 30516k |
phevalplo5 | 112296k |
phevalplo6 | 353484k |
The python subdirectory has the latest Python implementation.
Currently it supports 5-card, 6-card and 7-card poker hands evaluation, as well as Omaha poker hands evaluation.
You can install the library using pip
:
pip3 install phevaluator
You can find more examples from here.
Thanks to the community for contributing to the Python implementations. Especially azriel1rf, ohwi, and bensi94.
PHE is a Javascript port, developed by Thorsten Lorenz.
41Poker is another Javascript port, developed by 41semicolon.
poker is a Dart port, developed by Kohei.
ghais/poker contains a Haskell implementation of the evaluator.
gophe is a Go port, developed by mattlangl.
poker-handle has a TypeScript port, developed by pocketberserker.
PokerHandEvaluator.cs is a C# port, developed by travisstaloch.
poker_engine is a Rust port, developed by Alexander Leones.
Poker-Calculator contains a CUDA implementation of this evaluator.
A reddit user coded a Hold'em pre-flop equity estimator in C++ using the PHEvaluator library.
https://www.reddit.com/r/poker/comments/okk5qn/i_ran_1m_runouts_of_random_play_to_get_a_sense_of/
The source code can be found in sim.cc.
An article about Monte Carlo simulation of Texas Hold'em.
Estimating the outcome of a Texas hold’em game using Monte Carlo simulation
It's source code is in https://github.com/petrosDemetrakopoulos/TexasHoldemMonteCarloSimulation
All contributions are welcome. A contribution can be as small as reporting a bug by creating an issue.
If you plan to create a Pull Request, please find more details in CONTRIBUTING.md.