Soma Zero Tutorials
🔍 搜索功能尚未开启,敬请期待。

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 排序。