document.addEventListener('DOMContentLoaded', () => { // Game state let board = ['', '', '', '', '', '', '', '', '']; let currentPlayer = 'X'; let gameActive = true; let gameMode = 'pvp'; // pvp, pvc, cvc let scores = { x: 0, o: 0, d: 0 }; let theme = 'default'; // DOM elements const cells = document.querySelectorAll('#game-board .cell'); const gameOverlay = document.getElementById('game-overlay'); const gameResult = document.getElementById('game-result'); const playAgainBtn = document.getElementById('play-again-btn'); const xWinsEl = document.getElementById('x-wins'); const oWinsEl = document.getElementById('o-wins'); const drawsEl = document.getElementById('draws'); const gameBoard = document.getElementById('game-board'); // Initialize the game board function initializeBoard() { gameBoard.innerHTML = ''; for (let i = 0; i < 9; i++) { const cell = document.createElement('div'); cell.classList.add('cell', 'flex', 'items-center', 'justify-center', 'text-6xl', 'font-bold', 'bg-white', 'dark:bg-gray-800', 'rounded-lg', 'shadow-md'); cell.dataset.index = i; cell.addEventListener('click', () => handleCellClick(i)); gameBoard.appendChild(cell); } } // Handle cell click function handleCellClick(index) { if (!gameActive || board[index] !== '') return; makeMove(index, currentPlayer); if (gameMode === 'pvc' && currentPlayer === 'O' && gameActive) { setTimeout(() => { const bestMove = findBestMove(); makeMove(bestMove, 'O'); }, 500); } else if (gameMode === 'cvc' && gameActive) { setTimeout(() => { const bestMove = findBestMove(); makeMove(bestMove, currentPlayer); }, 500); } } // Make a move function makeMove(index, player) { board[index] = player; const cell = gameBoard.children[index]; cell.textContent = player; cell.classList.add(player.toLowerCase()); if (checkWin(player)) { endGame(`${player} Wins!`); scores[player.toLowerCase()]++; updateScoreboard(); highlightWinningCells(); return; } if (checkDraw()) { endGame("It's a Draw!"); scores.d++; updateScoreboard(); return; } currentPlayer = currentPlayer === 'X' ? 'O' : 'X'; // If it's computer's turn in pvc mode and player is O if (gameMode === 'pvc' && currentPlayer === 'O' && gameActive) { setTimeout(() => { const bestMove = findBestMove(); makeMove(bestMove, 'O'); }, 500); } } // Check for win function checkWin(player) { const winPatterns = [ [0, 1, 2], [3, 4, 5], [6, 7, 8], // rows [0, 3, 6], [1, 4, 7], [2, 5, 8], // columns [0, 4, 8], [2, 4, 6] // diagonals ]; return winPatterns.some(pattern => { return pattern.every(index => board[index] === player); }); } // Check for draw function checkDraw() { return board.every(cell => cell !== ''); } // End the game function endGame(message) { gameActive = false; gameResult.textContent = message; gameOverlay.classList.remove('hidden'); } // Reset the game function resetGame() { board = ['', '', '', '', '', '', '', '', '']; currentPlayer = 'X'; gameActive = true; gameOverlay.classList.add('hidden'); Array.from(gameBoard.children).forEach(cell => { cell.textContent = ''; cell.classList.remove('x', 'o', 'winning-cell'); }); if (gameMode === 'cvc') { setTimeout(() => { const bestMove = findBestMove(); makeMove(bestMove, 'X'); }, 500); } else if (gameMode === 'pvc' && currentPlayer === 'O') { setTimeout(() => { const bestMove = findBestMove(); makeMove(bestMove, 'O'); }, 500); } } // Update scoreboard function updateScoreboard() { xWinsEl.textContent = scores.x; oWinsEl.textContent = scores.o; drawsEl.textContent = scores.d; } // Highlight winning cells function highlightWinningCells() { const winPatterns = [ [0, 1, 2], [3, 4, 5], [6, 7, 8], // rows [0, 3, 6], [1, 4, 7], [2, 5, 8], // columns [0, 4, 8], [2, 4, 6] // diagonals ]; for (const pattern of winPatterns) { const [a, b, c] = pattern; if (board[a] !== '' && board[a] === board[b] && board[a] === board[c]) { gameBoard.children[a].classList.add('winning-cell'); gameBoard.children[b].classList.add('winning-cell'); gameBoard.children[c].classList.add('winning-cell'); break; } } } // Computer AI - Minimax algorithm function findBestMove() { if (gameMode === 'cvc') { // For computer vs computer, just pick a random empty spot for demo const emptyCells = board.map((cell, index) => cell === '' ? index : null).filter(val => val !== null); return emptyCells[Math.floor(Math.random() * emptyCells.length)]; } // Minimax algorithm for optimal play let bestScore = -Infinity; let bestMove = null; for (let i = 0; i < 9; i++) { if (board[i] === '') { board[i] = 'O'; const score = minimax(board, 0, false); board[i] = ''; if (score > bestScore) { bestScore = score; bestMove = i; } } } return bestMove; } function minimax(board, depth, isMaximizing) { const scores = { 'X': -10, 'O': 10, 'draw': 0 }; if (checkWin('O')) return scores['O'] - depth; if (checkWin('X')) return scores['X'] + depth; if (checkDraw()) return scores['draw']; if (isMaximizing) { let bestScore = -Infinity; for (let i = 0; i < 9; i++) { if (board[i] === '') { board[i] = 'O'; const score = minimax(board, depth + 1, false); board[i] = ''; bestScore = Math.max(score, bestScore); } } return bestScore; } else { let bestScore = Infinity; for (let i = 0; i < 9; i++) { if (board[i] === '') { board[i] = 'X'; const score = minimax(board, depth + 1, true); board[i] = ''; bestScore = Math.min(score, bestScore); } } return bestScore; } } // Event listeners playAgainBtn.addEventListener('click', resetGame); // Theme change handler document.addEventListener('theme-change', (e) => { theme = e.detail.theme; applyTheme(); }); // Game mode change handler document.addEventListener('game-mode-change', (e) => { gameMode = e.detail.mode; resetGame(); }); // Apply theme function applyTheme() { // Remove all theme classes first const themeClasses = Array.from(document.body.classList).filter(cls => cls.startsWith('theme-')); themeClasses.forEach(cls => document.body.classList.remove(cls)); // Add the current theme class document.body.classList.add(`theme-${theme}`); // Update CSS variables document.documentElement.style.setProperty('--primary-color', getComputedStyle(document.body).getPropertyValue('--primary-color')); document.documentElement.style.setProperty('--secondary-color', getComputedStyle(document.body).getPropertyValue('--secondary-color')); // Update cell colors document.querySelectorAll('.cell.x').forEach(cell => { cell.style.color = `var(--primary-color)`; }); document.querySelectorAll('.cell.o').forEach(cell => { cell.style.color = `var(--secondary-color)`; }); } // Initialize initializeBoard(); applyTheme(); });