import { cloneState, getValidMoves, applyMove, computePipCount, } from './BackgammonLogic.js'; // Returns an ordered array of moves for the AI (Black) to execute. export function chooseMoves(state) { const sequences = generateSequences(state); if (sequences.length === 0) return []; let best = null; let bestScore = -Infinity; for (const seq of sequences) { const score = evaluateState(seq.finalState, 'black'); if (score > bestScore) { bestScore = score; best = seq; } } return best ? best.moves : []; } function generateSequences(state, depth = 0) { if (depth > 6) return [{ moves: [], finalState: state }]; const validMoves = getValidMoves(state); if (validMoves.length === 0 || state.movesLeft.length === 0) { return [{ moves: [], finalState: state }]; } const results = []; const seenBoards = new Set(); for (const move of validMoves) { const next = applyMove(state, move); // If applyMove ended the turn, no further moves are possible in this sequence const finished = next.currentPlayer !== state.currentPlayer || next.phase !== 'move'; if (finished) { results.push({ moves: [move], finalState: next }); } else { const subSeqs = generateSequences(next, depth + 1); for (const sub of subSeqs) { const key = boardHash(sub.finalState); if (!seenBoards.has(key)) { seenBoards.add(key); results.push({ moves: [move, ...sub.moves], finalState: sub.finalState }); } } } } return results.length > 0 ? results : [{ moves: [], finalState: state }]; } function boardHash(state) { return state.points.map((p) => `${p.color?.[0] ?? '-'}${p.count}`).join('') + `|b${state.bar.black}w${state.bar.white}`; } function evaluateState(state, player) { const opp = player === 'white' ? 'black' : 'white'; let score = 0; // Pip count advantage const ownPips = computePipCount(state, player); const oppPips = computePipCount(state, opp); score += (oppPips - ownPips) * 1.5; // Borne off bonus score += state.borneOff[player] * 25; score -= state.borneOff[opp] * 25; // Opponent checkers on bar (we sent them there) score += state.bar[opp] * 20; // Own blots (lone exposed checkers) for (let i = 0; i < 24; i++) { const pt = state.points[i]; if (pt.color === player && pt.count === 1) score -= 8; if (pt.color === player && pt.count >= 2) { // Home board anchors const inHome = player === 'white' ? (i <= 5) : (i >= 18); if (inHome) score += 10; } } // Prime bonus — runs of 3+ consecutive blocked points let run = 0; for (let i = 0; i < 24; i++) { if (state.points[i].color === player && state.points[i].count >= 2) { run++; if (run >= 3) score += 15; } else { run = 0; } } return score; }