概念 · 导师经历
学习者会做什么
一条每节课都以“做出一样东西”收尾的学习路径,外加一节可以直接运行的课:一个井字棋程序,学会分辨哪些走法根本不用看。
计划中 · 本页为概念演示
在下方运行 ↓这是一个概念演示,不是真实课程的记录。页面不涉及任何学员、课程或机构。学习路径、课程内容、代码以及演示里的每一个棋局,都是为本页从零写的。
想法
在辅导和教学里,真正让人记住的很少是讲解本身,而是学习者亲手做出来、跑通了的那个小东西。到了那一步,概念才不再只是文字。
真实课程的笔记属于参与其中的人,不适合放到公开页面上。所以这一页把这种做法从零重写了一遍:一条简短的学习路径,写明每节课讲什么、学习者会做出什么,再加一节可以在浏览器里直接运行的课。
学习路径
每节课只讲一个概念,做一样小东西,再用一个检验确认它能用。下面这条示例路径讲的是博弈搜索,是为本页写的。
第 1 节:把游戏看成一棵树
- 讲什么
- 局面、走法和轮次,以及为什么每一盘井字棋都是同一棵树上的一条路径。
- 做出什么
- 一个列出所有合法走法的函数,以及一个统计所有可能对局的计数器。
- 怎么检验
- 数出来应该正好是 255,168 盘。
第 2 节:极小化极大(minimax)
- 讲什么
- 给结束的对局打分,再把最好的分数沿着树往上传:X 取最大,O 取最小。
- 做出什么
- 一个下井字棋永远不会输的程序。
- 怎么检验
- 从空棋盘开始让它自己跟自己下,结果永远是平局。
第 3 节:alpha-beta 剪枝
- 讲什么
- alpha 和 beta 两个界限,让搜索跳过那些不可能改变结果的分支。
- 做出什么
- 同一个程序,加上一个记录访问了多少局面的计数器。
- 怎么检验
- 它得出的结果和 minimax 一样,访问的局面却少得多。
第 4 节:走法排序
- 讲什么
- 为什么先试强的走法,剪枝就能剪得更多。
- 做出什么
- 一种先中心、再四角、最后四边的搜索顺序。
- 怎么检验
- 对比改顺序前后的计数,结果保持不变。
第 5 节:当树大到搜不完
- 讲什么
- 深度限制和局面评分规则,用在四子棋这类搜不到终局的游戏上。
- 做出什么
- 一个搜到固定深度就停下、用一条简单规则给局面打分的程序。
- 怎么检验
- 让它和随机落子的对手下,统计胜负。
第 6 节:讲给别人听
- 讲什么
- 用平实的话写清楚自己做了什么,并为容易出错的部分写测试。
- 做出什么
- 一份简短的 README,以及几个检查胜负判断的测试。
- 怎么检验
- 一个没接触过的人能自己跑起来,也看得懂。
运行这节课:先 minimax,再 alpha-beta
概念演示,并非真实系统。棋局都是虚构的,没有任何内容来自真实的课程或学员。
选一个起始局面,或者自己走几步,然后比较两种搜索。双方都走最佳时,两者算出的结局永远一致,但 alpha-beta 访问的局面更少。下面逐行列出了它在哪里省得最多。
01
Minimax
把每一步都试到终局。结束的对局按结果打分:X 赢记 +1,O 赢记 −1,平局记 0。X 取最高分,O 取最低分,分数沿着树一层层往上传。
02
Alpha-beta
往下搜索时带上两个数。alpha 是 X 已经稳拿的最好分数,beta 是 O 已经稳拿的最好分数。一旦 alpha 追上 beta,这个分支里剩下的走法都改变不了结果,搜索就在这里停下。
03
顺序
先试强的走法,剪枝就剪得最多。切换搜索顺序,看看 alpha-beta 的计数怎么变,而结局保持不变。
合成棋局 · 从零编写 · 在你的浏览器里运行
轮到 O
选一个空格落下一步。方向键在格子之间移动,回车键或空格键落子。
最佳走法
从当前局面出发访问的局面数
- Minimax
- 55,505
- Alpha-beta
- 2,316
- 少看了
- 96%
- 剪掉的分支
- 1,014
最佳走法左上。双方都走最佳时,结果是平局。
逐步来看
每一行是当前局面下的一种走法,按搜索顺序排列,并注明双方都走最佳时的结局。上面的条是 minimax,下面的条是 alpha-beta,用的是同一个比例尺。
左上平局
Minimax6,812Alpha-beta703目前最好的一步
上中X 胜
Minimax7,064Alpha-beta166不可能比左上更好,alpha-beta 一确认就停下了。
右上平局
Minimax6,812Alpha-beta254不可能比左上更好,alpha-beta 一确认就停下了。
左中X 胜
Minimax7,064Alpha-beta106不可能比左上更好,alpha-beta 一确认就停下了。
右中X 胜
Minimax7,064Alpha-beta174不可能比左上更好,alpha-beta 一确认就停下了。
左下平局
Minimax6,812Alpha-beta282不可能比左上更好,alpha-beta 一确认就停下了。
下中X 胜
Minimax7,064Alpha-beta311不可能比左上更好,alpha-beta 一确认就停下了。
右下平局
Minimax6,812Alpha-beta319不可能比左上更好,alpha-beta 一确认就停下了。
轮到 O。最佳走法:左上,双方都走最佳时结果是平局。minimax 访问了 55,505 个局面,alpha-beta 访问了 2,316 个,少了 96%。
代码
function minimax(board, player, order, stats) { stats.nodes += 1; const score = finalScore(board); if (score !== null) return score; let best = player === "X" ? -Infinity : Infinity; for (const cell of order) { if (board[cell]) continue; board[cell] = player; const value = minimax(board, other(player), order, stats); board[cell] = null; best = player === "X" ? Math.max(best, value) : Math.min(best, value); } return best;}标记的行是 alpha-beta 与 minimax 不同的地方。
怎么做的
- 角色
- 导师兼作者
- 导师经历
- 2024 – 2025
- 数据
- 合成棋局
- 运行
- 在浏览器里
- JavaScript
- React
- Next.js
- Tailwind CSS
搜索引擎是纯 JavaScript 写的,不依赖任何库。它在你的浏览器里运行,不保存也不发送任何数据。
两个搜索函数就是代码面板里的那两个。唯一多出来的是一个计数器,每访问一个局面就加一,页面上的数字都来自它。页面从同一个局面出发,逐个走法分别运行两种搜索,所以每一行都能显示那一步花了多少。
棋盘是九个原生按钮。方向键可以在格子之间移动,每次变化后屏幕阅读器会读出结果。页面上没有自动播放的动画,开启“减少动态效果”后用起来也完全一样。
我的角色
我做导师,也教课。这张卡片会用来整理这些经历里的概念和小项目。本页的所有内容,从学习路径到搜索代码,都是我自己写的。
每节课上,我会尽量找到那个能打通下一步的概念,再帮学习者做出一个足够小的东西,在下课前完成并检验。
接下来
这一页目前还只是计划。完整的学习路径会一节一节地写出来,上面的每个例子都会从零重写,或者使用合成数据。真实课程里的内容,以及参与者的任何信息,都不会公开。
概念页。课程和其中的每个棋局都是合成的,为本页从零编写。
返回项目