JS实现五子棋完整步骤及功能扩展
更新时间:2025年12月04日 08:17:50 作者:MadeInSQL
五子棋是一种双人对弈的策略型棋类游戏,简单易学,但其策略深度却让玩家乐此不疲,这篇文章主要介绍了JS实现五子棋完整步骤及功能扩展的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下
五子棋规则详解
1. 棋盘与棋子
- 棋盘规格:标准五子棋使用15×15的方格棋盘,共225个交叉点(日文称"目")。棋盘通常为木质或塑料材质,横向标记A-O(或1-15),纵向标记1-15便于定位
- 棋子:双方分别使用黑色(先手)和白色(后手)的圆形扁片棋子,直径约1cm。日本规则中常用双凸面的玻璃棋子,落子时会发出清脆声响
2. 基本规则
开局:
- 黑棋先行(现代竞技规则中通常采用"指定开局"制,即黑方必须在棋盘中心区域完成前三手)
- 传统民间玩法可采用"自由开局",即黑棋第一手可下在任意位置
落子规则:
- 棋子必须放在交叉点上,不得放在方格内
- 落子后不允许移动或取回(除非采用"禁手"规则下的提子)
- 双方交替落子,每次只能下一颗棋子
胜负判定:
- 先形成"五连"(横、竖、斜任意方向的连续五颗同色棋子)者胜
- 若棋盘填满仍未分胜负(极罕见),则判为和棋
- 正式比赛通常采用计时制,超时判负
3. 竞技规则变体
禁手规则(职业比赛采用):
- 三三禁手:黑棋禁止同时形成两个活三
- 四四禁手:黑棋禁止同时形成两个活四
- 长连禁手:黑棋禁止形成六子或以上的连线
- 出现禁手时白方必须立即指出,经裁判确认后白方获胜
交换规则:
- 国际连珠联盟(RIF)标准规则包含"三手交换":
- 黑方下开局前三手(必须包含对称布局)
- 白方有权选择交换颜色或保持原色
- 之后由白方下第四手,黑方提供第五手的多个打点供白方选择
- 国际连珠联盟(RIF)标准规则包含"三手交换":
五手两打:
- 黑方第五手必须提供两个对称的打点
- 白方有权选择保留其中一个,另一个由黑方收回
4. 特殊术语
- 活四:两端无阻挡的四连子,下一步必胜
- 冲四:一端被阻挡的四连子
- 活三:能发展成活四的三连子
- 眠三:一端被阻挡的三连子
- VCF(Victory by Continuous Four):通过连续冲四取胜的战术
5. 应用场景
- 休闲玩法:公园、家庭等场合多采用简单规则,不设禁手
- 网络对战:腾讯、野狐等平台通常提供多种规则选项
- 职业比赛:世界连珠锦标赛、中国全国智力运动会等采用RIF标准规则
- AI研究:作为离散数学和人工智能的研究对象,2016年AlphaGo团队开发的AlphaZero已能完胜人类顶尖选手
6. 注意事项
- 正式比赛禁止使用"影子战术"(模仿棋)
- 黑棋因先手优势,在现代规则中受到多重限制
- 日本"连珠"与欧美"Gomoku"规则存在细微差异,网络对战需提前确认规则版本
游戏概述
五子棋是一种传统的策略型棋类游戏,黑白双方轮流在棋盘上落子,先形成五子连线的一方获胜。下面介绍如何使用JavaScript实现一个简单的五子棋游戏。
实现步骤
1. 创建HTML结构
<!DOCTYPE html>
<html>
<head>
<title>JS五子棋</title>
<style>
#board {
display: grid;
grid-template-columns: repeat(15, 30px);
grid-template-rows: repeat(15, 30px);
gap: 1px;
background-color: #DCB35C;
padding: 10px;
}
.cell {
width: 30px;
height: 30px;
background-color: #DCB35C;
border: 1px solid #000;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
}
.black {
background-color: black;
border-radius: 50%;
}
.white {
background-color: white;
border-radius: 50%;
}
</style>
</head>
<body>
<h1>五子棋游戏</h1>
<div id="board"></div>
<div id="status">当前玩家: 黑棋</div>
</body>
</html>
2. JavaScript核心逻辑
document.addEventListener('DOMContentLoaded', function() {
const boardSize = 15;
const board = document.getElementById('board');
const statusDiv = document.getElementById('status');
let currentPlayer = 'black';
let gameBoard = Array(boardSize).fill().map(() => Array(boardSize).fill(null));
// 初始化棋盘
function initializeBoard() {
for (let i = 0; i < boardSize; i++) {
for (let j = 0; j < boardSize; j++) {
const cell = document.createElement('div');
cell.className = 'cell';
cell.dataset.row = i;
cell.dataset.col = j;
cell.addEventListener('click', handleCellClick);
board.appendChild(cell);
}
}
}
// 处理点击事件
function handleCellClick(event) {
const row = parseInt(event.target.dataset.row);
const col = parseInt(event.target.dataset.col);
// 如果该位置已有棋子,则返回
if (gameBoard[row][col]) return;
// 更新游戏状态
gameBoard[row][col] = currentPlayer;
event.target.classList.add(currentPlayer);
// 检查是否获胜
if (checkWin(row, col)) {
setTimeout(() => {
alert(`${currentPlayer === 'black' ? '黑棋' : '白棋'}获胜!`);
resetGame();
}, 100);
return;
}
// 切换玩家
currentPlayer = currentPlayer === 'black' ? 'white' : 'black';
statusDiv.textContent = `当前玩家: ${currentPlayer === 'black' ? '黑棋' : '白棋'}`;
}
// 检查胜利条件
function checkWin(row, col) {
const directions = [
[0, 1], // 水平
[1, 0], // 垂直
[1, 1], // 对角线
[1, -1] // 反对角线
];
for (const [dx, dy] of directions) {
let count = 1;
// 正向检查
for (let i = 1; i < 5; i++) {
const newRow = row + i * dx;
const newCol = col + i * dy;
if (
newRow >= 0 && newRow < boardSize &&
newCol >= 0 && newCol < boardSize &&
gameBoard[newRow][newCol] === currentPlayer
) {
count++;
} else {
break;
}
}
// 反向检查
for (let i = 1; i < 5; i++) {
const newRow = row - i * dx;
const newCol = col - i * dy;
if (
newRow >= 0 && newRow < boardSize &&
newCol >= 0 && newCol < boardSize &&
gameBoard[newRow][newCol] === currentPlayer
) {
count++;
} else {
break;
}
}
if (count >= 5) return true;
}
return false;
}
// 重置游戏
function resetGame() {
gameBoard = Array(boardSize).fill().map(() => Array(boardSize).fill(null));
currentPlayer = 'black';
statusDiv.textContent = '当前玩家: 黑棋';
const cells = document.querySelectorAll('.cell');
cells.forEach(cell => {
cell.classList.remove('black', 'white');
});
}
initializeBoard();
});
功能扩展与实现原理详解
功能扩展
悔棋功能
- 实现一个"悔棋"按钮,点击后可以撤销上一步的落子操作
- 需要维护一个落子历史栈,存储每一步的落子位置和玩家信息
- 撤销时从栈中弹出最近一步,恢复棋盘对应位置为空
- 示例代码逻辑:
function undoMove() { if (moveHistory.length > 0) { const lastMove = moveHistory.pop(); board[lastMove.row][lastMove.col] = EMPTY; currentPlayer = lastMove.player; updateBoardUI(); } }
游戏计时
- 为黑白双方分别添加倒计时计时器(如每人15分钟)
- 使用
setInterval每秒更新计时器显示 - 当某方时间耗尽时自动判负
- 计时器暂停/恢复逻辑:
- 开始对方回合时暂停本方计时器
- 对方落子后启动本方计时器
AI对战
- 实现简单AI算法:
- 优先在己方四连两端落子形成五连
- 其次阻挡对方四连
- 然后寻找己方可形成活三的位置
- 随机选择空位作为最后策略
- 使用评估函数给每个空位打分,选择最高分位置落子
保存游戏
- 使用
localStorage保存游戏状态:function saveGame() { const gameState = { board: board, currentPlayer: currentPlayer, moveHistory: moveHistory }; localStorage.setItem('gomokuGame', JSON.stringify(gameState)); } - 加载时解析存储的JSON数据恢复游戏
音效增强
- 预加载落子音效和胜利音效文件
- 落子时播放"click"音效
- 胜利时播放"victory"音效
- 示例:
function playSound(type) { const audio = new Audio(`sounds/${type}.mp3`); audio.play(); }
实现原理说明
棋盘表示
- 使用15×15二维数组表示棋盘:
const board = Array(15).fill().map(() => Array(15).fill(0)); // 0表示空位,1表示黑子,2表示白子
- 每个数组元素对应棋盘交叉点状态
胜利检测
- 从当前落子点向四个方向检查:
- 水平方向(左右)
- 垂直方向(上下)
- 主对角线(左上到右下)
- 副对角线(右上到左下)
- 检查算法示例:
function checkWin(row, col) { const directions = [ [0, 1], [1, 0], [1, 1], [1, -1] // 四个方向向量 ]; for (const [dx, dy] of directions) { let count = 1; // 正向检查 for (let i = 1; i < 5; i++) { const newRow = row + dx * i; const newCol = col + dy * i; if (!isValidPosition(newRow, newCol) || board[newRow][newCol] !== board[row][col]) { break; } count++; } // 反向检查 for (let i = 1; i < 5; i++) { const newRow = row - dx * i; const newCol = col - dy * i; if (!isValidPosition(newRow, newCol) || board[newRow][newCol] !== board[row][col]) { break; } count++; } if (count >= 5) return true; } return false; }
玩家切换
- 使用变量记录当前玩家:
let currentPlayer = BLACK; // 1表示黑方,2表示白方
- 每次落子后切换玩家:
function switchPlayer() { currentPlayer = currentPlayer === BLACK ? WHITE : BLACK; updatePlayerIndicator(); }
UI更新
- 通过CSS类显示棋子:
.cell.black { background: black; } .cell.white { background: white; border: 1px solid #333; } - JavaScript动态添加类:
function updateBoardUI() { for (let row = 0; row < 15; row++) { for (let col = 0; col < 15; col++) { const cell = document.getElementById(`cell-${row}-${col}`); cell.className = 'cell'; if (board[row][col] === BLACK) { cell.classList.add('black'); } else if (board[row][col] === WHITE) { cell.classList.add('white'); } } } }

总结
到此这篇关于JS实现五子棋完整步骤及功能扩展的文章就介绍到这了,更多相关JS实现五子棋内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
相关文章
关于取不到由location.href提交而来的上级页面地址的解决办法
验证上级页面来源取不到由location.href提交而来的页面地址,搜索了一大堆没有合适的解决办法,突然想到通过模拟JS点击链接的方法2009-07-07
clipboard.js无需Flash无需依赖任何JS库实现文本复制与剪切
这篇文章主要实现了无需Flash无需依赖任何JS库实现文本复制与剪切,是一款极现代的,不需要flash,不依赖任何其他js库的非常小的插件,叫clipboard.js,感兴趣的小伙伴们可以参考一下2015-10-10


最新评论