4.2 棋盘与规则引擎:气、提子、打劫、数子
和 3.2 一样,造引擎第一步是把规则写成代码。围棋规则条目少,但暗坑多:气、提子、打劫、自杀、数子。这一章把
GoBoard写出来——它正是本单元 capstone 那个可玩 App 的地基(对应仓库里的go/engine.py)。
一、棋盘与“气”
棋盘就是一个 N×N 的数组,每格 0/1/2 表示空/黑/白。围棋一切判断的原子概念是气(liberty):
- 相邻同色棋子连成一块叫棋串;
- 棋串周围的空交叉点就是它的气;
- 气尽则亡。
实现上,从一个子出发做洪泛搜索(flood fill),就能找出整块棋串和它的所有气。判断死活、提子、自杀,全靠这一个操作。
二、提子与自杀
落子后按顺序处理:
落子(点, 我方):
放上我方一子
对每个相邻的【对方】棋串:
若它已经没气 -> 整块提走
若我方这块此时仍没气:
-> 这是【自杀】,非法,撤销 # 除非上一步刚好提了子注意顺序:先提对方、再判自己。所以“看似自杀、实则提掉对方”的手是合法的。这一个先后关系,是规则引擎最容易写错的地方。
三、打劫(ko)
打劫是围棋最优雅的规则:如果单子提单子会让棋盘回到上一手的样子,就会无限循环。规则禁止立即回提:
- 提子后若“我这颗是只有一口气的单子、且只提了对方一子”,就记下那个劫点;
- 对方下一手不许落在劫点;
- 他在别处走一手后,劫点解禁,可以回提。
这迫使双方去别处找“劫材”,是围棋战斗的核心机制之一。
四、终局与数子
双方连续 pass(虚手)即终局。然后数子定胜负——本课用中国规则 · 区域计分:
某方得分 = 自己活子数 + 只被自己包围的空点数;白方再加贴目 7.5。
为什么强调这个?因为终局可以被明确数清楚,正是 MCTS“随机下到底再判胜负”这条路走得通的根本前提——下一章马上要用到。