构建一个井字棋网页应用

CSSBeginner
立即练习

介绍

在这个项目中,你将学习如何使用 HTML、CSS 和 JavaScript 创建一个井字棋(Tic-Tac-Toe)游戏。井字棋是一款双人游戏,玩家轮流在 3x3 的网格中标记 X 或 O。目标是使自己的标记在水平、垂直或对角线上连成三子。你将逐步创建必要的 HTML、CSS 和 JavaScript 文件,并实现游戏逻辑。

👀 预览

Tic Tac Toe game preview

🎯 任务

在这个项目中,你将学习:

  • 如何使用 HTML 设置井字棋游戏的基本结构。
  • 如何添加 CSS 样式来定义游戏元素的外观。
  • 如何使用 JavaScript 实现游戏逻辑。
  • 如何处理用户交互、检查胜利或平局,以及更新分数。
  • 如何渲染游戏棋盘并更新回合指示器。
  • 如何允许玩家重置游戏并开始新一轮。

🏆 成就

完成本项目后,你将能够:

  • 为网页应用构建 HTML 文件结构。
  • 使用 CSS 类对元素进行样式化。
  • 使用 JavaScript 实现游戏逻辑。
  • 处理用户交互并相应地更新用户界面(UI)。
  • 渲染游戏棋盘并更新回合指示器。
  • 在 JavaScript 中创建事件监听器并处理事件。
这是一个指导性实验,提供分步说明以帮助你学习和实践。请仔细遵循说明完成每一步,以获得实践经验。历史数据显示,这是一个中等难度的实验,完成率为52%。学习者给出了100%的好评率。

创建 HTML 文件

创建一个名为 index.html 的新文件,并将以下代码添加到其中。

cd ~/project
touch index.html

此代码设置了井字棋游戏的基本结构。

<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Tic-Tac-Toe</title>
    <link
      href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css"
      rel="stylesheet"
    />
    <style>
      /* CSS styles for the game */
    </style>
  </head>

  <body>
    <div id="app">
      <h1 class="text-3xl font-bold mb-4 text-gray-900">Tic-Tac-Toe</h1>
      <div id="board" class="grid grid-cols-3 gap-4 mb-4">
        <!-- Game board cells -->
      </div>
      <div id="scoreboard" class="flex justify-between items-center mb-4">
        <!-- Player scores -->
      </div>
      <div
        id="turn-indicator"
        class="text-2xl font-bold mb-4 text-gray-900"
      ></div>
      <button
        id="reset-button"
        class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded"
      >
        Reset Game
      </button>
    </div>

    <script>
      // JavaScript code for the game logic
    </script>
  </body>
</html>
✨ 查看解决方案并练习

添加 CSS 样式

在 HTML 文件 <head> 部分的 <style> 标签内,添加游戏所需的 CSS 样式。这些样式定义了游戏元素(如棋盘、单元格、分数和按钮)的外观。

<style>
  .board-cell {
    width: 100px;
    height: 100px;
  }

  body {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    height: 100vh;
    background-color: #222;
    font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
  }

  #app {
    text-align: center;
    background-color: #f5f5f5;
    border-radius: 8px;
    padding: 24px;
    box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
  }

  h1 {
    font-size: 32px;
    color: #333;
  }

  .text-gray-900 {
    color: #333 !important;
  }

  .text-2xl {
    font-size: 24px;
  }

  .bg-blue-500 {
    background-color: #4267b2;
  }

  .bg-blue-500:hover {
    background-color: #3b5ca0;
  }

  .bg-blue-700 {
    background-color: #385898;
  }

  .text-white {
    color: #fff !important;
  }

  .rounded {
    border-radius: 4px;
  }

  .highlight {
    background-color: #ffed4a;
  }
</style>

你也可以将样式添加到项目中的 style.css 文件,并使用 <link> 标签将其链接到 HTML 文件。

<link rel="stylesheet" href="style.css" />

选择你喜欢的方式即可。

✨ 查看解决方案并练习

添加游戏逻辑 JavaScript 代码

在 HTML 文件末尾 <script> 标签内,添加处理游戏逻辑的 JavaScript 代码。这段代码负责跟踪游戏状态、处理用户交互、检查胜利或平局、更新分数以及渲染游戏棋盘。

<script>
  // Game logic code
</script>
✨ 查看解决方案并练习

初始化游戏变量

在 JavaScript 代码的开头声明必要的变量。这些变量将存储游戏状态、玩家分数和其他相关信息。

// Game logic
const board = ["", "", "", "", "", "", "", "", ""];
let currentPlayer = "X";
let gameEnded = false;
let playerXScore = 0;
let playerOScore = 0;
let winningCells = [];
✨ 查看解决方案并练习

