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

井字棋游戏forEach循环中if/else if逻辑失效问题排查

问题描述

想要实现点击三个指定单元格时触发console.log("game over"),但当前代码中的if语句仅第一个案例生效,后续的||条件和else if分支都无法触发。尝试了两种判断逻辑:

  1. 匹配cellsClicked数组与winningMoves的索引
  2. 判断单元格id是否为指定值(如box-1、box-2等)
    两种方式均只有第一个场景能输出控制台信息,后续操作无响应。相关代码如下:
"use strict";

const gameClock = document.querySelector(".clock");
playerTitle = document.querySelector(".player-title");
const ticTacToeBoard = document.querySelector(".tic-tac-toe-container");
const cells = document.querySelectorAll(".cell");
const startPauseBtn = document.querySelector(".start-btn");
const resetBtn = document.querySelector(".resetBtn");
const cellsClicked = [];
const winningMoves = [
  "box-1",
  "box-2",
  "box-3",
  "box-4",
  "box-5",
  "box-6",
  "box-7",
  "box-8",
  "box-9",
];
let seconds = 0;
let minutes = 0;
let displaySeconds = 0;
let displayMinutes = 0;
let interval = null;
let stopWatchStatus = "stopped";

ticTacToeBoard.classList.add("player-turn");
//functions

const playerMove = () => {
  cells.forEach((cell) => {
     const playerEventListener = () => {
      if (ticTacToeBoard.classList.contains("player-turn")) {
        let currentPlayer = document.createElement("p");
        currentPlayer.classList.add("player-1");
        currentPlayer.innerHTML = "X";
        cell.append(currentPlayer);
        playerTitle.innerHTML = "Player: 2";
        ticTacToeBoard.classList.toggle("player-turn");
        cellsClicked.push(cell.getAttribute("id"));
        if (
          cellsClicked[0] === winningMoves[0] &&
          cellsClicked[1] === winningMoves[1] &&
          cellsClicked[2] === winningMoves[2]
        ) {
          console.log("game over");
        } else if (
          cellsClicked[3] === winningMoves[3] &&
          cellsClicked[4] === winningMoves[4] &&
          cellsClicked[5] === winningMoves[5]
         ) {
          console.log("game over");
        } else if (
          cellsClicked[6] === winningMoves[6] &&
          cellsClicked[7] === winningMoves[7] &&
          cellsClicked[8] === winningMoves[8]
        ) {
          console.log("game over");
        } else {
          console.log(false);
          console.log(cellsClicked, winningMoves);
        }
      } else {
        let currentPlayer = document.createElement("p");
        currentPlayer.classList.add("player-2");
        currentPlayer.innerHTML = "O";
        cell.append(currentPlayer);
        playerTitle.innerHTML = "Player: 1";
        ticTacToeBoard.classList.toggle("player-turn");
        if (
          (cell.contains(currentPlayer) &&
            cell.getAttribute("id") === "box-1" &&
            cell.getAttribute("id") === "box-2" &&
            cell.getAttribute("id") === "box-3") ||
          (cell.contains(currentPlayer) &&
            cell.getAttribute("id") === "box-4" &&
            cell.getAttribute("id") === "box-5" &&
            cell.getAttribute("id") === "box-6") ||
           (cell.contains(currentPlayer) &&
            cell.getAttribute("id") === "box-7" &&
            cell.getAttribute("id") === "box-8" &&
            cell.getAttribute("id") === "box-9") ||
          (cell.contains(currentPlayer) &&
            cell.getAttribute("id") === "box-1" &&
            cell.getAttribute("id") === "box-4" &&
            cell.getAttribute("id") === "box-7") ||
          (cell.contains(currentPlayer) &&
            cell.getAttribute("id") === "box-2" &&
            cell.getAttribute("id") === "box-5" &&
            cell.getAttribute("id") === "box-8") ||
          (cell.contains(currentPlayer) &&
            cell.getAttribute("id") === "box-3" &&
            cell.getAttribute("id") === "box-6" &&
            cell.getAttribute("id") === "box-9") ||
          (cell.contains(currentPlayer) &&
            cell.getAttribute("id") === "box-1" &&
            cell.getAttribute("id") === "box-5" &&
            cell.getAttribute("id") === "box-9") ||
           (cell.contains(currentPlayer) &&
            cell.getAttribute("id") === "box-3" &&
            cell.getAttribute("id") === "box-5" &&
            cell.getAttribute("id") === "box-7")
        ) {
           console.log("game over");
         }
      }
    };

    cell.addEventListener("click", playerEventListener, { once: true });
  });
};
const stopWatch = () => {
  seconds++;
  if (seconds / 60 === 1) {
    seconds = 0;
    minutes++;
    if (minutes / 60 === 1) {
      minutes = 0;
    }
  }
  if (seconds < 10) {
    displaySeconds = "0" + seconds.toString();
  } else {
    displaySeconds = seconds;
  }
  if (minutes < 10) {
    displayMinutes = "0" + minutes.toString();
  } else {
    displayMinutes = minutes;
   }
  gameClock.innerHTML = `${displayMinutes}:${displaySeconds}`;
};

const startStop = () => {
  if (stopWatchStatus === "stopped") {
    interval = setInterval(stopWatch, 1000);
    stopWatchStatus = "started";
    startPauseBtn.textContent = "Pause";
  } else {
    clearInterval(interval);
    stopWatchStatus = "stopped";
    startPauseBtn.textContent = "Start Game";
  }
};

