<p>用二维数组boardi存状态(0空/1黑/2白),动态生成15×15网格,点击格子时校验空位、落子、切换玩家(currentPlayer = 3 - currentPlayer),仅检查该点横竖正反斜四线各向两端延展4格的连子数,≥5则胜,禁右键拖拽,刷新清盘。</p>

怎么用纯 HTML + CSS + JavaScript 实现可落子的五子棋棋盘
核心是用 <table> 或 flex 布局生成 15×15 网格,每个格子绑定 click 事件,用数组记录落子状态(0空、1黑、2白),不能靠 DOM 查找判断胜负——太慢也容易漏。
推荐用二维数组 board[i][j] 存状态,每次落子后只检查该点所在「横、竖、正斜、反斜」四条线是否连成五子。别遍历全盘,否则 15×15 下每步要查 225 个位置,卡顿明显。
实操建议:
- 用
document.createElement('div')动态生成棋盘比写死<table>更易控制样式和事件委托 - 给每个格子加
data-row和data-col属性,点击时直接读取坐标,避免用getBoundingClientRect()计算位置 - 禁用右键和拖拽:在棋盘容器上加
oncontextmenu="return false"和ondragstart="return false"
JavaScript 判胜逻辑怎么写才不漏判、不误判
常见错误是只检查「从左到右」或「从上到下」单向延伸,结果漏掉跨中点的五连(比如第 3–7 个连续,但检查从第 1 位开始就断了)。正确做法是:以落子点为中心,向两个方向各探 4 格,统计同色连续总数。
立即学习“前端免费学习笔记(深入)”;
例如横线判断:
function checkRow(row, col) {
let count = 1;
// 左
for (let j = col - 1; j >= 0 && board[row][j] === board[row][col]; j--) count++;
// 右
for (let j = col + 1; j < 15 && board[row][j] === board[row][col]; j++) count++;
return count >= 5;
}注意边界必须用 && 短路判断,先校验索引再取值,否则 board[row][-1] 会报 Cannot read property '...' of undefined。
其他方向同理,但别合并成一个函数硬套方向向量——初学者容易把坐标加错,调试困难。
如何让黑棋先手、切换玩家、禁重复落子
用一个变量 currentPlayer 记录当前轮到谁(1 或 2),每次落子成功后立刻翻转:currentPlayer = 3 - currentPlayer(比 === 1 ? 2 : 1 更简洁且不易写反)。
落子前必须检查:if (board[row][col] !== 0) return; —— 这句漏写会导致覆盖、胜负判定失效,是最常被忽略的守门逻辑。
实操细节:
- 落子后立即将对应 DOM 元素设为
disabled或加pointer-events: none,视觉+交互双重锁定 - 显示当前玩家提示时,别用
innerHTML = '轮到黑棋'这种硬编码,改用textContent = currentPlayer === 1 ? '⚫' : '⚪',更轻量也支持无障碍阅读 - 游戏结束(赢/和)后,所有格子应禁止点击,但别删事件监听器——重置时复用更稳
为什么本地双人对弈不要用 localStorage 存棋局
localStorage 是同步阻塞 API,存大数组(如 15×15 的数字矩阵)会明显卡 UI;而且它只能存字符串,每次都要 JSON.stringify/JSON.parse,序列化失败(比如出现 undefined)会导致整个棋局丢失。
真要持久化,只存关键字段:{ board: [1,0,2,...], turn: 1, winner: null },长度控制在 300 字符内。但双人面对面玩,其实根本不需要存——关页面就重开,反而更干净。
最容易被忽略的是:用户按 F5 刷新页面后,内存里的 board 数组全丢,但 DOM 棋子还在。解决方法只有两个:要么刷新即清盘(加 window.onbeforeunload 提示),要么初始化时扫描 DOM 补全数组——后者容易因样式未加载完导致漏读,不推荐。



















