一、需要实现的功能
五子棋是一种策略棋型游戏,它是在棋盘上排列成连续的五个棋子(横向、纵向或对角线),即赢得比赛。
二、需求功能细化
1、五子棋棋盘
棋盘是一个15x15的方格网格,共有225个点。玩家可以在这些点上放置自己的棋子。
2、游戏目标
玩家需要先于对手,在棋盘上形成连续的五个棋子(横向、纵向或对角线),即获得胜利。
3、游戏流程
玩家与电脑(或其他玩家)轮流进行下棋,玩家先手。玩家可以通过点击棋盘上的点来放置自己的棋子。电脑(或其他玩家)也会在空闲的点上进行下棋操作。每一步棋之后,都会检查是否有玩家获胜或者游戏结束。
4、获胜条件
如果玩家(或电脑)在横向、纵向或对角线上形成连续的五个棋子(即五子连珠),即可获得胜利。如果棋盘填满且没有玩家获胜,则宣布游戏为平局。
5、再来一局
在游戏结束后,玩家可以选择重新开始一局,棋盘会被清空,双方重新开始对决。
三、H5页面设计
我们创建一个命名为 gobang.html 的文件通过编辑器(我用的EditPlus)打开。使用<!DOCTYPE>声明HTML文档类型,确保浏览器以正确的方式渲染网页内容。同时,设置UTF-8编码,以确保浏览器能够正确地解析和显示中文字符。
以下是五子棋游戏的DOM结构了。
<body>
<h1>五子棋游戏</h1>
<div class="board"></div>
<div class="message"></div>
<button class="reset-button">重新开始</button>
</body>
<h1>五子棋游戏</h1>:标题,使用h1标签,用于显示游戏的名称或标题,让玩家知道这是一个拼图游戏。
<div class="board">:一个具有board类的<div>元素,用于承载五子棋的棋盘。
<div class="message">:一个具有message类的<div>元素,用于显示游戏中的消息或提示。
<button class="reset-button">重新开始</button>:一个具有reset-button类的<button>元素,用于重新开始游戏。
以上是五子棋游戏的基本页面结构,其中棋盘、消息和重新开始按钮是游戏的主要组成部分。
四、CSS样式设置
上面html已经准备好了,下面我们简单的来配置一下样式吧。
<style>
.board {
display: grid;
grid-template-columns: repeat(15, 40px);
grid-template-rows: repeat(15, 40px);
gap: 1px;
background-color: #aaa;
margin-bottom: 20px;
}
.cell {
background-color: #eee;
border: 1px solid #ccc;
}
.cell:hover {
background-color: #ddd;
}
.piece {
width: 36px;
height: 36px;
border-radius: 50%;
margin: 2px;
}
.black-piece {
background-color: #000;
}
.white-piece {
background-color: #fff;
}
.message {
font-weight: bold;
}
.reset-button {
margin-top: 10px;
}
</style>
.board:棋盘容器的样式规则,使用网格布局,设置背景颜色和间距。
.cell:每个棋盘格子的样式规则,设置背景颜色和边框。
.cell:hover:鼠标悬停在格子上时的样式规则,设置背景颜色。
.piece:棋子的样式规则,设置宽度、高度、边框半径和间距。
.black-piece:黑色棋子的样式规则,设置背景颜色。
.white-piece:白色棋子的样式规则,设置背景颜色。
.message:消息文本的样式规则,设置字体粗细。
.reset-button:重新开始按钮的样式规则,设置上方间距。
以上样式规则通过类名的方式应用到HTML元素上,从而实现了五子棋游戏界面的样式和外观。
五、代码逻辑,游戏实现
<script>
document.addEventListener('DOMContentLoaded', () => {
const board = document.querySelector('.board');
const message = document.querySelector('.message');
const resetButton = document.querySelector('.reset-button');
const PlayerType = {
PLAYER: 'player',
COMPUTER: 'computer',
};
let currentPlayer = PlayerType.PLAYER;
let isGameOver = false;
let boardState = [];
function createBoard() {
board.innerHTML = '';
for (let row = 0; row < 15; row++) {
boardState[row] = [];
for (let col = 0; col < 15; col++) {
const cell = document.createElement('div');
cell.classList.add('cell');
cell.dataset.row = row;
cell.dataset.col = col;
cell.addEventListener('click', handleCellClick);
board.appendChild(cell);
boardState[row][col] = '';
}
}
}
function handleCellClick(event) {
if (isGameOver) {
return;
}
const cell = event.target;
const row = parseInt(cell.dataset.row);
const col = parseInt(cell.dataset.col);
if (boardState[row][col] !== '') {
return;
}
placePiece(row, col, currentPlayer);
if (checkWin(row, col)) {
endGame(currentPlayer);
return;
}
switchPlayer();
if (currentPlayer === PlayerType.COMPUTER && !isGameOver) {
makeComputerMove();
}
}
function placePiece(row, col, player) {
const piece = document.createElement('div');
piece.classList.add('piece');
piece.classList.add(player === PlayerType.PLAYER ? 'black-piece' : 'white-piece');
const cell = document.querySelector(`.cell[data-row="${row}"][data-col="${col}"]`);
cell.appendChild(piece);
boardState[row][col] = player;
}
function switchPlayer() {
currentPlayer = currentPlayer === PlayerType.PLAYER ? PlayerType.COMPUTER : PlayerType.PLAYER;
}
function checkWin(row, col) {
const directions = [
[1, 0],
[0, 1],
[1, 1],
[1, -1]
];
const player = boardState[row][col];
for (const direction of directions) {
const [dx, dy] = direction;
let count = 1;
// Check for consecutive pieces in both directions
count += checkDirection(row, col, dx, dy, player);
count += checkDirection(row, col, -dx, -dy, player);
if (count >= 5) {
return true;
}
}
return false;
}
function checkDirection(row, col, dx, dy, player) {
let count = 0;
let newRow = row + dx;
let newCol = col + dy;
while (isValidPosition(newRow, newCol) && boardState[newRow][newCol] === player) {
count++;
newRow += dx;
newCol += dy;
}
return count;
}
function isValidPosition(row, col) {
return row >= 0 && row < 15 && col >= 0 && col < 15;
}
function makeComputerMove() {
// Generate a random move for the computer
let row, col;
do {
row = Math.floor(Math.random() * 15);
col = Math.floor(Math.random() * 15);
} while (boardState[row][col] !== '');
placePiece(row, col, currentPlayer);
if (checkWin(row, col)) {
endGame(currentPlayer);
return;
}
switchPlayer();
}
function endGame(winner) {
isGameOver = true;
message.textContent = winner === PlayerType.PLAYER ? 'You win!' : 'Computer wins!';
}
function resetGame() {
currentPlayer = PlayerType.PLAYER;
isGameOver = false;
boardState = [];
message.textContent = '';
createBoard();
}
resetButton.addEventListener('click', resetGame);
createBoard();
});
</script>
现在解释一下关键部分的代码。
(1)createBoard():创建棋盘函数,用于动态生成一个15x15的棋盘,并为每个格子添加事件监听器。
(2)handleCellClick(event):处理格子点击事件函数,根据当前游戏状态和点击的格子位置判断是否可以下子,并进行相应的处理。
(3)placePiece(row, col, player):下子函数,根据给定的行、列和玩家类型,在指定的格子位置放置对应颜色的棋子,并更新棋盘状态。
(4)switchPlayer():切换玩家函数,用于在玩家下子后切换到另一个玩家。
(5)checkWin(row, col):检查胜利函数,根据当前下子的位置检查是否达到五子连珠的胜利条件。
(6)checkDirection(row, col, dx, dy, player):检查方向函数,根据指定的方向,在当前位置的左右两侧检查是否有连续的同色棋子。
(7)isValidPosition(row, col):验证位置有效性函数,用于判断指定的行和列是否在合法的范围内。
(8)makeComputerMove():电脑下子函数,随机生成电脑下子的位置,并执行下子操作。
(9)endGame(winner):结束游戏函数,当游戏达到胜利条件时,设置游戏结束标志,并显示胜利信息。
(10)resetGame():重新开始游戏函数,用于重置游戏状态,清空棋盘,重新创建棋盘。
(11)resetButton.addEventListener('click', resetGame):绑定重新开始按钮的点击事件监听器。
(12)createBoard():在页面加载完成后,执行创建棋盘的函数,初始化游戏。
每个方法都承担着不同的功能,这些代码一起实现了一个基于DOM操作的五子棋游戏。
六、完整源代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>五子棋游戏</title>
<style>
.board {
display: grid;
grid-template-columns: repeat(15, 40px);
grid-template-rows: repeat(15, 40px);
gap: 1px;
background-color: #aaa;
margin-bottom: 20px;
}
.cell {
background-color: #eee;
border: 1px solid #ccc;
}
.cell:hover {
background-color: #ddd;
}
.piece {
width: 36px;
height: 36px;
border-radius: 50%;
margin: 2px;
}
.black-piece {
background-color: #000;
}
.white-piece {
background-color: #fff;
}
.message {
font-weight: bold;
}
.reset-button {
margin-top: 10px;
}
</style>
</head>
<body>
<div class="board"></div>
<div class="message"></div>
<button class="reset-button">重新开始</button>
</body>
<script>
document.addEventListener('DOMContentLoaded', () => {
const board = document.querySelector('.board');
const message = document.querySelector('.message');
const resetButton = document.querySelector('.reset-button');
const PlayerType = {
PLAYER: 'player',
COMPUTER: 'computer',
};
let currentPlayer = PlayerType.PLAYER;
let isGameOver = false;
let boardState = [];
function createBoard() {
board.innerHTML = '';
for (let row = 0; row < 15; row++) {
boardState[row] = [];
for (let col = 0; col < 15; col++) {
const cell = document.createElement('div');
cell.classList.add('cell');
cell.dataset.row = row;
cell.dataset.col = col;
cell.addEventListener('click', handleCellClick);
board.appendChild(cell);
boardState[row][col] = '';
}
}
}
function handleCellClick(event) {
if (isGameOver) {
return;
}
const cell = event.target;
const row = parseInt(cell.dataset.row);
const col = parseInt(cell.dataset.col);
if (boardState[row][col] !== '') {
return;
}
placePiece(row, col, currentPlayer);
if (checkWin(row, col)) {
endGame(currentPlayer);
return;
}
switchPlayer();
if (currentPlayer === PlayerType.COMPUTER && !isGameOver) {
makeComputerMove();
}
}
function placePiece(row, col, player) {
const piece = document.createElement('div');
piece.classList.add('piece');
piece.classList.add(player === PlayerType.PLAYER ? 'black-piece' : 'white-piece');
const cell = document.querySelector(`.cell[data-row="${row}"][data-col="${col}"]`);
cell.appendChild(piece);
boardState[row][col] = player;
}
function switchPlayer() {
currentPlayer = currentPlayer === PlayerType.PLAYER ? PlayerType.COMPUTER : PlayerType.PLAYER;
}
function checkWin(row, col) {
const directions = [
[1, 0],
[0, 1],
[1, 1],
[1, -1]
];
const player = boardState[row][col];
for (const direction of directions) {
const [dx, dy] = direction;
let count = 1;
// Check for consecutive pieces in both directions
count += checkDirection(row, col, dx, dy, player);
count += checkDirection(row, col, -dx, -dy, player);
if (count >= 5) {
return true;
}
}
return false;
}
function checkDirection(row, col, dx, dy, player) {
let count = 0;
let newRow = row + dx;
let newCol = col + dy;
while (isValidPosition(newRow, newCol) && boardState[newRow][newCol] === player) {
count++;
newRow += dx;
newCol += dy;
}
return count;
}
function isValidPosition(row, col) {
return row >= 0 && row < 15 && col >= 0 && col < 15;
}
function makeComputerMove() {
// Generate a random move for the computer
let row, col;
do {
row = Math.floor(Math.random() * 15);
col = Math.floor(Math.random() * 15);
} while (boardState[row][col] !== '');
placePiece(row, col, currentPlayer);
if (checkWin(row, col)) {
endGame(currentPlayer);
return;
}
switchPlayer();
}
function endGame(winner) {
isGameOver = true;
message.textContent = winner === PlayerType.PLAYER ? 'You win!' : 'Computer wins!';
}
function resetGame() {
currentPlayer = PlayerType.PLAYER;
isGameOver = false;
boardState = [];
message.textContent = '';
createBoard();
}
resetButton.addEventListener('click', resetGame);
createBoard();
});
</script>
</html>
以上是五子棋游戏的完整代码,可以直接复制过去,或者点击五子棋游戏demo链接访问。