UNPKG

@idealic/poker-engine

Version:

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

137 lines (111 loc) 4.57 kB
import express from 'express'; import * as Poker from 'poker-engine'; const app = express(); app.use(express.json()); // Database operations (stubbed) function loadGameHand(gameId: string): Poker.Hand | null { // TODO: Load the Hand from database by gameId // The 'log' JSONB field contains the actions array // const result = await db.query('SELECT * FROM games WHERE id = $1', [gameId]); // const game = result.rows[0]; // return { // actions: game.log, // log contains the actions array // variant: game.variant, // seed: game.seed, // // ... construct other Hand properties from game metadata // }; return null; } function saveGameHand(gameId: string, hand: Poker.Hand): void { // TODO: Save the Hand to database and update timeout // The 'log' JSONB field stores the actions array // const game = Poker.Game.create(hand); // const timeoutAt = new Date(Date.now() + game.timeLimit * 1000); // await db.query('UPDATE games SET log = $1, timeout_at = $2 WHERE id = $3', [hand.actions, timeoutAt, gameId]); } function broadcastToPlayers(gameId: string, game: Poker.Game): void { // TODO: Send sanitized hands to each player // const players = getPlayersInGame(gameId); // for (const playerId of players) { // const sanitizedHand = Poker.Game.export(game, playerId); // websocket.send(playerId, { gameId, hand: sanitizedHand }); // } } /** * Single endpoint for poker game state management * Follows the stateless request-response pattern described in the spec */ app.post('/game/poker', async (req, res) => { try { // Step 1: Receiving - Request body IS the Hand from the client const clientHand: Poker.Hand = req.body; if (!clientHand) { return res.status(400).json({ error: 'Missing hand data' }); } // Step 2: Loading - Load current hand from database const serverHand = loadGameHand(clientHand.id); if (!serverHand) { return res.status(404).json({ error: 'Game not found' }); } // Step 3: Merging - Merge client hand with server hand const mergedHand = Poker.Hand.merge(serverHand, clientHand); // Step 4: Applying - Create game (which applies all actions from the merged Hand) let game = Poker.Game.create(mergedHand); // Check and execute dealer actions if needed (flop, turn, river, showdown) game = Poker.Game.advance(game); // Step 5: Storing - Save updated hand to database const updatedHand = Poker.Game.export(game); saveGameHand(clientHand.id, updatedHand); // Step 6: Sanitizing & Updating - Broadcast sanitized hands to all players broadcastToPlayers(clientHand.id, game); // Return the sanitized hand for the requesting player // not strictly necessary, as typically client will receieve it in the websocket message const responseHand = Poker.Game.export(game, Poker.Game.getAuthorPlayerIndex(game)); res.json(responseHand); } catch (error) { console.error('Error processing poker action:', error); res.status(500).json({ error: 'Internal server error' }); } }); /** * Check for expired game timeouts and apply fold actions * This function should be called periodically (e.g., every second) */ async function checkGameTimeouts(): Promise<void> { const expiredGames = await db.query( 'SELECT id FROM games WHERE timeout_at < NOW() AND timeout_at IS NOT NULL' ); for (const row of expiredGames.rows) { const gameId = row.id; // Load the current game state const hand = loadGameHand(gameId); if (!hand) continue; const game = Poker.Game.create(hand); const activePlayerIndex = Poker.Game.getActivePlayer(game); if (activePlayerIndex !== -1) { // Apply fold action for the timed-out player const foldAction = Poker.Game.act(game, 'fold', activePlayerIndex); const updatedGame = Poker.Game.applyAction(game, foldAction); // Check and execute dealer actions if needed const finalGame = Poker.Game.advance(updatedGame); // Save updated state (which also updates timeout) const updatedHand = Poker.Game.export(finalGame); saveGameHand(gameId, updatedHand); // Broadcast to all players broadcastToPlayers(gameId, finalGame); } } } /** * Start timeout polling - runs every second * This would typically be a separate process/service */ setInterval(() => { checkGameTimeouts(); }, 1000); // Start server const PORT = process.env.PORT || 3000; app.listen(PORT, () => { console.log(`Poker game server running on port ${PORT}`); }); export default app;