UNPKG

@idealic/poker-engine

Version:

Professional poker game engine and hand evaluator with built-in iterator utilities

286 lines 10.2 kB
import { dealStreet as dealStreetAction, showCards as dealerShowCards } from './game/dealer'; /** * Command constructor/factory function that creates actions from a request object. * Acts as a unified interface for creating poker actions with validation. * * @param props - Command request properties * @returns Action string that can be applied to the game * * @example * const action = Command({ * type: 'bet', * game: gameState, * playerIndex: 1, * amount: 100 * }); * * @example * const action = Command({ * type: 'fold', * game: gameState, * playerIndex: 0 * }); */ export function Command(props) { const { type, game, playerIndex, amount, cards } = props; // Basic validation if (!game || !game.players) { throw new Error('Command requires valid game state'); } if (typeof playerIndex !== 'number' || playerIndex < 0 || playerIndex >= game.players.length) { throw new Error('Command requires valid playerIndex'); } // Route to appropriate command implementation switch (type) { case 'fold': return fold(game, playerIndex); case 'call': return call(game, playerIndex); case 'check': return check(game, playerIndex); case 'bet': if (typeof amount !== 'number' || amount <= 0) { throw new Error('bet command requires positive amount'); } return bet(game, playerIndex, amount); case 'raise': if (typeof amount !== 'number' || amount <= 0) { throw new Error('raise command requires positive amount'); } return raise(game, playerIndex, amount); case 'allIn': return allIn(game, playerIndex); case 'dealBoard': if (!Array.isArray(cards) || cards.length === 0) { throw new Error('dealBoard command requires non-empty cards array'); } return dealBoard(game, cards); case 'dealHoleCards': if (!Array.isArray(cards) || cards.length === 0) { throw new Error('dealHoleCards command requires non-empty cards array'); } return dealHoleCards(game, playerIndex, cards); case 'dealStreet': return dealStreet(game); case 'showCards': return showCards(game); default: throw new Error(`Unknown command type: ${type}`); } } /** * Returns a fold action string without applying it */ function fold(_, playerIndex) { return `p${playerIndex + 1} f`; } /** * Returns a check action string without applying it */ function check(game, playerIndex) { return `p${playerIndex + 1} cc 0`; } /** * Returns a call action string without applying it. * Available stack includes current bet since it will be returned when calling. */ function call(game, playerIndex) { const player = game.players[playerIndex]; const availableStack = player.stack + player.currentBet; const amountToCall = game.bet - player.currentBet; const callAmount = Math.min(amountToCall, availableStack); return `p${playerIndex + 1} cc ${player.currentBet + callAmount}`; } /** * Returns a bet action string without applying it. * Available stack includes current bet since it will be returned when betting. */ function bet(game, playerIndex, amount) { const player = game.players[playerIndex]; const availableStack = player.stack + player.currentBet; const betAmount = Math.min(amount, availableStack); return `p${playerIndex + 1} cbr ${betAmount}`; } /** * Returns a raise action string without applying it. * Available stack includes current bet since it will be returned when raising. */ function raise(game, playerIndex, amount) { const player = game.players[playerIndex]; const availableStack = player.stack + player.currentBet; const raiseAmount = Math.min(amount, availableStack); return `p${playerIndex + 1} cbr ${raiseAmount}`; } /** * Player bets their entire remaining stack. * This action automatically determines whether it's a bet or raise based on the current game state. * * @param game - The current game state * @param playerIndex - Index of the player (0-based) * @returns Action string for going all-in */ function allIn(game, playerIndex) { const player = game.players[playerIndex]; const availableStack = player.stack + player.currentBet; // If no bet exists or player hasn't bet yet, it's a bet if (game.bet === 0 || game.bet === player.currentBet) { return bet(game, playerIndex, availableStack); } // Otherwise it's a raise return raise(game, playerIndex, availableStack); } /** * Returns a deal board action string without applying it */ function dealBoard(_table, cards) { return `d db ${cards.join('')}`; } /** * Returns a deal hole cards action string without applying it */ function dealHoleCards(_table, playerIndex, cards) { return `d dh p${playerIndex + 1} ${cards.join('')}`; } /** * Advances the game to the next betting round by dealing appropriate cards. * * @param game - The current game state * @returns Action string for dealing street cards */ function dealStreet(game) { return dealStreetAction(game); } /** * Shows cards for showdown or mucking. * * @param game - The current game state * @returns Action string for showing cards */ function showCards(game) { const action = dealerShowCards(game); if (!action) { throw new Error('No cards to show'); } return action; } /** * Command namespace containing all command functions. * These functions generate action strings that can be applied to the game using Game.applyAction(). */ (function (Command) { /** * Player folds their hand and forfeits the current round * @param game - Current game state * @param playerIndex - Index of the player (0-based) * @returns Action string for folding */ Command.fold = (game, playerIndex) => { return `p${playerIndex + 1} f`; }; /** * Player matches the current bet amount * @param game - Current game state * @param playerIndex - Index of the player (0-based) * @returns Action string for calling */ Command.call = (game, playerIndex) => { const player = game.players[playerIndex]; const availableStack = player.stack + player.currentBet; const amountToCall = game.bet - player.currentBet; const callAmount = Math.min(amountToCall, availableStack); return `p${playerIndex + 1} cc ${player.currentBet + callAmount}`; }; /** * Player passes when no bet is required * @param game - Current game state * @param playerIndex - Index of the player (0-based) * @returns Action string for checking */ Command.check = (game, playerIndex) => { return `p${playerIndex + 1} cc 0`; }; /** * Player makes an initial bet * @param game - Current game state * @param playerIndex - Index of the player (0-based) * @param amount - Total bet amount * @returns Action string for betting */ Command.bet = (game, playerIndex, amount) => { const player = game.players[playerIndex]; const availableStack = player.stack + player.currentBet; const betAmount = Math.min(amount, availableStack); return `p${playerIndex + 1} cbr ${betAmount}`; }; /** * Player increases the current bet * @param game - Current game state * @param playerIndex - Index of the player (0-based) * @param amount - Total raise amount * @returns Action string for raising */ Command.raise = (game, playerIndex, amount) => { const player = game.players[playerIndex]; const availableStack = player.stack + player.currentBet; const raiseAmount = Math.min(amount, availableStack); return `p${playerIndex + 1} cbr ${raiseAmount}`; }; /** * Player bets their entire remaining stack * @param game - Current game state * @param playerIndex - Index of the player (0-based) * @returns Action string for going all-in */ Command.allIn = (game, playerIndex) => { const player = game.players[playerIndex]; const availableStack = player.stack + player.currentBet; // If no bet exists or player hasn't bet yet, it's a bet if (game.bet === 0 || game.bet === player.currentBet) { return `p${playerIndex + 1} cbr ${availableStack}`; } // Otherwise it's a raise return `p${playerIndex + 1} cbr ${availableStack}`; }; /** * Deals community cards to the board * @param game - Current game state * @param cards - Array of card strings to deal * @returns Action string for dealing board cards */ Command.dealBoard = (game, cards) => { return `d db ${cards.join('')}`; }; /** * Deals hole cards to a specific player * @param game - Current game state * @param playerIndex - Index of the player (0-based) * @param cards - Array of card strings to deal * @returns Action string for dealing hole cards */ Command.dealHoleCards = (game, playerIndex, cards) => { return `d dh p${playerIndex + 1} ${cards.join('')}`; }; /** * Advances the game to the next betting round * @param game - Current game state * @returns Action string for dealing street cards */ Command.dealStreet = (game) => { return dealStreetAction(game); }; /** * Shows cards for showdown or mucking * @param game - Current game state * @returns Action string for showing cards */ Command.showCards = (game) => { const action = dealerShowCards(game); if (!action) { throw new Error('No cards to show'); } return action; }; })(Command || (Command = {})); // Export individual functions for backward compatibility export { fold, check, call, bet, raise, dealBoard, dealHoleCards, dealStreet, showCards, allIn }; //# sourceMappingURL=Command.js.map