3.2 棋盘表示与规则引擎
上一节说国象“难在判得准”,但在判之前,得先把规则写对——而这恰恰是国象工程量最大的一块。这一节我们认识 Bitboard 表示与 FEN,看清那些恼人的特殊规则,然后给你一个实用建议:别自己从零写规则,用成熟的
python-chess库,把精力省下来留给真正的主角——搜索和评估。
一、Bitboard 与 FEN:怎么表示一个国象局面
五子棋我们用 15×15 数组就行。国象棋盘只有 8×8=64 格,反而催生了一种极优雅的表示——位棋盘(Bitboard):用一个 64 位整数表示“某一类棋子在哪些格”,每一位对应一格、1 表示有子。比如“白兵的 bitboard”、“黑马的 bitboard”……一共十几个 64 位整数就描述了整个局面。
它的妙处是能用位运算批量算走子:想知道所有白兵能往前走一格到哪,把白兵 bitboard 整体左移 8 位、再去掉被占的格——一条位运算就算完 8 个兵。这种“一次算一整类”的效率,正是国象引擎能搜得快的底层秘密(和 2.1 提过的五子棋 bitboard 是同一思路,只是国象用得更尽兴)。
局面的串行化用 FEN(Forsyth–Edwards Notation)——一行字符串记下所有棋子位置、轮到谁、易位权、过路兵格等。它就是国象世界的“存档格式”,相当于五子棋那章 info() 里的 board 字段,只是更紧凑、且是行业标准。
二、那些恼人的特殊规则
国象“合法走子”之所以难写,全在几个特例上——它们也是上一节说的“异质棋子”带来的麻烦:
- 王车易位(castling):一手同时动王和车,还要满足“都没动过、中间没子、王不经过被攻击的格”。
- 吃过路兵(en passant):吃掉的兵不在落点上,是个反直觉的特例。
- 兵升变(promotion):兵走到底线,要换成后/车/象/马(通常选后)。
- 将军与绝杀检测:最关键也最容易写错——“合法走子”必须排除所有“走完后自己的王还被将军”的着法。这一条让走子生成不能只看“这子能去哪”,还得验证“走完王安不安全”。
这些规则本身不难懂,但要全部写对、且不留 bug,是个细致活——很多人写国象引擎,一大半时间都耗在调这些规则上,还没碰到 AI 就累趴了。
三、用 python-chess 把规则外包出去
所以这里给一个务实的建议:规则别自己造,交给 python-chess。它是成熟可靠的库(pip install chess),把上面那些特例全替你处理好了,还自带 FEN 解析、将杀判定、PGN 棋谱读写。我们把精力留给真正值得自己写的——搜索和评估。照例,把它包进第一章定稿的统一接口:
import chess
class ChessEngine(GameEngine):
def __init__(self, fen=chess.STARTING_FEN):
self.board = chess.Board(fen)
def legal_moves(self):
return list(self.board.legal_moves) # 易位/过路兵/升变/避将 全替你算好了
def make_move(self, move):
self.board.push(move) # 走一步
def is_terminal(self):
return self.board.is_game_over()
def winner(self):
r = self.board.result() # "1-0" / "0-1" / "1/2-1/2"
return {"1-0": 1, "0-1": -1}.get(r, 0)
def info(self):
return {"fen": self.board.fen(),
"legal_moves": [m.uci() for m in self.board.legal_moves],
"is_terminal": self.is_terminal(),
"winner": self.winner()}
看出来了吗——接口长得和井字棋、五子棋几乎一模一样。这正是我们从 1.2 起死磕统一接口的回报:哪怕换成规则复杂十倍的国象,外面的 pygame 界面、对战擂台、乃至将来的 Anima 框架,对接方式完全不变。规则这块外包掉之后,从下一节起,我们就能心无旁骛地搬来前两章的搜索框架了。
四、小结与下一节
- Bitboard:用 64 位整数表示一类棋子的位置,位运算批量算走子,是国象引擎跑得快的底层。
- FEN:国象的标准“存档格式”,紧凑记录整个局面。
- 特殊规则:易位/过路兵/升变/避将检测,难写易错。
- 务实建议:用
python-chess把规则外包,包进统一接口,省力留给搜索与评估。
地基搞定。下一节 3.3 搜索:迁移到国象,我们把前两章的 α-β、迭代加深、置换表原样搬过来,再补上国象特有的两样:静态搜索(Quiescence)和 MVV-LVA 排序。