处理单元格点击

创建一个名为 handleCellClick 的函数,当游戏棋盘上的单元格被点击时调用此函数。此函数将处理主要游戏逻辑,例如更新棋盘、检查胜利、更新分数和更改当前玩家。

function handleCellClick(index) {
  if (gameEnded || board[index] !== "") return;
  board[index] = currentPlayer;
  renderBoard();

  if (checkWin()) {
    updateScore();
    highlightWinningCells();
    alert(`Player ${currentPlayer} wins!`);
    gameEnded = true;
  } else if (board.every((cell) => cell !== "")) {
    alert("It's a tie!");
    gameEnded = true;
  } else {
    currentPlayer = currentPlayer === "X" ? "O" : "X";
    updateTurnIndicator();
  }
}
✨ 查看解决方案并练习

检查胜利条件

创建一个名为 checkWin 的函数,用于检查游戏棋盘上是否存在胜利条件。此函数将棋盘上的值与获胜组合进行比较,以确定玩家是否赢得了游戏。

function checkWin() {
  const winningCombinations = [
    [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 < winningCombinations.length; i++) {
    const [a, b, c] = winningCombinations[i];
    if (board[a] !== "" && board[a] === board[b] && board[a] === board[c]) {
      winningCells = [a, b, c];
      return true;
    }
  }
  return false;
}
✨ 查看解决方案并练习

重置游戏

创建一个名为 resetGame 的函数,用于将游戏状态重置为初始值。当点击重置按钮时调用此函数,它会清空棋盘、重置当前玩家、清除获胜单元格、更新回合指示器并渲染棋盘。

function resetGame() {
  board.fill("");
  currentPlayer = "X";
  gameEnded = false;
  winningCells = [];
  updateTurnIndicator();
  renderBoard();
}
✨ 查看解决方案并练习

更新玩家分数

创建一个名为 updateScore 的函数,用于更新玩家的分数。当有玩家获胜时调用此函数。它会增加相应玩家的分数,并更新页面上的分数显示。

function updateScore() {
  if (currentPlayer === "X") {
    playerXScore++;
    document.getElementById("player-x-score").textContent = playerXScore;
  } else {
    playerOScore++;
    document.getElementById("player-o-score").textContent = playerOScore;
  }
}
✨ 查看解决方案并练习

更新回合指示器

创建一个名为 updateTurnIndicator 的函数,用于在页面上更新指示器以显示当前玩家的回合。

function updateTurnIndicator() {
  const turnIndicator = document.getElementById("turn-indicator");
  turnIndicator.textContent = `Current Turn: Player ${currentPlayer}`;
}
✨ 查看解决方案并练习

高亮获胜单元格

创建一个名为 highlightWinningCells 的函数,它向游戏棋盘上的获胜单元格添加一个高亮类。当有玩家获胜时调用此函数。

function highlightWinningCells() {
  const cells = document.querySelectorAll(".board-cell");
  cells.forEach((cell, index) => {
    if (winningCells.includes(index)) {
      cell.classList.add("highlight");
    }
  });
}
✨ 查看解决方案并练习

总结

Summary content missing in import file.

✨ 查看解决方案并练习

Add Event Listeners

Add event listeners to the game board cells and the reset button. These event listeners call the corresponding functions when the events occur.

// Event listeners
const cells = document.querySelectorAll(".board-cell");
cells.forEach((cell, index) => {
  cell.addEventListener("click", () => handleCellClick(index));
});

const resetButton = document.getElementById("reset-button");
resetButton.addEventListener("click", resetGame);
✨ 查看解决方案并练习

Initial Render

At the end of the JavaScript code, add the code for the initial render. This code sets up the initial state of the game, updates the turn indicator, and renders the game board.

// Initial render
updateTurnIndicator();
renderBoard();
✨ 查看解决方案并练习

Run the Project

You can now run the project and play Tic-Tac-Toe!

Click on Go Live button in the bottom right corner of WebIDE, to run the project.

WebIDE Go Live button

This will open the project in Web 8080 Tab.

Web 8080 Tab interface

Click on the cells to make your moves and click the reset button to start a new game.

✨ 查看解决方案并练习

Summary

Congratulations! You have successfully created a Tic-Tac-Toe game using HTML, CSS, and JavaScript. The project covered creating the HTML file, adding CSS styles, implementing the game logic, and handling user interactions. The game allows two players to take turns, checks for a win or a tie, updates scores, and highlights winning cells. You can now run the project and enjoy playing Tic-Tac-Toe!