JavaScript 中的井字游戏

TicTacToe Game in JavaScript

我一直在努力找出为什么我的 TicTacToe 游戏没有按照我想要的方式进行检查。因为我一直在看教程,但仍然无法弄清楚当玩家赢得游戏时正确使函数 winning 运行的逻辑。

这里我尝试将 O 或 X 推入数组,然后 console.log 看看它是什么样子以及为什么获胜条件检查不起作用。

  spaces.push[id];
  console.log(spaces);

我也尝试过其他方法来使程序正确,比如使用预制的获胜条件并通过映射当前数组,但也不起作用...

  const winningCondition = [
    [0, 1, 2],
    [3, 4, 5],
    [6, 7, 8],
    [0, 3, 6],
    [1, 4, 7],
    [2, 5, 8],
    [0, 4, 8],
    [2, 4, 6],
  ];

对于单元格,我在 HTML 中创建了 9 个 div,并在 CSS 中使用了网格系统。

非常感谢您的帮助!以下是 TicTacToe 游戏的 JavaScript 代码:

const winning = (player) => {
  if (spaces[0] === player) {
    if (spaces[1] === player && spaces[2] === player) return true;
    if (spaces[3] === player && spaces[6] === player) return true;
    if (spaces[4] === player && spaces[8] === player) return true;
  }
  if (spaces[8] === player) {
    if (spaces[2] === player && spaces[5] === player) return true;
    if (spaces[6] === player && spaces[7] === player) return true;
  }
  if (spaces[4] === player) {
    if (spaces[1] === player && spaces[7] === player) return true;
    if (spaces[3] === player && spaces[5] === player) return true;
  }
};

看起来棋盘是一个名为spaces 的数组,长度为九。看起来数组的值是 ' ''x''o',表示未被占用或被两个玩家之一占用。

您已经列举了获胜者必须占据的位置。检查获胜的简单函数将迭代该数组。

// assuming spaces is defined here as game state, an array 'x', 'o' or ' '
const winningLines = [
    [0, 1, 2],
    [3, 4, 5],
    [6, 7, 8],
    [0, 3, 6],
    [1, 4, 7],
    [2, 5, 8],
    [0, 4, 8],
    [2, 4, 6],
  ];


// call with 'x' or 'o' representing player
function playerWon(player) {
  const playerOccupiesLine = line => line.every(el => spaces[el] === player);
  return winningLines.some(line => playerOccupiesLine(line);
}

没有理由 spaces.push(id) 将额外的元素添加到数组的末尾,只需将其删除即可。您已经有 spaces[id] = currentPlayer 将当前玩家值写入 spaces.

中所需的位置

我发现的唯一问题是单元格应该有从 0 到 8 的数字,这些数字对应于 spaces 数组中的索引:

0 1 2
3 4 5
6 7 8
<div class="game">
    <div class="cell" id="0"></div>
    <div class="cell" id="1"></div>
    <div class="cell" id="2"></div>
    <div class="cell" id="3"></div>
    <div class="cell" id="4"></div>
    <div class="cell" id="5"></div>
    <div class="cell" id="6"></div>
    <div class="cell" id="7"></div>
    <div class="cell" id="8"></div>
</div>

有 8 个获胜条件(3 行,3 列和 2 对角线)。缺少一个对角线条件:

if (spaces[4] === player) {
    // ...
    if (spaces[2] === player && spaces[6] === player) return true;
}

完整代码如下:

const cells = document.querySelectorAll(".cell");
const playText = document.getElementById("game-text");
const restartBtn = document.getElementById("restart");

const spaces = [];
const OPlayer = "O";
const XPlayer = "X";
let currentPlayer;

function handleClick(e) {
    const id = e.target.id;
    if (!spaces[id]) {
        spaces[id] = currentPlayer;

        console.log('[' + spaces.slice(0, 3) + ']\n[' + spaces.slice(3, 6) + ']\n[' + spaces.slice(6) + ']');
        e.target.innerText = currentPlayer;

        if (playerWon(currentPlayer)) {
            const winningAlert = document.createElement("p");
            winningAlert.setAttribute("id", "winning-text");
            winningAlert.innerText = `${currentPlayer} HAS WON!`;
            playText.appendChild(winningAlert);

            setTimeout(() => {
                restart();
            }, 4000);
            return;
        }
        currentPlayer = currentPlayer === OPlayer ? XPlayer : OPlayer;
    }
}

cells.forEach((cell) => {
    cell.addEventListener("click", handleClick);
});

const playerWon = (player) => {
    if (spaces[0] === player) {
        if (spaces[1] === player && spaces[2] === player) return true;
        if (spaces[3] === player && spaces[6] === player) return true;
        if (spaces[4] === player && spaces[8] === player) return true;
    }
    if (spaces[8] === player) {
        if (spaces[2] === player && spaces[5] === player) return true;
        if (spaces[6] === player && spaces[7] === player) return true;
    }
    if (spaces[4] === player) {
        if (spaces[1] === player && spaces[7] === player) return true;
        if (spaces[3] === player && spaces[5] === player) return true;
        if (spaces[2] === player && spaces[6] === player) return true;
    }
};

const restart = () => {
    spaces.forEach((space, index) => {
        console.log(space);
        spaces[index] = null;
    });
    cells.forEach((cell) => {
        cell.innerText = "";
    });
    playText.innerHTML = `LET'S PLAY!`;
    currentPlayer = OPlayer;
};

restartBtn.addEventListener("click", restart);

restart();
* {
    box-sizing: border-box;
    font-family: Verdana, Geneva, Tahoma, sans-serif;
}

.game-board {
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    margin: 6% 15%;
}

.game {
    display: grid;
    grid-gap: 1px;
    grid-template-columns: repeat(3, 1fr);
}

.btn {
    padding: 15px 18px;
    margin: 30px auto auto auto;
    width: 120px;
    font-size: 18px;
    border-radius: 8px;
    border: none;
    color: white;
    background: green;
    cursor: pointer;
}

.btn:hover {
    transition-duration: 0.3s;
    background-color: red;
    transform: translateY(-5px);
}


.cell {
    width: 150px;
    height: 150px;
    margin: 8px 8px;
    border-radius: 15px;
    background-color: brown;
    text-align: center;
    font-size: 120px;
}

#game-text {
    font-size: 25px;
    font-weight: bold;
    text-transform: uppercase;
    margin: -10px auto 25px auto;
}

#winning-text {
    text-align: center;
    margin-bottom: -20px;
    font-size: 20px;
    color: purple;
}
<section class="game-board">
    <div id="game-text"></div>
    <div class="game">
        <div class="cell" id="0"></div>
        <div class="cell" id="1"></div>
        <div class="cell" id="2"></div>
        <div class="cell" id="3"></div>
        <div class="cell" id="4"></div>
        <div class="cell" id="5"></div>
        <div class="cell" id="6"></div>
        <div class="cell" id="7"></div>
        <div class="cell" id="8"></div>
    </div>
    <button class="btn" id="restart">Restart</button>
</section>