A high-performance poker algorithm library for Texas Hold'em with Joker (wild card) support, implemented in Java, Go and C++ with feature-parity APIs. Supports up to 2 Jokers and provides two independent subsystems:
| Subsystem | Memory | Capability |
|---|---|---|
| Lookup Table | ~tens of MB | Best-hand evaluation, rank, type for 5–7 cards |
| Win Probability | ~200 MB | 1v1 win probability estimate for 2 hole + 0–4 community cards |
java/ Java implementation (Maven, published to Maven Central)
go/ Go implementation (feature-aligned port of the Java library)
cpp/ C++ implementation (feature-aligned port, CMake build)
All implementations share the same generated data tables (texas_data*.txt) and produce identical results; the Go and C++ versions are verified against the Java version with bit-level output comparison.
<dependency>
<groupId>com.github.esrrhs</groupId>
<artifactId>texas_algorithm</artifactId>
<version>1.0.14</version>
</dependency>// Load lookup table (~tens of MB, required for hand evaluation)
TexasAlgorithmUtil.load();
// Load probability table (~200 MB, required for win probability estimation)
TexasAlgorithmUtil.loadProbility();// Get the best 5-card hand from 2 hole cards + 5 community cards
// Returns a string of the best 5 cards
String best = TexasAlgorithmUtil.getMax("黑2,黑3", "方2,方A,黑7,黑5,鬼");// Get the absolute rank of a 7-card hand (higher = stronger)
// Used to compare two hands: whichever has a higher position wins
int rank = TexasAlgorithmUtil.getWinPosition("方4,方A,鬼,黑A,黑3,黑5,黑6");
// Compare two 7-card hands directly: returns positive if str1 > str2, 0 if equal, negative if str1 < str2
int cmp = TexasAlgorithmUtil.compare("方4,方A,鬼,黑A,黑3,黑5,黑6", "黑2,红3,方7,梅9,方K,黑Q,红J");// Returns an integer constant for the hand type (see Hand Types below)
int type = TexasAlgorithmUtil.getWinType("方4,方A,鬼,黑A,黑3,黑5,黑6");// Estimate win probability given 2 hole cards + some community cards
// Returns a float in [0, 1]
float p = TexasAlgorithmUtil.getHandProbability("方3,鬼", "黑2,黑4,黑5,黑K");go get github.com/esrrhs/texas_algorithm/gopackage main
import (
"fmt"
ta "github.com/esrrhs/texas_algorithm/go"
)
func main() {
// Load lookup table (~tens of MB, required for hand evaluation)
ta.Load()
// Get the best 5-card hand from 2 hole cards + 5 community cards
best, guiTrans := ta.GetMaxStrHandPub("黑2,黑3", "方2,方A,黑7,黑5,鬼")
fmt.Println(best)
// Absolute rank of a 7-card hand (higher = stronger)
rank := ta.GetWinPositionStr("方4,方A,鬼,黑A,黑3,黑5,黑6")
// Compare two 7-card hands: positive if str1 wins
cmp := ta.CompareStr("方4,方A,鬼,黑A,黑3,黑5,黑6", "黑2,红3,方7,梅9,方K,黑Q,红J")
// Hand type constant (see Hand Types below)
typ := ta.GetWinTypeStr("方4,方A,鬼,黑A,黑3,黑5,黑6")
// Load probability table (~200 MB), then estimate 1v1 win probability
ta.LoadProbility()
p := ta.GetHandProbabilityStr("方3,鬼", "黑2,黑4,黑5,黑K")
_ = guiTrans
_ = rank
_ = cmp
_ = typ
_ = p
}The Go API mirrors the Java one: Load/LoadDir ↔ load(), GetKeyData* ↔ getKeyData(), GetMax* ↔ getMax(), GetWin* ↔ getWin*(), Compare* ↔ compare(), GetHandProbability* ↔ getHandProbability(). Wild-card substitution lists are returned instead of passed as out-parameters.
cd cpp
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build --parallelRequires a C++17 compiler and CMake 3.16+.
#include "texas_algorithm_util.h"
using namespace texas_algorithm;
int main()
{
// Load lookup table (~tens of MB, required for hand evaluation)
Load();
// Get the best 5-card hand from 2 hole cards + 5 community cards
auto [best, guiTrans] = GetMaxStrHandPub("黑2,黑3", "方2,方A,黑7,黑5,鬼");
// Absolute rank of a 7-card hand (higher = stronger)
int rank = GetWinPositionStr("方4,方A,鬼,黑A,黑3,黑5,黑6");
// Compare two 7-card hands: positive if str1 wins
int cmp = CompareStr("方4,方A,鬼,黑A,黑3,黑5,黑6", "黑2,红3,方7,梅9,方K,黑Q,红J");
// Hand type constant (see Hand Types below)
int type = GetWinTypeStr("方4,方A,鬼,黑A,黑3,黑5,黑6");
// Load probability table (~200 MB), then estimate 1v1 win probability
LoadProbility();
float p = GetHandProbabilityStr("方3,鬼", "黑2,黑4,黑5,黑K");
}Link against the texas_algorithm library target. The C++ API mirrors the Java/Go one with the same naming: Load, GetKeyData*, GetMax*, GetWin*, Compare*, GetHandProbability*. Wild-card substitution lists are returned instead of passed as out-parameters.
Cards are expressed as Chinese-character strings separated by commas.
| Notation | Suit | English |
|---|---|---|
方 |
♦ | Diamond |
梅 |
♣ | Club |
红 |
♥ | Heart |
黑 |
♠ | Spade |
鬼 |
Joker | Wild card |
2 3 4 5 6 7 8 9 10 J Q K A
方A = Diamond Ace
黑K = Spade King
红10 = Heart Ten
鬼 = Joker (wild card, can substitute any card)
The getWinType() method returns one of these constants from TexasCardUtil (Go: TexasCardType* in the go package, C++: TexasCardType* in the texas_algorithm namespace — same values):
| Constant | Value | Hand |
|---|---|---|
TEXAS_CARD_TYPE_GAOPAI |
1 | High Card |
TEXAS_CARD_TYPE_DUIZI |
2 | One Pair |
TEXAS_CARD_TYPE_LIANGDUI |
3 | Two Pair |
TEXAS_CARD_TYPE_SANTIAO |
4 | Three of a Kind |
TEXAS_CARD_TYPE_SHUNZI |
5 | Straight |
TEXAS_CARD_TYPE_TONGHUA |
6 | Flush |
TEXAS_CARD_TYPE_HULU |
7 | Full House |
TEXAS_CARD_TYPE_SITIAO |
8 | Four of a Kind |
TEXAS_CARD_TYPE_TONGHUASHUN |
9 | Straight Flush |
TEXAS_CARD_TYPE_KINGTONGHUASHUN |
10 | Royal Flush |
// Load / unload
void load() // Load lookup tables into memory (current directory)
void load(String dirPath) // Load lookup tables from specified directory
void load(File dir) // Load lookup tables from specified directory
void loadProbility() // Load probability tables into memory (current directory)
void loadProbility(String dirPath) // Load probability tables from specified directory
void loadProbility(File dir) // Load probability tables from specified directory
boolean isLoaded() // Check if lookup tables are loaded
boolean isProbabilityLoaded() // Check if probability tables are loaded
// Best hand
String getMax(String hand, String pub, ...) // Best 5 cards from 2 hole + 3–5 community
List<Byte> getMax(List<Byte> pokes, ...) // Same, accepting byte lists
// Hand evaluation (requires load())
int getWinPosition(String cards) // Absolute rank among all combinations
double getWinProbability(String cards) // Win ratio vs. all same-size combinations
int getWinType(String cards) // Hand type constant
long getWinMax(String cards) // Encoded key of best 5-card hand
int compare(String str1, String str2) // Compare two 7-card hands
// Win probability estimate (requires loadProbility())
float getHandProbability(String hand, String pub) // 1v1 win probability estimateThe Go package (github.com/esrrhs/texas_algorithm/go) and the C++ library (cpp/, namespace texas_algorithm) expose the same operations with aligned naming:
| Java | Go / C++ |
|---|---|
load() / load(dir) |
Load() / LoadDir(dir) |
loadProbility() / loadProbility(dir) |
LoadProbility() / LoadProbilityDir(dir) |
isLoaded() / isProbabilityLoaded() |
IsLoaded() / IsProbabilityLoaded() |
getMax(hand, pub, ...) |
GetMaxStrHandPub(hand, pub) |
getMax(pokes, ...) |
GetMax(pokes) |
getWinPosition(cards) |
GetWinPositionStr(cards) / GetWinPosition(pokes) |
getWinProbability(cards) |
GetWinProbabilityStr(cards) / GetWinProbability(pokes) |
getWinType(cards) |
GetWinTypeStr(cards) / GetWinType(pokes) |
getWinMax(cards) |
GetWinMaxStr(cards) / GetWinMax(pokes) |
compare(str1, str2) |
CompareStr(str1, str2) / CompareBytes(a, b) / CompareKey(k1, k2) |
getHandProbability(hand, pub) |
GetHandProbabilityStr(hand, pub) / GetHandProbability(hand, pub) |
The only systematic difference: wild-card substitution lists are returned instead of being passed as out-parameters.
# Java: JUnit 5 tests (compatible with Java 8, 11, 17, 21)
cd java && mvn test
# Go: mirror of the same test suite
cd go && go test ./...
# C++: mirror of the same test suite (CMake/ctest)
cd cpp && cmake -S . -B build && cmake --build build && ctest --test-dir build --output-on-failureAll three suites run the same cases; tests that need the generated data tables skip gracefully when the files are absent (CI has no data files, local runs may).
To run the full benchmark and lookup verification:
- Extract
texas_algorithm.rarinto the working directory (java/,go/orcpp/). - Run the tests again, or
TestUtil.main()(Java) /go run ./cmd/texas_algorithm demo(Go) /./build/texas_algorithm_demo demo(C++).
- Extract
texas_algorithm.rarinto the working directory. - Java: run
TexasAlgorithmUtil.main()with JVM flag-Xmx8000m(requires ~8 GB heap); Go: rungo run ./cmd/texas_algorithmingo/; C++: run./build/texas_algorithm_demoincpp/. - Generation takes approximately 10 hours on an 8-core machine.
The lookup table answers "given N cards (5–7), what is the best possible 5-card hand and its absolute rank?"
All C(54, 7) combinations from a 52-card deck plus 2 Jokers are enumerated (~100 million combinations). Each 7-card hand is encoded into a long key. The same process is repeated for 6-card and 5-card hands.
The ~100 million entries are sorted by hand strength using multi-threaded quicksort. On an 8-core machine this takes ~10 hours. If the lookup table itself is used as the comparator instead of the brute-force evaluator, this can be reduced to ~2 hours.
The sorted array is written to texas_data.txt (~12 GB), recording the encoding key, rank order, best-5-card value, hand type, and human-readable card string for each entry.
100 million entries cannot fit in practical memory. The key insight is that suit information is redundant for non-flush hands:
- Flush hands (Flush, Straight Flush, Royal Flush): at least 5 cards share a suit. The suit distribution is normalized to
♦♦♦♦♦♣♠, reducing the keyspace dramatically. - Non-flush hands: suits are irrelevant; all suits are collapsed to
♦.
This produces two compact files (texas_data_color.txt and texas_data_normal.txt) with a combined size of ~18 MB, loading to tens of MB in memory.
Given 7 cards:
- Look up the normalized flush key in the color table.
- Look up the suit-stripped key in the normal table.
- If both match, return the entry with the higher rank.
Given 2 hole cards and 0–4 community cards, this estimates 1v1 win probability without exhaustively enumerating all remaining card combinations.
Using the 7-card rank table from above, for every N-card combination (2 ≤ N ≤ 6), the average win probability is computed by iterating over all 7-card supersets containing those N cards. This produces 5 output files (~2 GB total before compression).
The same suit-normalization trick is applied, reducing the 5 files to ~300 MB (two tables each: original and suit-stripped). Runtime memory usage is ~200 MB.
Given hole cards H and community cards C:
-
P1 — Look up the community cards alone in the probability table.
This gives the average win probability for any hand using those community cards, plusP1_maxandP1_min. -
P2 — Look up the combined hole + community cards.
This approximates the average win probability for the player's specific hand. (Minor inaccuracy: hole cards are counted twice.) -
Interpolation — Using the relationship between
P2,P1,P1_max, andP1_min, the final win probability is estimated by linear interpolation, assuming a uniform distribution of opponent hands.
| Scenario | True probability | Typical estimate | Error |
|---|---|---|---|
| General | 0.50 | 0.60 | ≤ 0.10 |
Exhaustive calculation (fixing hole + community, enumerating all remaining cards and opponents) would take 20+ days for 2 hole + 4 community cards and exceeds practical data size limits. The estimation approach achieves acceptable accuracy within those constraints.
- majiang_algorithm — Mahjong algorithm
- teenpatti_algorithm — Teen Patti (Indian poker) algorithm