const startGame = () => {
  startPauseBtn.addEventListener("click", () => {
    if (startPauseBtn.textContent === "Start Game") {
      startPauseBtn.textContent = "Pause";
      startStop();
     } else if ((startPauseBtn.textContent = "Pause")) {
      startPauseBtn.textContent = "Start Game";
      startStop();
    }
  });
};

startGame();
playerMove();
问题分析

第一种判断逻辑的问题

  1. winningMoves定义错误:应该定义为二维数组,每个子数组代表一组获胜单元格id,而非将所有id放在一维数组中。
  2. 索引匹配逻辑错误:仅检查cellsClicked的固定索引(如0、1、2),但玩家交替点击,获胜组合的单元格id不会恰好出现在这些固定位置,且只有当数组长度足够时,后续的else if才有可能触发,完全不符合井字棋的获胜规则。

第二种判断逻辑的问题

同一个单元格的id不可能同时等于多个值(如cell.getAttribute("id") === "box-1" && cell.getAttribute("id") === "box-2"永远为false),逻辑完全不成立,无法检测到获胜组合。

修复方案
  1. 重新定义所有获胜组合为二维数组winningCombos。
  2. 为两个玩家分别维护已点击的单元格数组,区分不同玩家的操作。
  3. 抽取checkWin函数,统一检查玩家是否达成获胜组合。
  4. 修复点击事件中的逻辑,每次玩家点击后调用checkWin判断是否获胜。

修复后的代码:

"use strict";

const gameClock = document.querySelector(".clock");
let playerTitle = document.querySelector(".player-title");
const ticTacToeBoard = document.querySelector(".tic-tac-toe-container");
const cells = document.querySelectorAll(".cell");
const startPauseBtn = document.querySelector(".start-btn");
const resetBtn = document.querySelector(".resetBtn");
// 分别记录两个玩家的已点击单元格
const player1Cells = [];
const player2Cells = [];
// 定义所有获胜组合
const winningCombos = [
  ["box-1", "box-2", "box-3"],
  ["box-4", "box-5", "box-6"],
  ["box-7", "box-8", "box-9"],
  ["box-1", "box-4", "box-7"],
  ["box-2", "box-5", "box-8"],
  ["box-3", "box-6", "box-9"],
  ["box-1", "box-5", "box-9"],
  ["box-3", "box-5", "box-7"]
];
let seconds = 0;
let minutes = 0;
let displaySeconds = 0;
let displayMinutes = 0;
let interval = null;
let stopWatchStatus = "stopped";

ticTacToeBoard.classList.add("player-turn");

// 检查是否获胜的函数
const checkWin = (playerCells) => {
  return winningCombos.some(combo => {
    return combo.every(cellId => playerCells.includes(cellId));
  });
};

const playerMove = () => {
  cells.forEach((cell) => {
    const playerEventListener = () => {
      const cellId = cell.getAttribute("id");
      if (ticTacToeBoard.classList.contains("player-turn")) {
        // 玩家1操作
        let currentPlayer = document.createElement("p");
        currentPlayer.classList.add("player-1");
        currentPlayer.innerHTML = "X";
        cell.append(currentPlayer);
        playerTitle.innerHTML = "Player: 2";
        ticTacToeBoard.classList.toggle("player-turn");
        player1Cells.push(cellId);
        
        // 检查玩家1是否获胜
        if (checkWin(player1Cells)) {
          console.log("game over - Player 1 wins!");
        }
      } else {
        // 玩家2操作
        let currentPlayer = document.createElement("p");
        currentPlayer.classList.add("player-2");
        currentPlayer.innerHTML = "O";
        cell.append(currentPlayer);
        playerTitle.innerHTML = "Player: 1";
        ticTacToeBoard.classList.toggle("player-turn");
        player2Cells.push(cellId);
        
        // 检查玩家2是否获胜
        if (checkWin(player2Cells)) {
          console.log("game over - Player 2 wins!");
        }
      }
    };

    cell.addEventListener("click", playerEventListener, { once: true });
  });
};

const stopWatch = () => {
  seconds++;
  if (seconds >= 60) {
    seconds = 0;
    minutes++;
    if (minutes >= 60) {
      minutes = 0;
    }
  }
  displaySeconds = seconds < 10 ? `0${seconds}` : seconds;
  displayMinutes = minutes < 10 ? `0${minutes}` : minutes;
  gameClock.innerHTML = `${displayMinutes}:${displaySeconds}`;
};

const startStop = () => {
  if (stopWatchStatus === "stopped") {
    interval = setInterval(stopWatch, 1000);
    stopWatchStatus = "started";
    startPauseBtn.textContent = "Pause";
  } else {
    clearInterval(interval);
    stopWatchStatus = "stopped";
    startPauseBtn.textContent = "Start Game";
  }
};

const startGame = () => {
  startPauseBtn.addEventListener("click", () => {
    if (startPauseBtn.textContent === "Start Game") {
      startPauseBtn.textContent = "Pause";
      startStop();
    } else if (startPauseBtn.textContent === "Pause") {
      startPauseBtn.textContent = "Start Game";
      startStop();
    }
  });
};

startGame();
playerMove();
额外优化点
  • 修复了startGame函数中else if的赋值错误(原代码用了=而非===)。
  • 简化了stopWatch函数中的时间判断逻辑,更清晰可靠。
  • 为playerTitle添加了let声明,符合严格模式要求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 11:15:36