用职责拆分降低 AI 开发棋类游戏的返工
作者在持续增加棋类游戏规则时发现,原有结构使每次扩展都牵动大量修改。通过拆分格子、单位、玩家、卡牌和裁判,并将流程与规则分离,为 AI 后续实现新规则建立更清晰的边界。
AI 深度解读
让 AI 写出一个能玩的棋盘游戏,和让它持续接住新规则,是两件事。作者开发 INSIGNIA 时发现,真正拖慢迭代的,是每加一条规则都要重做现有结构。他的解法是拆开游戏流程与规则,让变化有明确的落点。
这篇经验值得程序员读的地方,在于它把 AI 编程的评价标准往后推了一步:第一次生成得快固然有用,下一次改需求时要动多少旧代码,同样重要。不过,共享引擎带来的收益,也有适用前提。
新规则为什么总会牵动旧结构
INSIGNIA 基于 Stratego,但增加了原版没有的玩法:导弹必须沿直线飞行恰好 2 或 3 格;工兵可以把相邻障碍变成通路,再向前移动;突击队员能使用一次跳跃,攻击 3 格外的位置,但落点附近有狙击手时会被击落。

这些规则涉及不同层面:移动距离、地形变化、能力次数,以及其他单位对攻击结果的影响。它们不能全靠给棋子增加几个属性解决。
作者最初让 AI 构建游戏,后来继续加入规则和卡牌,却发现每次都要调整既有结构。他将问题归因于结构难以容纳变化,而不是 AI 写错了某段代码。
这里要区分两种工作:实现一条已经确定的规则,以及为后续未知规则留出修改空间。AI 能完成前者,并不代表第一次生成的组织方式就适合后者。
把 Game 和 Referee 分开,究竟省了什么
作者把游戏拆成格子、单位、玩家、卡牌和裁判,并划出最关键的一条边界:Game 管流程,Referee 管规则。
Game 接收行动,把行动交给裁判,再询问游戏是否结束。至于当前能走哪里、行动产生什么结果、下一步轮到谁,都由具体游戏的裁判处理。

Referee 是抽象类,其中 legalActions 提供当前可执行的行动,resolve 处理行动并决定下一回合归属。不同游戏实现各自的裁判类,复用相同的流程。
这相当于约定:流程只负责组织一局游戏,具体玩法通过统一接口接入。以后修改玩法,就有机会把改动限制在裁判及相关对象内。
格子和单位也被分开,不承担具体游戏规则。作者特别提到,格子不知道哪个单位位于自己上面。不过,正文没有进一步解释占位关系由谁维护。
拆分之后,规则有了各自的位置:隐藏军衔通过单位的 perceived value 表达,区分对手看到的身份与真实军衔;导弹使用单位的 range;工兵改变格子的可通行状态;突击队员的跳跃作为一次性能力处理。

有价值的抽象,是让下一条规则找到落点,而不是让类的数量增加。
约 400 行共享引擎,能说明复用成功了吗
作者随后把多个游戏放进同一引擎,给出了代码行数:
| 部分 | 代码行数 |
|---|---|
| 共享引擎 | 约 400 行 |
| Ladder game | 80 行 |
| Yut Nori | 127 行 |
| Blue Marble | 167 行 |
| Janggi | 257 行 |
他的实现方式是继承 Referee,再补齐游戏规则。据作者描述,从第二个游戏开始,引擎一行都没改;完成抽象并构建六个游戏的总耗时,也少于单独开发 INSIGNIA 的耗时。
比这些数字更有参考价值的,是抽象的时机:作者没有一开始就泛化全部能力,而是等第二个游戏需要时,才把共同部分移进引擎。
例如,Yut Nori 的分岔路径和 Ladder game 的单向捷径,都要求格子支持不同连接方式。没有棋盘的 Dominion,则可以只使用游戏流程,不使用格子。
这说明共享边界不一定等于大家熟悉的棋盘外形。作者实际复用的是流程与部分结构,玩法仍留在各自的规则实现里。
我的判断
我认同作者把注意力放在需求变更成本上。日常 AI 编程很容易围绕「一次生成了多少代码」讨论效率,但如果一个新能力会迫使流程、状态和规则一起修改,生成速度很难抵消后续维护成本。
不过,这仍然是一份个人实践报告。作者没有提供具体耗时、行数统计口径、测试覆盖情况,也没有给出采用其他结构的对照实现。「六个游戏比一个更快」可以作为经验线索,不能直接推广成面向对象设计的效率结论;列出的行数表也只覆盖四个具体游戏。
继承抽象裁判类是一种可行做法。函数组合或独立规则模块,也可能建立类似边界。原文没有比较这些方案,无法据此判断哪一种更优。
作者自己也划定了范围:如果只是做一个规则固定的 Janggi 或 Gomoku,完成后不再扩展,未必需要搭建这套结构。先找到反复变化的部分,再决定抽象到什么程度,比预先设计通用引擎更可靠。
能拿来做什么
- 用 AI 开发前端棋盘游戏时,可以先明确 Game、
legalActions和resolve的职责,再让 AI 实现具体规则,减少规则判断散落在流程中的机会。 - 给现有游戏增加能力前,先列出它影响的是移动范围、地形、可见身份还是使用次数。如果每次都要同时修改多个核心模块,就值得重新检查职责边界。
- 准备复用第二款游戏时,再提取两者实际共有的流程和结构,并记录新增规则需要修改哪些旧文件,用具体改动判断抽象是否有效。