You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React开发井字棋:获胜检测函数无法识别数组值问题求助

井字棋获胜检测失效的问题修复

几个关键问题点

  1. 获胜检查函数提前退出:checkWin里的第一个if,只要当前遍历的赢法组合第一个格子是空,就直接return退出函数了——这会导致比如玩家在最后一行连成三个时,前面的赢法组合里有空格子,函数直接跑路,根本不会检查到后面的获胜情况。
  2. 相等判断逻辑错误:board[a] == board[b] == board[c]这种写法在JS里完全不成立,先判断前两个对象是否相等(对象比的是引用,永远不等),然后拿布尔值和第三个对象对比,结果永远是false,等于白判断。
  3. State更新异步坑:setBoard是异步操作,你刚改完就调用checkWin,拿到的还是旧的board状态,自然检查不到最新的落子。
  4. 回合切换时机错误:你先切换回合再检查获胜,导致控制台打印的获胜玩家是下一个回合的人,完全搞反了。
  5. 对象属性不统一:初始化的board元素是{num: i, value:''},落子时改成{id: cell.id, value: currentTurn},属性名混乱,虽然暂时不影响取value,但容易引发其他潜在bug。

修复后的代码

App.js

import logo from './logo.svg';
import './App.css';
import { useState, useEffect } from 'react';
import Board from './components/Board';

function App() {
  const [board, setBoard] = useState([]);
  const [currentTurn, setCurrentTurn] = useState('');
  const [gameOver, setGameOver] = useState(false);

  function checkWin() {
    if (gameOver) return; // 游戏结束后不再检查
    // 修正原代码错误:[2,4,8]改为[2,5,8],这才是纵向第三列的正确索引
    const winConditions = [
      [0, 3, 6], [1, 4, 7], [2, 5, 8],
      [0, 4, 8], [2, 4, 6],
      [0, 1, 2], [3, 4, 5], [6, 7, 8]
    ];

    for (let j = 0; j < winConditions.length; j++) {
      const [a, b, c] = winConditions[j];
      const valA = board[a]?.value;
      const valB = board[b]?.value;
      const valC = board[c]?.value;

      // 有空格子就跳过当前赢法,不直接退出函数
      if (!valA || !valB || !valC) continue;

      // 正确判断三个格子的value是否相等
      if (valA === valB && valB === valC) {
        setGameOver(true);
        console.log(`Game Over! ${currentTurn} has won`);
        return; // 找到获胜条件后直接退出,无需继续检查
      }
    }
  }

  function populateObject() {
    // 用Array.from简化初始化代码
    const mockarray = Array.from({length:9}, (_,i) => ({num: i, value: ''}));
    setBoard(mockarray);
    setCurrentTurn('x');
    setGameOver(false); // 重置游戏结束状态
  }

  function fillCell(event) {
    if (gameOver) return; // 游戏结束后禁止落子
    const cellIndex = parseInt(event.target.id);
    if (board[cellIndex].value !== '') return; // 已有棋子的格子禁止点击

    // 遵循React immutable原则,创建新数组更新state
    const newBoard = [...board];
    newBoard[cellIndex] = {num: cellIndex, value: currentTurn};
    setBoard(newBoard);
  }

  // 监听board变化,确保用最新状态检查获胜
  useEffect(() => {
    if (board.length === 0) return;
    checkWin();
    // 仅当未获胜且不是初始化状态时,才切换回合
    if (!gameOver && board.some(cell => cell.value !== '')) {
      setCurrentTurn(prev => prev === 'x' ? 'o' : 'x');
    }
  }, [board, gameOver]);

  useEffect(() => {
    populateObject();
  }, []);

  return (
    <div className="App">
      <Board fillFunction={fillCell} currentTurn={currentTurn} valuearray={board} />
      <button onClick={populateObject}>Reset</button>
    </div>
  );
}

export default App;

Board.js(补全key属性,优化渲染逻辑)

import '../stylesheets/board.css'

function Board({valuearray, currentTurn, fillFunction}) {

    const insertSymbol = (value) => {
        switch(value) {
            case 'x':
                return <i className='fa solid fa-x'></i>;
            case 'o' :
                return <i className='fa solid fa-o'></i>;
            default:
                return '';
        }
    }
    
    return(
        <div className="board-section">
            <div className='turn-header'>
             <h4>It is currently {currentTurn}'s turn</h4>
            </div>
            <div className='board'>
                {valuearray.map(v => (
                    <div 
                        className="cell" 
                        key={v.num} // React列表必须添加key属性
                        id={v.num} 
                        onClick={fillFunction}
                    >
                        {insertSymbol(v.value)}                      
                    </div>
                ))}
            </div>
        </div>
    )
}

export default Board;

额外细节说明

  • 修复了原winConditions中的错误索引,确保所有赢法组合正确
  • 添加了游戏结束后禁止落子、已有棋子格子禁止点击的逻辑
  • 用Array.from简化了board初始化代码,更简洁
  • 为Board组件的列表项添加key属性,消除React渲染警告

内容的提问来源于stack exchange,提问作者Kevin H

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 16:40:17