Important: This documentation covers Yarn 1 (Classic).
For Yarn 2+ docs and migration guide, see yarnpkg.com.

Package detail

@pokertools/evaluator

aaurelions309MIT1.0.1TypeScript support: included

High-performance Poker Hand Evaluator (5, 6, and 7 cards)

poker, hand, evaluator, texas, holdem, typescript, poker-hand, poker-evaluator, card-game, performance

readme

@pokertools/evaluator

npm version License: MIT

A lightning-fast, strongly-typed Poker Hand Evaluator for Node.js and the browser.

Capable of evaluating over 16 million 7-card hands per second on a standard CPU. This library uses a Perfect Hash algorithm (based on Cactus Kev/Paul Senzee) optimized specifically for the V8 JavaScript engine.

🚀 Features

  • Extreme Performance: ~17M evaluations/sec (7-card hands).
  • Zero Garbage Collection: Uses static memory buffers to prevent GC overhead during Monte Carlo simulations.
  • Flexible: Supports 5, 6, and 7 card hands.
  • TypeScript: Written in strict TypeScript with full type definitions.
  • Lightweight: Zero runtime dependencies.

⚡ Benchmarks

Comparison of 7-card hand evaluation speed (Node.js V8):

Library Input Type Speed (Hands/Sec) Relative Speed
@pokertools/evaluator Integer ~17,900,000 100%
phe Integer ~16,550,000 92.5%
poker-evaluator String ~1,390,000 7.7%
pokersolver String ~73,000 0.4%

Raw Output

🃏 Starting Benchmark: 1000 random 7-card hands per cycle
----------------------------------------------------------------
phe (Int)                 |      16,574,257 hands/sec | ±2.26%
poker-evaluator (Str)     |       1,375,495 hands/sec | ±0.33%
pokersolver (Str)         |          70,980 hands/sec | ±0.70%
@pokertools (Int)         |      17,915,292 hands/sec | ±1.56%
----------------------------------------------------------------
🚀 WINNER: @pokertools (Int)

Benchmarks run on an M1 Air. Higher is better.

📦 Installation

npm install @pokertools/evaluator

📖 Usage

1. Basic Usage (Strings)

If you are building a UI or simple game logic, string inputs are easiest to work with.

import { evaluateBoard, rankBoard, rankDescription } from "@pokertools/evaluator";

// 1. Get a raw strength score (lower is better)
const score = evaluateBoard("Ah Kh Qh Jh Th 2c 3c");
console.log(score); // 1 (Royal Flush is the lowest/best number)

// 2. Get the Rank Category (Enum)
const rank = rankBoard("Ah As Ks Kd Qs Qd 2c");
console.log(rankDescription(rank)); // "Two Pair"

2. High-Performance Usage (Integers)

If you are building an Equity Calculator or AI Solver, you should convert cards to integers once and pass integers around your system. This creates a 12x performance boost by skipping string parsing.

import { evaluate, getCardCode, rank, HandRank } from "@pokertools/evaluator";

// Convert strings to integers once
const holeCards = [getCardCode("As"), getCardCode("Ah")];
const board = [getCardCode("Ks"), getCardCode("Kh"), getCardCode("Qs")];

// Combine arrays (Spread operator is fast enough for small arrays)
const hand = [...holeCards, ...board];

// Evaluate
const strength = evaluate(hand);

// Check Rank
if (rank(hand) === HandRank.FullHouse) {
  console.log("We have a boat!");
}

📚 API Reference

Core Functions

evaluate(codes: number[]): number

The fastest evaluation method. Accepts an array of 5, 6, or 7 integers. Returns a raw score (lower is better).

  • Royal Flush: 1
  • ...
  • Worst High Card: 7462

evaluateStrings(cards: string[]): number

Helper to evaluate an array of strings like ['Ah', 'Td', ...].

evaluateBoard(board: string): number

Helper to evaluate a space-separated string like "Ah Td 2c".

Ranking Helpers

rank(codes: number[]): HandRank

Returns the HandRank enum (0-8) for a set of card integers.

HandRank (Enum)

enum HandRank {
  StraightFlush = 0,
  FourOfAKind = 1,
  FullHouse = 2,
  Flush = 3,
  Straight = 4,
  ThreeOfAKind = 5,
  TwoPair = 6,
  OnePair = 7,
  HighCard = 8,
}

