Championship-grade single-table Texas Hold'em engine for Node.js with comprehensive position information and integer-validated betting.
v4.5.0 adds comprehensive showdown tracking for tournament logging and analytics:
- โ
Complete Showdown Data -
hand:endedevents now include ALL players who reached showdown - โ Tournament Logging Ready - Perfect for comprehensive hand history and analytics
- โ
Backward Compatible - Existing
winnersarray unchanged, newshowdownParticipantsadded - โ Detailed Information - Each participant includes hand strength, cards, and amount won/lost
- โ Client-Requested Feature - Direct response to PokerSim client team requirements
table.on('hand:ended', ({ winners, showdownParticipants }) => {
// Traditional winners array (unchanged)
console.log('Winners:', winners);
// NEW: All showdown participants with complete data
showdownParticipants.forEach(participant => {
console.log(`${participant.playerId}: ${participant.hand.description} - ${participant.amount > 0 ? 'Won' : 'Lost'} $${Math.abs(participant.amount)}`);
});
});- โ All-In Blind Posting FIXED - Games no longer freeze when players have insufficient chips for blinds
- โ Bet Clearing Bug FIXED - Player bets properly cleared when hands end by folding
- โ Tournament Stability - Memory exhaustion and infinite loops completely resolved
v4.4.2 exposed the powerful WildcardEventEmitter class for client applications:
- Advanced Event Monitoring - Listen to ALL events with a single
on('*', ...)listener - Perfect for Debugging - Capture complete event flow for analysis
- Analytics Ready - Build comprehensive event tracking systems
- Zero Overhead - EventEmitter3 based for optimal performance
- Full Documentation - Complete guide with examples and best practices
The hand:started event now provides comprehensive position information:
table.on('hand:started', ({ players, dealerButton, positions }) => {
// Easy position identification
console.log(`Button: ${positions.button}`);
console.log(`Big Blind: ${positions.bigBlind}`);
console.log(`Under the Gun: ${positions.utg}`);
// Detailed position mapping for all players
console.log('All positions:', positions.positions);
// Example: { "player1": "button", "player2": "small-blind", "player3": "big-blind" }
});Position Names Supported:
button,small-blind,big-blind,under-the-gunmiddle-position,cutoff,late-positionbutton-small-blind(heads-up)- Dead button information with
isDeadButtonandisDeadSmallBlindflags
See POSITION_API_EXAMPLE.md for complete usage examples.
- All chip/bet/pot amounts enforced as integers - Prevents floating-point precision issues
- Graceful rounding - Fractional amounts automatically rounded to nearest integer
- Comprehensive validation - Covers blinds, bets, raises, chips, and pot calculations
- Backward compatible - Existing code continues to work
- Detailed failure information - Know exactly why games fail to start
- Comprehensive debugging context - Player states, chip counts, error traces
- Structured result objects - Programmatic access to failure reasons
const result = await table.tryStartGame();
if (!result.success) {
console.error(`Failed: ${result.reason}`);
console.error(`Details:`, result.details);
}- No fold-when-can-check - Prevents unrealistic gameplay
- Immediate crash on violations - Fast feedback for development
- Action enum enforcement - Must use
Action.FOLD, not string 'FOLD' - Race-condition free - Proper event ordering for tournament systems
This package is published to GitHub Packages. To install:
-
Get a GitHub Personal Access Token with
read:packagesscope from https://github.com/settings/tokens/new -
Configure npm for GitHub Packages:
echo "@jkraybill:registry=https://npm.pkg.github.com" >> .npmrc echo "//npm.pkg.github.com/:_authToken=YOUR_GITHUB_TOKEN" >> .npmrc
-
Install the package:
npm install @jkraybill/poker-game-manager # Requires Node.js 22+
import { PokerGameManager, Player, Action } from '@jkraybill/poker-game-manager';
// Create a position-aware player
class PositionalPlayer extends Player {
constructor(config) {
super(config);
this.currentPosition = null;
}
async getAction(gameState) {
const { validActions, toCall } = gameState;
// Position-based strategy
switch(this.currentPosition) {
case 'button':
// Aggressive from button
if (validActions.includes(Action.RAISE)) {
return { action: Action.RAISE, amount: gameState.bigBlind * 3 };
}
break;
case 'big-blind':
// Defend big blind
if (validActions.includes(Action.CALL) && toCall <= gameState.bigBlind * 3) {
return { action: Action.CALL };
}
break;
case 'under-the-gun':
// Tight from UTG
if (validActions.includes(Action.FOLD)) {
return { action: Action.FOLD };
}
break;
}
// Default strategy
if (validActions.includes(Action.CHECK)) return { action: Action.CHECK };
if (validActions.includes(Action.CALL) && toCall <= 20) return { action: Action.CALL };
return { action: Action.FOLD };
}
}
// Set up the game
const manager = new PokerGameManager();
const table = manager.createTable({
blinds: { small: 10, big: 20 },
maxPlayers: 6
});
// Add players with starting chips
const alice = new PositionalPlayer({ id: 'alice', name: 'Alice' });
alice.chips = 1000;
table.addPlayer(alice);
const bob = new PositionalPlayer({ id: 'bob', name: 'Bob' });
bob.chips = 1000;
table.addPlayer(bob);
// Update player positions when hand starts
table.on('hand:started', ({ positions }) => {
// Update all players with their current positions
Object.entries(positions.positions).forEach(([playerId, position]) => {
const playerData = table.players.get(playerId);
if (playerData) {
playerData.player.currentPosition = position;
}
});
console.log('New hand positions:', positions.positions);
});
// Listen for results
table.on('hand:ended', (result) => {
console.log('Hand complete!', result.winners);
});
// Start the game
const result = await table.tryStartGame();
if (result.success) {
console.log('Game started successfully!');
} else {
console.error('Failed to start:', result.details.message);
}// Main imports
import { PokerGameManager, Table, Player } from '@jkraybill/poker-game-manager';
// Type imports
import { Action, GamePhase, PlayerState, TableState } from '@jkraybill/poker-game-manager';
// Specific module imports
import { Table } from '@jkraybill/poker-game-manager/table';
import { Player } from '@jkraybill/poker-game-manager/player';
import { Action, GamePhase } from '@jkraybill/poker-game-manager/types';
// Game components
import { HandEvaluator, Deck, GameEngine } from '@jkraybill/poker-game-manager';
// Event system (v4.4.2+)
import { WildcardEventEmitter } from '@jkraybill/poker-game-manager';
import { WildcardEventEmitter } from '@jkraybill/poker-game-manager/wildcard-event-emitter';
// Validation utilities (v4.3.0+)
import { validateIntegerAmount, ensureInteger } from '@jkraybill/poker-game-manager/utils/validation';
// CommonJS also supported
const { PokerGameManager, Player } = require('@jkraybill/poker-game-manager');- Texas Hold'em Rules - Complete implementation with edge case handling
- Dead Button Rules - WSOP-compliant tournament position management
- Side Pots - Complex all-in scenarios with precise chip distribution
- Split Pots - Correct odd chip distribution and tied hand handling
- Hand Evaluation - Fast and accurate using pokersolver library
- Position Tracking - Comprehensive position information for strategic play
- Clean APIs - Intuitive interfaces with comprehensive events
- Event-Driven Architecture - React to game changes in real-time
- Flexible Player System - Any player implementation can connect
- Championship Testing - 308+ tests covering all scenarios
- Complete Type Definitions - Full JSDoc documentation
- Integer Validation - All monetary values guaranteed to be integers
- Lightning Performance - Sub-millisecond hand evaluation
- Memory Efficient - Optimized object management and caching
- Robust Error Handling - Detailed diagnostics and graceful failures
- CI/CD Pipeline - Automated testing and releases
- Zero Dependencies - Only essential poker-related packages
- Position API Examples - Comprehensive position usage guide
- WildcardEventEmitter Guide - Advanced event monitoring and debugging
- Integration Guide - Player implementation patterns
- Testing Guide - Test utilities and patterns
- Poker Rules - Complete rule reference
- Examples - Working code examples
# Test suite (308+ tests - championship coverage!)
npm test
# Specific test categories
npm test -- position-information # Position API tests
npm test -- integer-validation # Monetary validation tests
npm test -- dead-button # Tournament position rules
npm test -- side-pots # Complex pot scenarios
# Code quality
npm run lint # ESLint validation
npm run format # Prettier formatting
npm run test:coverage # Coverage reporting
# Build
npm run build # Creates dist/ for distribution
# ๐จ NEVER manually publish - CI handles releases!
# โ
Create tags for automated publishing:
git tag v4.x.x && git push origin v4.x.xAutomated Release Process:
- Push changes to
masterand verify CI passes โ - Update
package.jsonversion and commit - Create and push git tag:
git tag v4.x.x && git push origin v4.x.x - GitHub Actions automatically publishes to GitHub Packages
Never run npm publish manually - it causes CI conflicts!
- Node.js >= 22.0.0 (tested on latest versions)
- npm >= 10.0.0
packages/core/src/
โโโ PokerGameManager.js # Multi-table management
โโโ Table.js # Single table with position tracking
โโโ Player.js # Base player class
โโโ game/
โ โโโ GameEngine.js # Core Texas Hold'em with position calculation
โ โโโ PotManager.js # Betting and pot management
โ โโโ HandEvaluator.js # Fast hand strength calculation
โ โโโ Deck.js # Card management
โโโ utils/
โ โโโ validation.js # Integer validation utilities
โโโ types/ # Complete type definitions
โโโ integration/ # 84+ test files total
Championship-Grade Single-Table Texas Hold'em:
โ
Complete Rule Implementation - All Texas Hold'em scenarios handled correctly
โ
Position Intelligence - Comprehensive position tracking and identification
โ
Tournament Standards - Dead button, side pots, split pots like the pros
โ
Integer Precision - All monetary values validated as integers
โ
Comprehensive Testing - 308+ tests across 84 test files
โ
Production Performance - Optimized for real-world usage
โ
Clean Architecture - Event-driven design that scales
// Implement sophisticated strategies using position data
class TournamentPlayer extends Player {
getAction(gameState) {
const position = this.getCurrentPosition();
const playerCount = Object.keys(gameState.players).length;
// Adjust strategy based on position and table size
return this.getPositionalStrategy(position, playerCount)
.getAction(gameState);
}
}// All amounts automatically validated and rounded
player.chips = 1000.5; // Becomes 1000
table.blinds = { small: 10.3, big: 20.7 }; // Becomes 10, 21// Rich event data for analysis and debugging
table.on('hand:started', ({ positions, players, dealerButton }) => {
// Position tracking, player states, button location
});
table.on('player:action', ({ playerId, action, amount, position }) => {
// Track every action with context
});
table.on('hand:ended', ({ winners, pot, sidePots, board }) => {
// Complete hand results with detailed breakdowns
});The vision continues to expand:
- ๐ Advanced Analytics - Decision tracking and EV calculation
- ๐ฎ Training Scenarios - Practice specific poker situations
- ๐ Multi-Table Tournaments - Full tournament management
- ๐ Poker Variants - Omaha, Short Deck, Mixed Games
- ๐ง AI Integration - Neural network player implementations
This library embodies championship-level poker software:
- Correctness First - Every rule implemented precisely
- Developer Experience - Clean, well-documented APIs
- Performance Matters - Fast enough for production use
- Testing Excellence - Comprehensive scenario coverage
- Real-World Ready - Built for actual poker applications
"Championship-grade doesn't happen by accident" - Every feature is thoroughly tested and validated against real poker scenarios.
MIT License - see LICENSE.md
Found a bug? Got an enhancement idea?
- Report issues on GitHub Issues
- Follow the comprehensive testing patterns in TESTING_GUIDE.md
- Maintain the championship standard - all features must be thoroughly tested
Built for poker excellence. ๐๐