document.addEventListener('DOMContentLoaded', function() { const playNowButton = document.querySelector('.btn-primary'); if (playNowButton) { playNowButton.addEventListener('click', function(e) { e.preventDefault(); document.querySelector('#game-section').scrollIntoView({ behavior: 'smooth' }); }); } const gameBoard = document.getElementById('game-board'); const resetButton = document.getElementById('reset-button'); const gameStatus = document.getElementById('game-status'); const boardSizeSelect = document.getElementById('board-size-select'); const aiDifficultySelect = document.getElementById('ai-difficulty-select'); const WIN_CONDITION = 4; const PLAYER_SYMBOL = '🐾'; const AI_SYMBOL = '🧶'; let BOARD_SIZE = 5; let boardState; let currentPlayer; let gameActive; let cells; function createBoard(size) { BOARD_SIZE = size; gameBoard.innerHTML = ''; gameBoard.className = 'game-board'; gameBoard.classList.add(`size-${size}`); gameBoard.style.gridTemplateColumns = `repeat(${size}, 1fr)`; gameBoard.style.gridTemplateRows = `repeat(${size}, 1fr)`; cells = []; for (let i = 0; i < size * size; i++) { const cell = document.createElement('div'); cell.classList.add('game-cell'); const row = Math.floor(i / BOARD_SIZE); const col = i % BOARD_SIZE; cell.addEventListener('click', () => handleCellClick(row, col)); gameBoard.appendChild(cell); cells.push(cell); } } function handleCellClick(row, col) { if (!gameActive || boardState[row][col] !== null || currentPlayer !== 'PLAYER') { return; } boardState[row][col] = 'PLAYER'; renderBoard(); if (checkWin('PLAYER')) { endGame('Player'); return; } if (isDraw()) { endGame('Draw'); return; } currentPlayer = 'AI'; updateStatus("AI's turn..."); setTimeout(makeAIMove, 500); } function makeAIMove() { if (!gameActive) return; const difficulty = aiDifficultySelect.value; let move; if (difficulty === 'easy') { move = findRandomMove(); } else if (difficulty === 'medium') { move = findBestMoveMedium(); } else { // Hard move = findBestMoveHard(); } if (move) { boardState[move.row][move.col] = 'AI'; renderBoard(); if (checkWin('AI')) { endGame('AI'); return; } if (isDraw()) { endGame('Draw'); return; } } currentPlayer = 'PLAYER'; updateStatus("Your turn!"); } function findRandomMove() { let availableCells = []; for (let i = 0; i < BOARD_SIZE; i++) { for (let j = 0; j < BOARD_SIZE; j++) { if (boardState[i][j] === null) { availableCells.push({ row: i, col: j }); } } } if (availableCells.length > 0) { return availableCells[Math.floor(Math.random() * availableCells.length)]; } return null; } function findBestMoveMedium() { // 1. Check if AI can win for (let i = 0; i < BOARD_SIZE; i++) { for (let j = 0; j < BOARD_SIZE; j++) { if (boardState[i][j] === null) { boardState[i][j] = 'AI'; if (checkWin('AI')) { boardState[i][j] = null; // Reset return { row: i, col: j }; } boardState[i][j] = null; // Reset } } } // 2. Check if Player is about to win and block for (let i = 0; i < BOARD_SIZE; i++) { for (let j = 0; j < BOARD_SIZE; j++) { if (boardState[i][j] === null) { boardState[i][j] = 'PLAYER'; if (checkWin('PLAYER')) { boardState[i][j] = null; // Reset return { row: i, col: j }; } boardState[i][j] = null; // Reset } } } // 3. Otherwise, make a random move return findRandomMove(); } function findBestMoveHard() { let bestScore = -Infinity; let move = null; for (let i = 0; i < BOARD_SIZE; i++) { for (let j = 0; j < BOARD_SIZE; j++) { if (boardState[i][j] === null) { boardState[i][j] = 'AI'; let score = evaluateBoard(); boardState[i][j] = null; if (score > bestScore) { bestScore = score; move = { row: i, col: j }; } } } } return move || findRandomMove(); // Fallback to random if no good move } function evaluateBoard() { let score = 0; // Prioritize winning moves if (checkWin('AI')) return 10000; // Prioritize blocking player's winning moves if (checkWin('PLAYER')) return -9000; // Evaluate lines for potential score += evaluateLinesForPlayer('AI'); score -= evaluateLinesForPlayer('PLAYER'); return score; } function evaluateLinesForPlayer(player) { let score = 0; const symbol = player; for (let i = 0; i < BOARD_SIZE; i++) { for (let j = 0; j < BOARD_SIZE; j++) { // Horizontal if (j + WIN_CONDITION <= BOARD_SIZE) { score += evaluateLine(i, j, 0, 1, symbol); } // Vertical if (i + WIN_CONDITION <= BOARD_SIZE) { score += evaluateLine(i, j, 1, 0, symbol); } // Diagonal (down-right) if (i + WIN_CONDITION <= BOARD_SIZE && j + WIN_CONDITION <= BOARD_SIZE) { score += evaluateLine(i, j, 1, 1, symbol); } // Diagonal (down-left) if (i + WIN_CONDITION <= BOARD_SIZE && j - WIN_CONDITION + 1 >= 0) { score += evaluateLine(i, j, 1, -1, symbol); } } } return score; } function evaluateLine(row, col, dr, dc, player) { let playerCount = 0; let emptyCount = 0; for (let k = 0; k < WIN_CONDITION; k++) { const current = boardState[row + k * dr][col + k * dc]; if (current === player) { playerCount++; } else if (current === null) { emptyCount++; } } // If the line is blocked by the opponent, it has no potential. if (playerCount + emptyCount < WIN_CONDITION) { return 0; } // Assign scores based on the number of pieces in a line if (playerCount === 3 && emptyCount === 1) return 100; if (playerCount === 2 && emptyCount === 2) return 10; if (playerCount === 1 && emptyCount === 3) return 1; return 0; } function checkWin(player) { const symbol = player; for (let i = 0; i < BOARD_SIZE; i++) { for (let j = 0; j < BOARD_SIZE; j++) { // Horizontal if (j + WIN_CONDITION <= BOARD_SIZE) { let count = 0; for (let k = 0; k < WIN_CONDITION; k++) { if (boardState[i][j + k] === symbol) count++; } if (count === WIN_CONDITION) return true; } // Vertical if (i + WIN_CONDITION <= BOARD_SIZE) { let count = 0; for (let k = 0; k < WIN_CONDITION; k++) { if (boardState[i + k][j] === symbol) count++; } if (count === WIN_CONDITION) return true; } // Diagonal (down-right) if (i + WIN_CONDITION <= BOARD_SIZE && j + WIN_CONDITION <= BOARD_SIZE) { let count = 0; for (let k = 0; k < WIN_CONDITION; k++) { if (boardState[i + k][j + k] === symbol) count++; } if (count === WIN_CONDITION) return true; } // Diagonal (down-left) if (i + WIN_CONDITION <= BOARD_SIZE && j - WIN_CONDITION + 1 >= 0) { let count = 0; for (let k = 0; k < WIN_CONDITION; k++) { if (boardState[i + k][j - k] === symbol) count++; } if (count === WIN_CONDITION) return true; } } } return false; } function isDraw() { return boardState.every(row => row.every(cell => cell !== null)); } function endGame(winner) { gameActive = false; if (winner === 'Draw') { updateStatus("It's a draw!"); } else { updateStatus(`${winner} wins!`); } } function resetGame() { const size = parseInt(boardSizeSelect.value); createBoard(size); boardState = Array(BOARD_SIZE).fill(null).map(() => Array(BOARD_SIZE).fill(null)); currentPlayer = 'PLAYER'; gameActive = true; renderBoard(); updateStatus("Your turn!"); } function renderBoard() { cells.forEach((cell, index) => { const row = Math.floor(index / BOARD_SIZE); const col = index % BOARD_SIZE; const state = boardState[row][col]; if (state === 'PLAYER') { cell.innerHTML = `
Could not load cat pictures. Meow-be later?
'; }); } });