做前端时间一长,总会在某个时刻冒出个念头:能不能不碰后端、不搭服务器,只靠浏览器里那点 JavaScript,写一个真正能跟人下棋的 AI 象棋程序?这个想法我一直惦记着,后来终于花几个周末把它落地了。
这个“HTML版AI象棋程序”就是一套纯前端实现的中国象棋人机对战网页:页面负责画棋盘、响应鼠标点击、记录行棋规则,AI 则通过搜索算法模拟思考,在当前局面下替电脑方算出一步棋。整个项目零依赖、零构建,一个 HTML 文件加一份脚本就能跑起来,双击就能打开。能做的功能包括:完整象棋规则判断(蹩马腿、塞象眼、将帅照面、兵卒过河等)、玩家执红先行、AI 自动回棋、胜负判定与将军提示。适合想深入理解棋类 AI 原理的前端开发者,也适合拿来当算法课的练手项目。
更让我觉得值得分享的是,这种“纯前端 + 极小极大搜索 + Alpha-Beta 剪枝”的路线,几乎把前端能玩的性能极限都压榨了一遍。接下来我会从整体设计、棋盘渲染、AI 算法、核心代码、踩坑记录五个方向,把这个项目掰开揉碎讲清楚。
1. 项目概述与方案选型
1.1 一句话讲清这个程序到底是什么
所谓 HTML 版 AI 象棋程序,其实就是在一个网页里完整复刻中国象棋的对局体验,并且让浏览器扮演“对手”。玩家点击棋子、选择目标格、松手落子,程序先校验是否符合象棋规则,再切换回合。
如果是轮到 AI 走棋,它就启动一套搜索算法:把未来若干步可能出现的局面全部展开,用评估函数给每个局面打分,然后选择对自己最有利的一条分支走。整个过程只在浏览器本地运行,不需要服务器,不需要 API 网关,也不需要训练模型权重的 Python 环境。
我给它定的目标是:AI 在 1 秒内完成思考,对普通爱好者至少能下出“不乱走、会兑子、知道将军”的水平。如果想做一个上线给朋友玩的产品,这个完成度已经足够作为一个 MVP。
1.2 为什么我不选后端服务或深度学习路线
大多数第一次听到“AI 象棋”的人,第一反应是上强化学习或者调一个神经网络模型。但真做起来你会发现,一个靠谱的棋类 AI 最核心的并不是“模仿人”,而是在规则空间内做有限深度的确定性搜索。
同样一盘棋,神经网络需要海量棋谱训练,而搜索算法只需要把局面展开然后选最优。中国象棋的分支因子通常在 40 左右,也就是平均每步有 40 种合法着法。相比围棋的 200+,搜索空间对于现代浏览器来说其实是可控的。用原生 JavaScript 实现带剪枝的搜索,深度在 4 到 6 层时可以做到准实时响应,效果已经相当能打。
我选择不碰后端还有一层现实原因:纯前端文件可以随时打开、随意分享,没有任何部署成本。用户拿到一个 .html 就能玩,配合 GitHub Pages 或任意静态托管就能挂到公网。AI 计算全部在本地完成,没有并发压力,也不涉及隐私数据。这对一个个人项目来说几乎是理想的形态。
1.3 最终功能清单
开发完以后,我把功能收敛成这样一份清单:
| 功能项 | 实现说明 |
|---|---|
| 棋盘渲染 | Canvas 绘制 9 列 x 10 行的象棋棋盘,包含楚河汉界与九宫斜线 |
| 走子交互 | 鼠标选中棋子高亮,点击目标格完成行棋,自动标注可走位置 |
| 完整规则 | 车、马、象、士、将、炮、兵的所有走法约束,包含蹩马腿、塞象眼、将帅不可照面等 |
| 回合管理 | 红方先行,玩家执红,AI 执黑,状态机轮转 |
| AI 落子 | 极小极大搜索 + Alpha-Beta 剪枝,当前版本固定搜索深度为 4 |
| 终局判定 | 将死、困毙、将军提示,和局提示 |
| 悔棋与重开 | 记录历史局面栈,支持一键悔棋和重置 |
有了这个清单以后,后面的开发就有了明确的验收标准。实际情况是:做完棋盘渲染只需要半天,规则校验花了整整一个周末,AI 搜索迭代又花了一个周末。下面我把这几个环节的关键决策一一拆开讲。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 棋盘绘制与交互设计——先把“壳”做扎实
2.1 用 Canvas 还是 DOM:我的选择逻辑
棋盘渲染可以走两条路:一是用 CSS + 绝对定位的 DOM 棋子,二是用 Canvas 统一绘制。我最后选了 Canvas,原因有三:
第一,Canvas 的重绘是立即模式的,绘制一个棋盘 10ms 以内就能完成,而 DOM 在棋子频繁移动时会产生布局计算和重排,对低端手机不够友好。第二,棋盘本身有大量网格线、九宫斜线、文字标注,Canvas 的路径 API 画起来更顺手。第三,Canvas 的坐标系和控制逻辑完全由自己掌控,后面画“可走位置提示点”、搞动画或调试显形走法时,可以直接把内部数据画出来,方便得不是一点半点。
对素材的执念可以放下:棋子不需要任何 PNG 图片资源,我直接用填充圆 + 文本绘制,“将”“士”“象”“马”这些字通过 fillText 写上去,中文天生就是最好的棋子素材。
2.2 坐标系统设计
这一步看起来简单,却是全项目最关键的抽象之一。中国象棋棋盘是 9 列 x 10 行,玩家习惯把横向称为“路”、纵向称为“线”。在代码里,我统一用 Board 坐标 [row, col],其中 row 范围 0~9(从上到下),col 范围 0~8(从左到右)。
举个例子:红方最底线的“车”位于 [9, 0],黑方最底线的“车”位于 [0, 0]。这样做的好处是:搜索算法、走法生成、AI 评估全都在同一套坐标系下面工作,不会出现“UI 坐标是 y 向下,AI 坐标是 x 向下”的混乱。
Canvas 像素坐标和棋盘逻辑坐标之间需要两个转换函数:
javascript复制function boardToPixel(row, col) {
return {
x: MARGIN + col * CELL_SIZE,
y: MARGIN + row * CELL_SIZE
};
}
function pixelToBoard(x, y) {
const col = Math.round((x - MARGIN) / CELL_SIZE);
const row = Math.round((y - MARGIN) / CELL_SIZE);
if (row < 0 || row > 9 || col < 0 || col > 8) return null;
return { row, col };
}
MARGIN 我取 40px,CELL_SIZE 随画布宽度自适应,比如画布宽 640px 时单元格约为 62px,棋子半径取 27px。棋盘绘制
