谜题 / 国际象棋 · 实战对局 / 第 7 课 · FEN 待审核 8 / 8
FEN · 局面的写法

第 7 课 · FEN

第 6 课 §3 把三种记法各点了一句:SAN 记一手棋,PGN 记一整局,FEN 记一个局面。前两种写的是过程,FEN 写的是状态:一个局面要被换个地方接着下完,必须随身带上哪些东西。答案恰好是六件。

对局页右侧面板逐手显示的那一行就是它,复制按钮出的也是它。

1 · 六个字段

初始局面写作:

rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1

FEN(Forsyth–Edwards Notation)以空格分成六段,顺序固定:

名字 初始值 记什么
1 piece placement 棋子分布 rnbqkbnr/…/RNBQKBNR 八行棋子,行间用 / 分隔
2 active color 轮走方 w 白方走记 w,黑方走记 b
3 castling availability 易位权 KQkq 四种易位还剩哪几种
4 en passant target square 过路兵目标格 - 上一手双步兵路过的那一格
5 halfmove clock 半回合钟 0 距上次吃子或兵动的半回合数
6 fullmove number 回合数 1 当前是第几个回合

第 1 段与第 2 段是「盘上有什么、轮谁走」,这两件事看棋盘就有;后四段看棋盘看不出来,全是历史留下的权利与计数。少了它们,一个局面可以合法地走出不同的着法:同样的盘面,易位权在与不在,可走的棋就不一样。

2 · 布局那一段

布局段用 / 分成八行,从第 8 行(黑方底线)写起,到第 1 行(白方底线)为止。行内从 a 列写到 h 列。字母是棋子,k 王、q 后、r 车、b 象、n 马、p 兵,大写为白、小写为黑。马取 n 是因为 k 已经归了王。

数字是连续空格的个数:8 是整行空格,3p4 是三个空格、一个黑兵、四个空格。一行内数字与字母加起来必须正好八格,八行合起来正好 64 格。

这个书写顺序对实现是白送的便利。本页的规则内核把棋盘存成长 64 的 Uint8Array,下标 0 是 a8、63 是 h1,与 FEN 的书写顺序一字不差(core/board.ts),解析时不需要任何行号换算,sq >> 3 直接就是行、sq & 7 直接就是列。

3 · 布局之外的五段

第 2 段只有 w 与 b 两个值。

第 3 段是四种易位权的清单:K 白方短易位(王翼)、Q 白方长易位(后翼)、k 与 q 是黑方的对应两项,四种全失写 -。这一段只减不增:王一动,本方两翼全失;车离开原位,或原位上的车被吃,该翼失权。

第 4 段记的是被双步兵路过的那一格,1.e4 之后写 e3。为什么是路过的格而不是兵停下的格,见 §4。

第 5 段是半回合钟(halfmove clock),距上一次吃子或兵动走了多少个半回合,吃子与动兵都把它清零。本页判 50 步和棋的门槛是这个数到 100,也就是双方各走满 50 步。第 6 段是回合数,黑方走完加一。

4 · 过路兵格与局面指纹

第 4 段有两种流通的口径。PGN 标准的说法是无条件的:只要上一手是兵的双步,就写下它路过的那一格,有没有兵吃得到都要写。Stockfish 输出的 FEN 走另一种:只在这一步过路兵真能走出来时才写格名,否则写 -。本页取前一种,applyMove 里一行就定了案——next.ep = fl & F_DOUBLE ? (from + to) / 2 : -1

差别不在字符串好不好看,而在三次重复怎么数。本页把局面指纹定义为 FEN 去掉两个计数器之后的前四段(posKey),同一指纹出现三次即判和。两条路线走到同一盘面:

1.a4 h6 2.a5 h5 3.Nf3 e5          rnbqkbnr/pppp1pp1/8/P3p2p/8/5N2/1PPPPPPP/RNBQKB1R w KQkq e6 0 4
1.a3 e6 2.a4 e5 3.a5 h6 4.Nf3 h5  rnbqkbnr/pppp1pp1/8/P3p2p/8/5N2/1PPPPPPP/RNBQKB1R w KQkq -  0 5

棋子分布、轮走方、易位权三段全同,两个局面各自的合法着法都是 24 条(黑方那个兵是一步跳过来还是两步挪过来,走完之后没留下任何区别),而指纹因第 4 段分岔。FIDE 判「同一局面」的依据是双方可走的着法相同,按那个依据这两处是同一个局面,本页数成两个。后果是个别三次重复漏判,方向是少判和而非错判和。

同一个指纹在本页另有两处用途。联机对局每手互报指纹做一致性校验:两端跑的是同一份内核,口径差异对两边同时生效,不会引起误报。棋盘视图则靠比对指纹决定这一手能不能走增量动画(core/view.ts),对不上就整盘重建。

5 · 解析器的宽与严

fromFen 的严格只覆盖「盘面能不能立起来」:段数不足四段抛错;布局段铺不满 64 格抛错,少写一个子会报「FEN 只铺满了 63 格」;缺王抛错。末两段允许整个省掉,按 01 补上。

第 3 段则完全不与棋子核对。4k3/8/8/8/8/8/4P3/4K3 w KQkq - 0 1 盘上一个车都没有,内核照收 KQkqgenMoves 给出 O-OO-O-O,走完之后 f1 上凭空多出一个白车:

4k3/8/8/8/8/8/4P3/5RK1 b kq - 1 1

自家走子撞不上这一条,易位权只减不增,权利与棋子在 applyMove 里是同步维护的。只有从外部粘进来的 FEN 才可能带着与盘面对不上的第 3 段。把这一项补成核对(王在 e1、车在 h1 才认 K)是个小改动,本页尚未做;拆解器里的审计提示是在旁边报出来,不拦着走。

6 · 拆解器

图 6-1 · FEN 拆解器。两方的子都可拖动,六个字段随每一手更新并高亮改动过的那几段,下方给出当前局面的指纹与出现次数。可粘贴任意 FEN 载入,预设里含过路兵两种口径、易位权失效、半回合钟临界与假易位权各一例。

课程目录 · 0 子力安全 · 1 开局三件事 · 2 五种吃子图形 · 3 攻王 · 4 该不该兑子 · 5 四个必会残局 · 6 名字 · 7 FEN