编程新手求助:如何为基础Tic Tac Toe游戏实现AI对手?
为井字棋游戏添加AI对手的修改方案
以下是针对你的基础版井字棋代码,添加AI对手的完整修改步骤和代码:
一、HTML代码(无需修改)
现有HTML结构已满足需求,无需调整:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Tic Tac Toe</title> <link rel="stylesheet" href="style.css"> </head> <body> <div class="container"> <h1>Tic Tac Toe</h1> <div id="board"> <div class="square" id="0"></div> <div class="square" id="1"></div> <div class="square" id="2"></div> <div class="square" id="3"></div> <div class="square" id="4"></div> <div class="square" id="5"></div> <div class="square" id="6"></div> <div class="square" id="7"></div> <div class="square" id="8"></div> </div> <button id="reset">Reset Game</button> <div id="message"></div> </div> <script src="index.js"></script> </body> </html>
二、CSS代码(新增获胜高亮样式)
为了让获胜棋子更醒目,新增.winner类的样式:
.container { text-align: center; } #board { display: flex; flex-wrap: wrap; width: 300px; margin: 0 auto; } .square { width: 90px; height: 90px; background-color: black; margin: 5px; border-radius: 5px; font-size: 50px; display: flex; justify-content: center; align-items: center; cursor: pointer; } .square:hover { background-color: whitesmoke; } .square.X { color: #ff5e5e; } .square.O { color: #0077ff; } /* 新增获胜棋子高亮样式 */ .square.winner { background-color: #f7dc6f; }
三、JavaScript代码(核心AI逻辑添加)
这里使用Minimax算法实现不会输的完美AI,同时保留原有核心逻辑,添加AI落子触发逻辑:
let board = ["", "", "", "", "", "", "", "", ""]; let currentPlayer = "X"; // 玩家控制X,AI控制O let gameOver = false; const winningConditions = [ [0, 1, 2], [3, 4, 5], [6, 7, 8], [0, 3, 6], [1, 4, 7], [2, 5, 8], [0, 4, 8], [2, 4, 6] ]; const squares = document.querySelectorAll(".square"); const resetButton = document.querySelector("#reset"); // 为每个格子添加点击事件 squares.forEach(square => { square.addEventListener("click", handleClick); }); // 重置按钮事件 resetButton.addEventListener("click", resetGame); function handleClick(event) { const square = event.target; const index = square.getAttribute("id"); // 如果格子已被占用或游戏结束,直接返回 if (board[index] !== "" || gameOver) { return; } // 玩家落子 makeMove(index, currentPlayer); // 检查游戏状态 if (checkForWinner(currentPlayer)) { gameOver = true; highlightWinnerSquares(); displayWinner(currentPlayer); return; } if (checkForTieGame()) { gameOver = true; displayTieGame(); return; } // 切换到AI玩家 currentPlayer = "O"; // AI延迟落子,提升用户体验 setTimeout(() => { const aiMove = minimax(board, "O").index; makeMove(aiMove, "O"); // 检查AI是否获胜 if (checkForWinner("O")) { gameOver = true; highlightWinnerSquares(); displayWinner("O"); return; } if (checkForTieGame()) { gameOver = true; displayTieGame(); return; } // 切换回玩家 currentPlayer = "X"; }, 500); } // 落子通用函数 function makeMove(index, player) { board[index] = player; const square = document.getElementById(index); square.classList.add(player); square.innerHTML = player; } // 检查获胜 function checkForWinner(player) { return winningConditions.some(condition => { return condition.every(index => board[index] === player); }); } // 检查平局 function checkForTieGame() { return !board.includes("") && !gameOver; } // 高亮获胜格子 function highlightWinnerSquares() { winningConditions.forEach(condition => { const [a, b, c] = condition; if (board[a] === board[b] && board[b] === board[c] && board[a] !== "") { document.getElementById(a).classList.add("winner"); document.getElementById(b).classList.add("winner"); document.getElementById(c).classList.add("winner"); } }); } // 显示获胜信息 function displayWinner(player) { const message = document.getElementById("message"); message.innerHTML = `${player === "X" ? "你" : "AI"}获胜!`; } // 显示平局信息 function displayTieGame() { const message = document.getElementById("message"); message.innerHTML = "平局!"; } // 重置游戏 function resetGame() { board = ["", "", "", "", "", "", "", "", ""]; currentPlayer = "X"; gameOver = false; squares.forEach(square => { square.classList.remove("X", "O", "winner"); square.innerHTML = ""; }); const message = document.getElementById("message"); message.innerHTML = ""; } // Minimax算法核心:计算最优落子 function minimax(newBoard, player) { const availableSpots = newBoard.map((val, idx) => val === "" ? idx : null).filter(val => val !== null); // 检查终止状态:AI赢、玩家赢、平局 if (checkForWinner("O")) return { score: 10 }; if (checkForWinner("X")) return { score: -10 }; if (availableSpots.length === 0) return { score: 0 }; const moves = []; // 遍历所有空位 for (let i = 0; i < availableSpots.length; i++) { const move = {}; move.index = availableSpots[i]; newBoard[availableSpots[i]] = player; // 递归计算得分 if (player === "O") { const result = minimax(newBoard, "X"); move.score = result.score; } else { const result = minimax(newBoard, "O"); move.score = result.score; } // 回溯,恢复棋盘状态 newBoard[availableSpots[i]] = ""; moves.push(move); } // 选择最优落子 let bestMove; if (player === "O") { let bestScore = -Infinity; moves.forEach(move => { if (move.score > bestScore) { bestScore = move.score; bestMove = move; } }); } else { let bestScore = Infinity; moves.forEach(move => { if (move.score < bestScore) { bestScore = move.score; bestMove = move; } }); } return bestMove; }
关键修改说明
- 角色分配:玩家控制
X先手,AI控制O后手 - Minimax算法:通过递归模拟所有可能的落子情况,计算AI的最优落子,确保AI不会输
- 延迟落子:添加500毫秒延迟,让AI操作更符合人类感知,避免瞬间落子
- 通用落子函数:封装
makeMove函数,减少重复代码 - 状态检查优化:重构获胜和平局检查逻辑,让代码更清晰
内容的提问来源于stack exchange,提问作者L.R
相关产品推荐
相关产品推荐

