PokerHandEvaluator-wasm
A WebAssembly port of Henry Lee's PokerHandEvaluator, an efficient poker hand evaluation algorithm and implementation.
Features
- Evaluates poker hands (5-card, 6-card, 7-card and Omaha) using WebAssembly for high performance in browsers and Node.js
- Provides both numeric card ID interface and string-based card notation
- Small footprint, suitable for web applications
- Same fast and efficient algorithm as the original C/C++ implementation
Getting Started
Installation
You can install the prebuilt package directly from npm:
npm install poker-hand-evaluator-wasm
The npm package includes all the compiled WebAssembly files and JavaScript wrappers needed to use the library. No additional build steps are required for end-users.
For Developers: Cloning the Repository
This repository uses the original PokerHandEvaluator as a Git submodule. Use one of the following approaches:
Option 1: Clone with submodules (recommended for development)
# Clone the repository with submodules
git clone --recurse-submodules https://github.com/WenheLI/PokerHandEvaluator-wasm.git
cd PokerHandEvaluator-wasm
Option 2: Clone and then initialize submodules
If you already cloned the repository without the --recurse-submodules
flag:
git clone https://github.com/WenheLI/PokerHandEvaluator-wasm.git
cd PokerHandEvaluator-wasm
git submodule init
git submodule update
Important: The Git submodules are only needed if you're building from source or contributing to development. If you're just using the npm package, you don't need to worry about Git submodules.
Building
To build the WebAssembly module, you need to have Emscripten installed. If you don't have it already, follow the Emscripten installation instructions.
# Set up Emscripten environment
source path/to/emsdk/emsdk_env.sh
# Build the WebAssembly module
emcmake cmake .
emmake make
This will generate phevaluator.js
and phevaluator.wasm
files in the dist
directory.
Usage
In Node.js
You can import the module using either CommonJS or ES Modules.
CommonJS (require)
// Install the package
// npm install poker-hand-evaluator-wasm
const PHEvaluator = require('poker-hand-evaluator-wasm');
// Option 1: Using the simplified API (auto-initialization)
// The module is automatically initialized when required
// All API methods will throw if used before initialization completes
try {
// Evaluate a hand directly (will throw if module is not ready yet)
const result = PHEvaluator.evaluate(['As', 'Kh', 'Qd', 'Jc', '10s']);
console.log("Royal Flush:", result.toString());
} catch (error) {
console.error("Module not ready yet:", error.message);
}
// Option 2: Using async/await with the ready() method (recommended)
async function evaluateHands() {
// Wait for the module to be fully initialized
await PHEvaluator.ready();
// Now safely use any of the module's functions
const royalFlushHand = PHEvaluator.evaluate(['As', 'Kh', 'Qd', 'Jc', '10s']); // Royal Flush
console.log("Royal Flush:", royalFlushHand.toString()); // "Straight Flush (Score: 1)"
console.log("Hand Category:", royalFlushHand.categoryName()); // "Straight Flush"
console.log("Category Value:", royalFlushHand.category); // 9
console.log("Hand Score:", royalFlushHand.value); // 1
// Evaluate using specific evaluator functions
const straightFlushHand = PHEvaluator.evaluate7('Ah', 'Kh', 'Qh', 'Jh', 'Th', '9h', '8h');
console.log("Straight Flush:", straightFlushHand.toString());
// Evaluate a 6-card hand
const sixCardHand = PHEvaluator.evaluate6('Ah', 'Kh', 'Qh', 'Jh', 'Th', '9h');
console.log("Six-card hand:", sixCardHand.toString());
// Evaluate Omaha hand (4 hole cards, 5 community cards)
const omahaHand = PHEvaluator.evaluateOmaha(
'Ah', 'Kh', 'Qh', 'Jd', '2c', // Community cards
'Th', '9h', '3c', '4d' // Hole cards
);
console.log("Omaha Hand:", omahaHand.toString());
// Compare two hands (lower score is better)
const hand1 = PHEvaluator.evaluate5('Ah', 'Kh', 'Qh', 'Jh', 'Th'); // Royal Flush
const hand2 = PHEvaluator.evaluate5('As', 'Ks', 'Qs', 'Js', 'Ts'); // Royal Flush (different suit)
const hand3 = PHEvaluator.evaluate5('Ah', 'Ad', 'Ac', 'As', 'Kh'); // Four of a Kind
if (hand1.value === hand2.value) {
console.log("Hand 1 and Hand 2 are equal in strength");
} else if (hand1.value < hand2.value) {
console.log("Hand 1 is stronger than Hand 2");
} else {
console.log("Hand 2 is stronger than Hand 1");
}
}
evaluateHands().catch(console.error);
// Option 3: Using the traditional Promise API
PHEvaluator.ready().then(function() {
const hand = PHEvaluator.evaluate(['As', 'Ks', 'Qs', 'Js', 'Ts']);
console.log("Royal Flush:", hand.toString());
}).catch(console.error);
// Option 4: Check if the module is already initialized
if (PHEvaluator.isReady()) {
// Safe to use synchronously if already initialized
const hand = PHEvaluator.evaluate(['As', 'Ks', 'Qs', 'Js', 'Ts']);
console.log(hand.toString());
}
// Option 5: Access the raw WebAssembly module directly (advanced usage)
PHEvaluator.ready().then(function() {
const rawModule = PHEvaluator.getRawModule();
// Use the raw module API directly
const Ah = new rawModule.Card(51);
const Kh = new rawModule.Card(47);
});
ES Modules (import)
// Install the package
// npm install poker-hand-evaluator-wasm
import PHEvaluator from 'poker-hand-evaluator-wasm';
// You can also import the factory function directly if needed
// import PHEvaluator, { PokerHandEvaluatorWasmFactory } from 'poker-hand-evaluator-wasm';
// Option 1: Using the simplified API (auto-initialization)
// The module is automatically initialized when imported
// All API methods will throw if used before initialization completes
try {
// Evaluate a hand directly (will throw if module is not ready yet)
const result = PHEvaluator.evaluate(['As', 'Kh', 'Qd', 'Jc', '10s']);
console.log("Royal Flush:", result.toString());
} catch (error) {
console.error("Module not ready yet:", error.message);
}
// Option 2: Using async/await with the ready() method (recommended)
async function evaluateHands() {
// Wait for the module to be fully initialized
await PHEvaluator.ready();
// Now safely use any of the module's functions
const royalFlushHand = PHEvaluator.evaluate(['As', 'Ks', 'Qs', 'Js', 'Ts']); // Royal Flush
console.log("Royal Flush:", royalFlushHand.toString());
}
evaluateHands().catch(console.error);
API Reference
The WebAssembly module exposes the following classes and functions:
Classes
Card
new Card(id)
- Create a new Card object with the given card IDCard.prototype.describeCard()
- Get a string description of the cardCard.prototype.describeRank()
- Get a string description of the card's rankCard.prototype.describeSuit()
- Get a string description of the card's suitCard.prototype.id()
- Get the numeric ID of the cardCard.prototype.toString()
- Get a string representation of the card
HandRank
HandRank.prototype.value
- The numeric score of the hand (lower is better)HandRank.prototype.category
- The category of the hand (1-9, where 9 is the best)HandRank.prototype.categoryName()
- Get the name of the hand category (e.g., "Straight Flush")HandRank.prototype.toString()
- Get a string representation of the hand with category and score
Functions Using Card Objects
evaluate5(a, b, c, d, e)
- Evaluate a 5-card poker handevaluate6(a, b, c, d, e, f)
- Evaluate a 6-card poker handevaluate7(a, b, c, d, e, f, g)
- Evaluate a 7-card poker handevaluateOmaha(c1, c2, c3, c4, c5, h1, h2, h3, h4)
- Evaluate an Omaha poker hand
Functions Using String Notation
evaluate5FromStrings(a, b, c, d, e)
- Evaluate a 5-card poker hand using string notationevaluate6FromStrings(a, b, c, d, e, f)
- Evaluate a 6-card poker hand using string notationevaluate7FromStrings(a, b, c, d, e, f, g)
- Evaluate a 7-card poker hand using string notationevaluateOmahaFromStrings(c1, c2, c3, c4, c5, h1, h2, h3, h4)
- Evaluate an Omaha poker hand using string notation
Utility Functions
createCardFromString(cardStr)
- Create a Card object from a string representationcreateCardFromId(id)
- Create a Card object from a numeric IDcardStringToId(cardStr)
- Convert a card string to its corresponding card ID
String notation format: <rank><suit>
where:
- Rank: 2, 3, 4, 5, 6, 7, 8, 9, T, J, Q, K, A
- Suit: c (clubs), d (diamonds), h (hearts), s (spades)
Examples: "Ah" (Ace of hearts), "Kd" (King of diamonds), "2c" (Two of clubs)
Demos & Examples
See the file in example folder
Project Structure
src/
- C++ WASM bindingssrc/phevaluator_wasm.cpp
- C++ wrapper for exposing the poker hand evaluator to JavaScriptsrc/include/
- Header files
lib/
- JavaScript wrapper codedist/
- Compiled WebAssembly outputexamples/
- Usage examples__tests__/
- Test suitePokerHandEvaluator/
- Git submodule of the original PokerHandEvaluator libraryCMakeLists.txt
- CMake build configuration for the WebAssembly module.github/workflows/
- GitHub Actions workflows for testing and publishing
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
License
This project is licensed under the Apache License 2.0, the same as the original PokerHandEvaluator.