用 HTML、CSS 和 JavaScript 实现五子棋游戏

623 阅读5分钟

五子棋是一种经典的棋类游戏,规则简单,但趣味无穷。在这篇博客中,我们将一步步实现一个可以在网页上玩的五子棋游戏。这个游戏支持两名玩家在同一个设备上交替下棋,并会在某一方获胜时给出提示。

玩一下 体验一下

1. 准备工作

在开始编写代码之前,你需要创建三个文件:

  • index.html: 用于定义网页的结构。
  • style.css: 用于定义页面的样式。
  • script.js: 用于实现游戏的逻辑。

1.1 创建项目结构

创建一个项目文件夹,在其中创建上述三个文件:

gomoku/
├── index.html
├── style.css
└── script.js

2. 实现 HTML 结构

首先,我们需要在 index.html 文件中定义页面的基本结构。这个文件将包含一个标题,一个用于显示棋盘的容器,以及一个用于显示提示信息的区域。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>五子棋</title>
    <link rel="stylesheet" href="style.css"> <!-- 引入CSS文件 -->
</head>
<body>
    <h1>五子棋游戏</h1> <!-- 标题 -->
    <div id="board"></div> <!-- 棋盘容器 -->
    <div id="message"></div> <!-- 提示信息容器 -->
    <script src="script.js"></script> <!-- 引入JavaScript文件 -->
</body>
</html>

在这个文件中,我们使用了一个 div 元素来表示棋盘,另一个 div 元素来显示游戏的提示信息。JavaScript 代码将会动态生成棋盘并处理玩家的操作。

3. 添加样式

接下来,我们在 style.css 文件中添加一些样式,使棋盘看起来更像样。

body {
    display: flex; /* 使用flexbox布局 */
    flex-direction: column; /* 垂直排列 */
    align-items: center; /* 居中对齐 */
    font-family: Arial, sans-serif; /* 设置字体 */
    background-color: #f5f5f5; /* 背景颜色 */
}

#board {
    display: grid; /* 使用网格布局 */
    grid-template-columns: repeat(15, 40px); /* 定义15列,每列宽40px */
    grid-template-rows: repeat(15, 40px); /* 定义15行,每行高40px */
    gap: 2px; /* 每个单元格之间的间距 */
    margin-top: 20px; /* 棋盘与标题的距离 */
}

.cell {
    width: 40px; /* 宽度 */
    height: 40px; /* 高度 */
    background-color: #e0e0e0; /* 背景颜色 */
    border: 1px solid #9e9e9e; /* 边框颜色 */
    display: flex; /* 使用flexbox布局 */
    align-items: center; /* 垂直居中 */
    justify-content: center; /* 水平居中 */
    font-size: 24px; /* 字体大小 */
    cursor: pointer; /* 鼠标悬停时显示为手形 */
}

#message {
    margin-top: 20px; /* 与棋盘的距离 */
    font-size: 18px; /* 字体大小 */
    color: #333; /* 字体颜色 */
}

3.1 样式说明

  • body 样式定义了页面的基本布局,使其内容居中对齐,并设置了背景颜色。
  • #board 样式使用 CSS Grid 来创建一个 15x15 的棋盘布局。
  • .cell 样式为每个棋盘格子定义了大小、颜色、边框以及居中显示内容的样式。
  • #message 样式定义了用于显示游戏状态信息的区域。

4. 实现游戏逻辑

最后,我们在 script.js 文件中编写游戏的核心逻辑。这个文件将初始化棋盘,处理玩家的点击操作,并检测是否有玩家获胜。

const SIZE = 15; // 定义棋盘的大小
const board = []; // 初始化棋盘数组
let current_player = 'X'; // 当前玩家,默认是 'X'
let game_over = false; // 标记游戏是否结束

// 初始化棋盘函数
function init_board() {
    const board_element = document.getElementById('board'); // 获取棋盘容器
    board_element.innerHTML = ''; // 清空容器内容

    for (let i = 0; i < SIZE; i++) { // 循环创建棋盘行
        board[i] = []; // 初始化每一行的数组
        for (let j = 0; j < SIZE; j++) { // 循环创建棋盘列
            board[i][j] = ''; // 初始化每个格子的内容为空

            const cell = document.createElement('div'); // 创建格子元素
            cell.className = 'cell'; // 设置格子样式
            cell.dataset.row = i; // 存储格子的行坐标
            cell.dataset.col = j; // 存储格子的列坐标
            cell.addEventListener('click', handle_move); // 绑定点击事件
            board_element.appendChild(cell); // 将格子添加到棋盘
        }
    }
}

// 处理玩家点击格子的逻辑
function handle_move(event) {
    if (game_over) return; // 如果游戏结束,点击无效

    const row = event.target.dataset.row; // 获取点击的格子的行坐标
    const col = event.target.dataset.col; // 获取点击的格子的列坐标

    if (board[row][col] !== '') return; // 如果格子不为空,点击无效

    board[row][col] = current_player; // 在棋盘数组中记录当前玩家的棋子
    event.target.textContent = current_player; // 显示当前玩家的棋子

    if (check_win(row, col)) { // 检查当前玩家是否获胜
        document.getElementById('message').textContent = `Player ${current_player} wins!`; // 显示获胜信息
        game_over = true; // 标记游戏结束
        return;
    }

    current_player = current_player === 'X' ? 'O' : 'X'; // 切换玩家
}

// 检查当前落子是否导致获胜
function check_win(row, col) {
    const directions = [
        [1, 0], [0, 1], [1, 1], [1, -1] // 定义四个方向,横、竖、对角线、反对角线
    ];

    const player = board[row][col]; // 获取当前玩家的棋子

    for (const [dx, dy] of directions) { // 遍历每个方向
        let count = 1; // 初始化连子数量

        count += count_in_direction(row, col, dx, dy, player); // 统计当前方向的连续棋子数量
        count += count_in_direction(row, col, -dx, -dy, player); // 统计相反方向的连续棋子数量

        if (count >= 5) return true; // 如果连成五子,返回true
    }

    return false; // 没有连成五子,返回false
}

// 统计某个方向上连续棋子的数量
function count_in_direction(row, col, dx, dy, player) {
    let count = 0;

    let x = parseInt(row) + dx; // 移动到下一个格子
    let y = parseInt(col) + dy; // 移动到下一个格子

    while (x >= 0 && x < SIZE && y >= 0 && y < SIZE && board[x][y] === player) { // 检查边界条件和棋子是否相同
        count++; // 计数
        x += dx; // 沿着方向继续移动
        y += dy; // 沿着方向继续移动
    }

    return count; // 返回计数结果
}

// 初始化棋盘
init_board();

4.1 逻辑说明

  • init_board() 函数用于生成一个 15x15 的棋盘,并将每个格子绑定点击事件。
  • handle_move() 函数在玩家点击格子时调用,负责处理玩家落子的逻辑,并检查是否有玩家获胜。
  • check_win() 函数用于判断当前落子是否形成五子连线,如果形成五子连线,游戏结束。
  • count_in_direction() 函数用于在某个方向上统计连续棋子的数量。

最终效果

企业微信截图_316fc7f8-5722-4754-9575-683c7894cebd.png