// Bingo AI — opponents auto-daub inside BingoLogic.drawBall, so the only AI // "decision" is the claim race: how long an eligible opponent waits before // shouting BINGO. That delay is the window in which the human can beat them. import { hasCompletedLine } from './BingoLogic.js'; // Non-human seats that currently hold a completed line. export function aiEligibleSeats(state) { return state.players .filter((p) => !p.isHuman && hasCompletedLine(p)) .map((p) => p.seat); } // Suspense delay (ms) before an eligible AI auto-calls Bingo. Jittered around // ~1.5s; sharper (higher-skill) opponents react a touch faster. export function chooseClaimDelayMs(seat, skill = 3) { const base = 1700 - skill * 120; return base + Math.random() * 500; } // When the human forfeits (advances without claiming) and ≥1 AI is eligible, // the fastest reactor wins. Tie-break by lowest seat for determinism. export function pickEarliestAIWinner(state) { const seats = aiEligibleSeats(state); if (seats.length === 0) return null; let best = seats[0]; let bestDelay = chooseClaimDelayMs(best); for (let i = 1; i < seats.length; i++) { const d = chooseClaimDelayMs(seats[i]); if (d < bestDelay) { best = seats[i]; bestDelay = d; } } return best; }