'use strict'; const boardDiv = document.getElementById('board'); const statusDiv = document.getElementById('status'); const restartBtn = document.getElementById('restart-btn'); const firstPlayerSelect = document.getElementById('first-player'); const scoreXSpan = document.getElementById('score-x'); const scoreOSpan = document.getElementById('score-o'); const scoreDrawSpan = document.getElementById('score-d'); const WIN_COMBOS = [ [0, 1, 2], [3, 4, 5], [6, 7, 8], // Filas [0, 3, 6], [1, 4, 7], [2, 5, 8], // Columnas [0, 4, 8], [2, 4, 6] // Diagonales ]; let board = Array(9).fill(''); let currentPlayer = 'X'; let gameOver = false; let scores = { X: 0, O: 0, D: 0 }; function loadScores() { try { const raw = localStorage.getItem('ttt_scores'); if (raw) { const parsed = JSON.parse(raw); if (parsed && typeof parsed === 'object') { scores.X = Number(parsed.X) || 0; scores.O = Number(parsed.O) || 0; scores.D = Number(parsed.D) || 0; } } } catch (_) { // Ignorar errores de parsing o acceso } } function saveScores() { try { localStorage.setItem('ttt_scores', JSON.stringify(scores)); } catch (_) { // Ignorar errores de almacenamiento } } function updateScoreUI() { if (scoreXSpan) scoreXSpan.textContent = String(scores.X); if (scoreOSpan) scoreOSpan.textContent = String(scores.O); if (scoreDrawSpan) scoreDrawSpan.textContent = String(scores.D); } function initBoardDom() { // Crear la cuadrícula de 3x3 solo si no existe if (boardDiv.children.length === 9) { // limpiar estado de clases win previas Array.from(boardDiv.children).forEach(c => c.classList.remove('win')); return; } boardDiv.textContent = ''; for (let idx = 0; idx < 9; idx++) { const cell = document.createElement('button'); cell.type = 'button'; cell.className = 'cell'; cell.setAttribute('data-idx', String(idx)); cell.setAttribute('aria-label', `Casilla ${idx + 1}`); cell.setAttribute('role', 'gridcell'); cell.addEventListener('click', onCellClick); cell.addEventListener('keydown', (e) => { if (e.key === 'Enter' || e.key === ' ') onCellClick(e); }); boardDiv.appendChild(cell); } boardDiv.setAttribute('aria-disabled', 'false'); } function render() { for (let i = 0; i < 9; i++) { const cellEl = boardDiv.children[i]; if (!cellEl) continue; cellEl.textContent = board[i]; } } function setStatus(msg) { statusDiv.textContent = msg; } function checkWinner(player) { for (const combo of WIN_COMBOS) { const [a, b, c] = combo; if (board[a] === player && board[b] === player && board[c] === player) { return { win: true, combo }; } } return { win: false, combo: null }; } function highlightCombo(combo) { if (!combo) return; combo.forEach(i => { const el = boardDiv.children[i]; if (el) el.classList.add('win'); }); } function endGame(result, combo) { gameOver = true; boardDiv.setAttribute('aria-disabled', 'true'); if (result === 'X' || result === 'O') { setStatus(`¡${result} gana! 🎉`); scores[result] += 1; highlightCombo(combo); } else { setStatus('¡Empate!'); scores.D += 1; } updateScoreUI(); saveScores(); } function onCellClick(e) { const target = e.currentTarget; const idx = Number(target.getAttribute('data-idx')); if (gameOver || !Number.isInteger(idx)) return; if (board[idx] !== '') return; board[idx] = currentPlayer; render(); const { win, combo } = checkWinner(currentPlayer); if (win) { endGame(currentPlayer, combo); return; } // Comprueba empate if (board.every(cell => cell !== '')) { endGame('D', null); return; } // Cambiar turno currentPlayer = currentPlayer === 'X' ? 'O' : 'X'; setStatus(`Turno de ${currentPlayer}`); } function startGame() { board = Array(9).fill(''); gameOver = false; // Determinar primer jugador desde el selector si existe if (firstPlayerSelect && (firstPlayerSelect.value === 'X' || firstPlayerSelect.value === 'O')) { currentPlayer = firstPlayerSelect.value; } else { currentPlayer = 'X'; } boardDiv.setAttribute('aria-disabled', 'false'); initBoardDom(); // Remover cualquier resaltado previo Array.from(boardDiv.children).forEach(c => c.classList.remove('win')); render(); setStatus(`Turno de ${currentPlayer}`); } // Listeners restartBtn.addEventListener('click', startGame); if (firstPlayerSelect) { firstPlayerSelect.addEventListener('change', () => { // Solo afecta si la partida no ha empezado o si no ha terminado aún if (!gameOver && board.every(v => v === '')) { currentPlayer = firstPlayerSelect.value; setStatus(`Turno de ${currentPlayer}`); } }); } // Init loadScores(); updateScoreUI(); startGame();