rankDescription(rank: HandRank): string

Returns human-readable strings like "Full House" or "High Card".

Card Encoding

getCardCode(cardStr: string): number

Converts a card string (e.g., "Ah") into the optimized integer format used by this library.

stringifyCardCode(code: number): string

Converts an integer back into a readable string.

🧮 Algorithm

This library implements the Perfect Hash algorithm.

  1. It first checks for a Flush using a bitmask OR operation.
  2. If no flush, it calculates a unique prime-product hash (Quinary) based on the rank counts.
  3. This hash is used as an index into a pre-computed DAG (Directed Acyclic Graph) lookup table to immediately return the hand strength.

This approach avoids expensive sorting or pattern matching operations found in slower libraries.

License

MIT

changelog

Changelog

All notable changes to this project will be documented in this file.

The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.

[1.0.1] - 2025-11-30

Added

@pokertools/engine

  • ADD_CHIPS action for chip rebuys/top-ups during hands
  • RESERVE_SEAT action for seat reservations with expiry timestamps
  • "Wait for Big Blind" logic via SitInOption enum

@pokertools/types

  • ActionType.ADD_CHIPS and ActionType.RESERVE_SEAT action types
  • AddChipsAction and ReserveSeatAction interfaces
  • PlayerStatus.RESERVED status for seat reservations
  • SitInOption enum (IMMEDIATE, WAIT_FOR_BB)
  • Player.pendingAddOn field for pending chip additions
  • Player.sitInOption field for sit-in timing preference
  • Player.reservationExpiry field for reservation expiration tracking
  • Optional sitInOption parameter on SitAction

Changed

@pokertools/engine

  • handleDeal() now merges pendingAddOn into player stack at hand start
  • handleDeal() automatically removes expired seat reservations
  • handleDeal() enforces "Wait for BB" logic in cash games
  • handleSit() initializes new player fields with defaults
  • gameReducer supports new management actions

1.0.0 - 2025-11-29

Added

@pokertools/engine

  • Complete Texas Hold'em poker engine implementation
  • Immutable state management (Redux-style)
  • TDA rules compliance (100%)
  • Chip conservation guarantees
  • Side pot calculation with iterative subtraction
  • Dead button rule implementation
  • Heads-up positioning logic
  • Incomplete raise handling
  • Auto-runout for all-in scenarios
  • Rake calculation (No Flop, No Drop)
  • Player view masking for security
  • Hand history export
  • Comprehensive test suite (117 tests passing)
  • Property-based testing with fast-check
  • Integration tests for full gameplay scenarios

@pokertools/evaluator

  • Lightning-fast hand evaluator (16M+ hands/sec)
  • Perfect Hash algorithm implementation
  • Support for 5, 6, and 7 card hands
  • Zero garbage collection overhead
  • TypeScript type definitions
  • Comprehensive test suite

@pokertools/types

  • Complete TypeScript type definitions
  • Immutable type design
  • Zero runtime dependencies
  • Shared types across all packages

@pokertools/bench

  • Performance benchmarking suite
  • Comparison with popular evaluators
  • Detailed analysis and results

Changed

  • N/A (initial release)

Deprecated

  • N/A (initial release)

Removed

  • N/A (initial release)

Fixed

  • Chip conservation violation in pot recalculation
  • Incomplete raise validation for short-stack all-ins
  • Action history street tracking
  • Property test strictness

Security

  • View masking to prevent cheating
  • Integer-only arithmetic to prevent float exploits
  • Immutable state to prevent tampering

Release Process

To create a new release:

  1. Update version numbers in package.json files
  2. Update this CHANGELOG.md with the new version
  3. Commit changes: git commit -am "chore: release vX.Y.Z"
  4. Create tag: git tag vX.Y.Z
  5. Push: git push && git push --tags
  6. Create GitHub Release
  7. GitHub Actions will automatically publish to NPM

Version Number Guidelines

Given a version number MAJOR.MINOR.PATCH:

  • MAJOR: Incompatible API changes
  • MINOR: Backwards-compatible functionality additions
  • PATCH: Backwards-compatible bug fixes