'use strict'; const CpuGame = (() => { const SCORES_KEY = 'ttt-scores'; const CPU_DELAY = 600; const state = { board: Array(9).fill(null), turn: 'X', gameOver: false, scores: { you: 0, opponent: 0, draws: 0 }, }; let cpuTimer = 0; function persistScores() { try { localStorage.setItem(SCORES_KEY, JSON.stringify(state.scores)); } catch (e) { /* storage unavailable */ } } function loadScores() { try { const raw = localStorage.getItem(SCORES_KEY); if (raw) { const s = JSON.parse(raw); state.scores = { you: Number(s.you) || 0, opponent: Number(s.cpu || s.opponent) || 0, draws: Number(s.draws) || 0, }; } } catch (e) { /* corrupted storage */ } } function handleMove(i) { if (state.gameOver || state.turn !== 'X' || state.board[i]) return; state.board[i] = 'X'; App.renderMark(i, 'X'); const result = App.checkWinner(state.board); if (result) { endRound(result); return; } state.turn = 'O'; App.renderStatus('CPU is thinking…', 'thinking'); cpuTimer = setTimeout(cpuMove, CPU_DELAY); } function cpuMove() { if (state.gameOver) return; const empty = []; state.board.forEach((v, i) => { if (v === null) empty.push(i); }); if (!empty.length) return; const i = empty[Math.floor(Math.random() * empty.length)]; state.board[i] = 'O'; App.renderMark(i, 'O'); const result = App.checkWinner(state.board); if (result) { endRound(result); return; } state.turn = 'X'; App.renderStatus('Your turn', 'normal'); } function endRound(result) { state.gameOver = true; let title; let key; if (result.winner === 'X') { key = 'you'; title = 'You Win!'; App.renderStatus('You win!', 'normal'); } else if (result.winner === 'O') { key = 'opponent'; title = 'CPU Wins'; App.renderStatus('CPU wins', 'normal'); document.getElementById('board').classList.add('shake'); } else { key = 'draws'; title = "It's a Draw"; App.renderStatus("It's a draw", 'normal'); document.getElementById('board').classList.add('pulse'); } state.scores[key]++; persistScores(); App.renderScores(state.scores); if (result.line) App.drawWinLine(result.line); setTimeout(() => { App.showOverlay(title); if (result.winner === 'X') App.burstConfetti(); }, result.winner === 'draw' ? 400 : 600); } function newRound() { clearTimeout(cpuTimer); state.board = Array(9).fill(null); state.turn = 'X'; state.gameOver = false; App.clearBoard(); App.renderStatus('Your turn', 'normal'); } function resetScores() { state.scores = { you: 0, opponent: 0, draws: 0 }; persistScores(); App.renderScores(state.scores); App.showToast('Scores reset'); } function destroy() { clearTimeout(cpuTimer); } function init() { clearTimeout(cpuTimer); App.clearBoard(); state.board = Array(9).fill(null); state.turn = 'X'; state.gameOver = false; loadScores(); App.renderScores(state.scores); App.renderStatus('Your turn', 'normal'); } return { init, handleMove, newRound, resetScores, destroy }; })();