五子棋是一种经典的棋类游戏,规则简单,但趣味无穷。在这篇博客中,我们将一步步实现一个可以在网页上玩的五子棋游戏。这个游戏支持两名玩家在同一个设备上交替下棋,并会在某一方获胜时给出提示。
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()函数用于在某个方向上统计连续棋子的数量。