井字棋游戏无法结束并提示平局问题求助
问题:井字棋游戏平局判断异常
我开发的井字棋游戏可以正常运行并判定胜负,但无法在无胜者的游戏结束时提示平局。尝试在getWinner()函数中添加平局返回逻辑时,要么游戏仅点击一次就结束,要么平局提示不生效。怀疑是for循环逻辑有问题,但找不到具体原因。
现有代码
JavaScript
/*----- constants -----*/ // 选中格子的背景色:玩家1(1)为粉色+X,玩家2(-1)为浅绿色+O const COLORS = { '0': 'white', '1': 'pink', '-1': 'lightgreen' }; // 选中格子的标记:X或O const MARK = { '0': '', '1': 'X', '-1': 'O' }; // 获胜组合 const COMBOS = [ [0, 1, 2], [3, 4, 5], [6, 7, 8], [6, 4, 2], [0, 4, 8], [0, 3, 6], [1, 4, 7], [2, 5, 8] ]; /*----- 状态变量 -----*/ let board; // 9个格子的数组 let turn; // 当前玩家:1或-1 let winner; // null=无胜者;1/-1=对应玩家获胜;'T'=平局 /*----- 缓存DOM元素 -----*/ const message = document.querySelector('h1'); const resetButton = document.querySelector('button'); /*----- 事件监听 -----*/ document.getElementById('board').addEventListener('click', handleClick); resetButton.addEventListener('click', init); /*----- 函数定义 -----*/ init(); // 初始化状态并渲染页面 function init() { board = [0, 0, 0, 0, 0, 0, 0, 0, 0]; turn = 1; winner = null; render(); } // 将状态可视化到DOM function render() { renderBoard(); renderMessage(); } // 渲染棋盘 function renderBoard() { board.forEach(function(boardVal, boardIdx) { const squareId = `box-${boardIdx}`; const squareEl = document.getElementById(squareId); // 设置玩家选中后的样式 squareEl.style.backgroundColor = COLORS[boardVal]; squareEl.innerHTML = MARK[boardVal]; squareEl.style.display = 'flex'; squareEl.style.justifyContent = 'center'; squareEl.style.alignItems = 'center'; squareEl.style.fontSize = '19vmin'; }); } // 显示当前回合或胜负结果 function renderMessage() { if (winner === 'T') { message.innerHTML = '平局!游戏结束!'; } else if (winner) { message.innerHTML = `玩家${MARK[winner]}获胜!`; } else { message.innerHTML = `玩家${MARK[turn]}的回合`; } } // 处理格子点击事件 function handleClick(event) { const boxIdx = parseInt(event.target.id.replace('box-', '')); // 点击无效区域、格子已被占用或已有胜者时,终止函数 if (isNaN(boxIdx) || board[boxIdx] || winner) return; // 更新棋盘状态为当前玩家标识 board[boxIdx] = turn; // 切换玩家 turn *= -1; // 检查胜负 winner = getWinner(); render(); } // 判断胜负:返回1/-1(胜者)、'T'(平局)、null(游戏继续) // 这里遇到了瓶颈,参考过示例并研究了Math.abs函数,但还是没搞定 function getWinner() { for (let i = 0; i < COMBOS.length; i++) { if (Math.abs(board[COMBOS[i][0]] + board[COMBOS[i][1]] + board[COMBOS[i][2]]) === 3) { return board[COMBOS[i][0]]; } else if (board.includes(null)) { return null; } } // return 'T'; // 启用这行代码后,游戏只点击一次就结束了 }
CSS
* { box-sizing: border-box; } body { height: 100vh; margin: 0; font-family: 'Raleway', sans-serif; display: flex; flex-direction: column; justify-content: center; align-items: center; } header { margin-top: 5vmin; font-size: 10vmin; color: darkslategrey; } h1 { color: slategrey; } #board { display: grid; grid-template-columns: repeat(3, 20vmin); grid-template-rows: repeat(3, 20vmin); } #board>div { border: 0.5vmin solid slategrey; } button { margin-top: 5vmin; margin-bottom: 5vmin; padding: 2vmin; font-size: 3vmin; border-radius: 4vmin; border: 0.5vmin solid lightslategrey; background-color: aliceblue; color: darkslategrey; } button:hover { color: azure; background-color: cadetblue; }
HTML
<link href="https://fonts.googleapis.com/css2?family=Raleway:wght@100&display=swap" rel="stylesheet"> <header>Tic-Tac-Toe</header> <h1>X's Turn</h1> <section id="board"> <div id="box-0"></div> <div id="box-1"></div> <div id="box-2"></div> <div id="box-3"></div> <div id="box-4"></div> <div id="box-5"></div> <div id="box-6"></div> <div id="box-7"></div> <div id="box-8"></div> </section> <button>Reset Match</button>
问题分析与修复
你的getWinner()函数存在两个关键问题:
- 循环内提前终止逻辑错误:遍历赢局组合时,只要第一个组合不满足胜负条件,就执行
else if分支返回null,直接终止函数,导致后续赢局组合无法被检查,游戏会提前判定为无胜者。 - 空格子判断逻辑错误:初始化的
board数组元素是0而非null,所以board.includes(null)永远为false,这行判断完全无效。
修复后的getWinner()函数
function getWinner() { // 先遍历所有赢局组合,检查是否有胜者 for (let i = 0; i < COMBOS.length; i++) { const sum = board[COMBOS[i][0]] + board[COMBOS[i][1]] + board[COMBOS[i][2]]; if (Math.abs(sum) === 3) { return board[COMBOS[i][0]]; } } // 检查棋盘是否已满(无空格子),满了则返回平局 if (!board.includes(0)) { return 'T'; } // 棋盘未满且无胜者,返回null表示游戏继续 return null; }
内容的提问来源于stack exchange,提问作者Lauren Johnson
相关产品推荐
相关产品推荐

