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

React井字棋无法判定胜者及终止游戏问题求助

问题修复方案

核心问题分析

你的两个问题(获胜无日志、获胜后游戏未终止)源于两处关键逻辑错误:

1. calculateWinner 函数循环逻辑错误

函数在检查第一个获胜组合不满足时就直接返回null,导致后续所有获胜组合都没有被检查的机会。比如当获胜组合是对角线[0,4,8]时,第一个横向组合[0,1,2]不满足,函数直接返回null,永远无法识别真正的赢家。

修复后的calculateWinner函数:

function calculateWinner(cells) {
  const winningCombo = [
    [0, 1, 2],
    [3, 4, 5],
    [6, 7, 8],
    [0, 3, 6],
    [1, 4, 7],
    [2, 5, 8],
    [0, 4, 8],
    [2, 4, 6],
  ];

  for (let i = 0; i < winningCombo.length; i++) {
    const [a, b, c] = winningCombo[i];
    // 简化判断:cells[a]不为null时,再检查三者是否相等
    if (cells[a] && cells[a] === cells[b] && cells[a] === cells[c]) {
      return cells[a];
    }
  }
  // 所有组合检查完毕后才返回null
  return null;
}

2. handleClick 函数使用旧状态判断赢家

修改单元格后,你仍然用未更新的原始cells状态计算赢家,导致无法识别刚产生的获胜组合;同时获胜后仍会切换回合,且后续点击的终止判断因之前的函数错误失效。

修复后的handleClick函数:

function handleClick(i) {
  const copiedCells = cells.slice();
  const currentWinner = calculateWinner(cells);

  // 已有赢家或单元格已被填充,直接终止操作
  if (copiedCells[i] || currentWinner) {
    return;
  }

  copiedCells[i] = xTurn ? 'X' : 'O';
  const newWinner = calculateWinner(copiedCells);

  if (newWinner) {
    console.log(`winner is ${newWinner}`);
  } else {
    console.log(`now, turn is ${xTurn ? 'O' : 'X'}`);
    // 只有未产生赢家时才切换回合
    setXTurn(!xTurn);
  }

  setCells(copiedCells);
}

完整修复代码

import { useState } from 'react';

export default function Board() {
  const [xTurn, setXTurn] = useState(true);
  const [cells, setCells] = useState(Array(9).fill(null));

  function handleClick(i) {
    const copiedCells = cells.slice();
    const currentWinner = calculateWinner(cells);

    if (copiedCells[i] || currentWinner) {
      return;
    }

    copiedCells[i] = xTurn ? 'X' : 'O';
    const newWinner = calculateWinner(copiedCells);

    if (newWinner) {
      console.log(`winner is ${newWinner}`);
    } else {
      console.log(`now, turn is ${xTurn ? 'O' : 'X'}`);
      setXTurn(!xTurn);
    }

    setCells(copiedCells);
  }

  return (
    <div className="container">
      <Cell value={cells[0]} onSquareClick={() => handleClick(0)} />
      <Cell value={cells[1]} onSquareClick={() => handleClick(1)} />
      <Cell value={cells[2]} onSquareClick={() => handleClick(2)} />
      <Cell value={cells[3]} onSquareClick={() => handleClick(3)} />
      <Cell value={cells[4]} onSquareClick={() => handleClick(4)} />
      <Cell value={cells[5]} onSquareClick={() => handleClick(5)} />
      <Cell value={cells[6]} onSquareClick={() => handleClick(6)} />
      <Cell value={cells[7]} onSquareClick={() => handleClick(7)} />
      <Cell value={cells[8]} onSquareClick={() => handleClick(8)} />
    </div>
  );
}

function Cell({ value, onSquareClick }) {
  return (
    <div className="cell" onClick={onSquareClick}>
      {value}
    </div>
  );
}

function calculateWinner(cells) {
  const winningCombo = [
    [0, 1, 2],
    [3, 4, 5],
    [6, 7, 8],
    [0, 3, 6],
    [1, 4, 7],
    [2, 5, 8],
    [0, 4, 8],
    [2, 4, 6],
  ];

  for (let i = 0; i < winningCombo.length; i++) {
    const [a, b, c] = winningCombo[i];
    if (cells[a] && cells[a] === cells[b] && cells[a] === cells[c]) {
      return cells[a];
    }
  }
  return null;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 15:33:17