From b6a409c5f47da22fcdd33417c5cb0f4a9a86297d Mon Sep 17 00:00:00 2001 From: RAJ <143867566+TheRaj71@users.noreply.github.com> Date: Fri, 4 Oct 2024 22:18:41 +0530 Subject: [PATCH] AI Opponent added --- js/script.js | 189 ++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 136 insertions(+), 53 deletions(-) diff --git a/js/script.js b/js/script.js index 9a045c2..b5300ac 100644 --- a/js/script.js +++ b/js/script.js @@ -1,12 +1,16 @@ +// DOM Elements const gameBoard = document.getElementById("gameBoard"); const resultElement = document.getElementById("result"); const currentPlayerDisplay = document.getElementById("currentPlayer"); const soundButton = document.getElementById("soundButton"); +const resetButton = document.getElementById("resetButton"); +// Game state let currentPlayer = "X"; let gameIsOver = false; +let isAIMode = false; -//sound-effects" +// Sound effects const backgroundSound = new Audio("sounds/background.wav"); const clickSound = new Audio("sounds/click.wav"); const winSound = new Audio("sounds/win.wav"); @@ -15,7 +19,26 @@ backgroundSound.loop = true; backgroundSound.volume = 0.1; backgroundSound.play(); -soundButton.addEventListener("click", () => { +// Event Listeners +soundButton.addEventListener("click", toggleSound); +resetButton.addEventListener("click", resetGame); + +// Add mode selection +const modeSelect = document.createElement("select"); +modeSelect.id = "modeSelect"; +const multiplayerOption = document.createElement("option"); +multiplayerOption.value = "multiplayer"; +multiplayerOption.textContent = "Multiplayer"; +const aiOption = document.createElement("option"); +aiOption.value = "ai"; +aiOption.textContent = "Play against AI"; +modeSelect.appendChild(multiplayerOption); +modeSelect.appendChild(aiOption); +document.body.insertBefore(modeSelect, gameBoard); + +modeSelect.addEventListener("change", changeGameMode); + +function toggleSound() { if (backgroundSound.paused) { backgroundSound.play(); soundButton.textContent = "Sound: On"; @@ -23,96 +46,156 @@ soundButton.addEventListener("click", () => { backgroundSound.pause(); soundButton.textContent = "Sound: Off"; } -}); +} + +function changeGameMode() { + isAIMode = modeSelect.value === "ai"; + resetGame(); +} function createBoard() { + gameBoard.innerHTML = ''; for (let i = 0; i < 9; i++) { const cell = document.createElement("div"); cell.classList.add("cell"); cell.addEventListener("click", handleCellClick); gameBoard.appendChild(cell); } - updateCurrentPlayerDisplay(); // Show the initial player + updateCurrentPlayerDisplay(); } function handleCellClick(event) { - clickSound.play(); + if (gameIsOver || (isAIMode && currentPlayer === "O")) return; + const cell = event.target; - if (!cell.textContent && !gameIsOver) { - cell.textContent = currentPlayer; - - // Add class for styling based on current player - cell.classList.add(currentPlayer.toLowerCase()); - - if (checkWinner()) { - resultElement.textContent = `${currentPlayer} wins!`; - gameIsOver = true; - } else if (isBoardFull()) { - resultElement.textContent = "It's a draw!"; - gameIsOver = true; - } else { - currentPlayer = currentPlayer === "X" ? "O" : "X"; - updateCurrentPlayerDisplay(); // Update display after each turn + if (cell.textContent) return; + + clickSound.play(); + makeMove(cell, currentPlayer); + + if (checkWinner()) { + endGame(`${currentPlayer} wins!`); + } else if (isBoardFull()) { + endGame("It's a draw!"); + } else { + currentPlayer = currentPlayer === "X" ? "O" : "X"; + updateCurrentPlayerDisplay(); + + if (isAIMode && currentPlayer === "O") { + setTimeout(makeAIMove, 500); + } + } +} + +function makeMove(cell, player) { + cell.textContent = player; + cell.classList.add(player.toLowerCase()); +} + +function makeAIMove() { + const bestMove = findBestMove(); + const cell = gameBoard.children[bestMove]; + makeMove(cell, currentPlayer); + + if (checkWinner()) { + endGame(`${currentPlayer} wins!`); + } else if (isBoardFull()) { + endGame("It's a draw!"); + } else { + currentPlayer = "X"; + updateCurrentPlayerDisplay(); + } +} + +function findBestMove() { + let bestScore = -Infinity; + let bestMove; + for (let i = 0; i < 9; i++) { + if (gameBoard.children[i].textContent === "") { + gameBoard.children[i].textContent = "O"; + let score = minimax(gameBoard, 0, false); + gameBoard.children[i].textContent = ""; + if (score > bestScore) { + bestScore = score; + bestMove = i; + } } } + return bestMove; +} + +function minimax(board, depth, isMaximizing) { + if (checkWinner()) { + return isMaximizing ? -1 : 1; + } else if (isBoardFull()) { + return 0; + } + + if (isMaximizing) { + let bestScore = -Infinity; + for (let i = 0; i < 9; i++) { + if (board.children[i].textContent === "") { + board.children[i].textContent = "O"; + let score = minimax(board, depth + 1, false); + board.children[i].textContent = ""; + bestScore = Math.max(score, bestScore); + } + } + return bestScore; + } else { + let bestScore = Infinity; + for (let i = 0; i < 9; i++) { + if (board.children[i].textContent === "") { + board.children[i].textContent = "X"; + let score = minimax(board, depth + 1, true); + board.children[i].textContent = ""; + bestScore = Math.min(score, bestScore); + } + } + return bestScore; + } } function updateCurrentPlayerDisplay() { currentPlayerDisplay.textContent = `Current Player: ${currentPlayer}`; - console.log("Current player:", currentPlayer); } function checkWinner() { const winningCombinations = [ - [0, 1, 2], - [3, 4, 5], - [6, 7, 8], - [0, 3, 6], - [1, 4, 7], - [2, 5, 8], - [0, 4, 8], - [2, 4, 6], + [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 (let combination of winningCombinations) { + const [a, b, c] = combination; if ( - gameBoard.children[combination[0]].textContent === - gameBoard.children[combination[1]].textContent && - gameBoard.children[combination[1]].textContent === - gameBoard.children[combination[2]].textContent && - gameBoard.children[combination[0]].textContent !== "" + gameBoard.children[a].textContent && + gameBoard.children[a].textContent === gameBoard.children[b].textContent && + gameBoard.children[a].textContent === gameBoard.children[c].textContent ) { - winSound.play(); return true; } } - return false; } function isBoardFull() { - for (let i = 0; i < gameBoard.children.length; i++) { - if (gameBoard.children[i].textContent === "") { - return false; - } - } - return true; + return [...gameBoard.children].every(cell => cell.textContent !== ""); +} + +function endGame(message) { + resultElement.textContent = message; + gameIsOver = true; + winSound.play(); } function resetGame() { currentPlayer = "X"; gameIsOver = false; resultElement.textContent = ""; - updateCurrentPlayerDisplay(); // Reset display on game reset - - for (let i = 0; i < gameBoard.children.length; i++) { - gameBoard.children[i].textContent = ""; - gameBoard.children[i].classList.remove("x", "o"); // Remove the classes - } + updateCurrentPlayerDisplay(); + createBoard(); } -// Set up the reset button -const resetButton = document.getElementById("resetButton"); -resetButton.addEventListener("click", resetGame); - -createBoard(); +createBoard(); \ No newline at end of file