Bonanzaの3手詰み判定関数はどういう処理になっているのか【前編】

1手詰みの解説が終わったので今回は3手詰み。
3手詰み判定はmate3ply.cに書いてある。


"3手詰み" というのは名ばかりで、すぐに取り替えされる中合いをした場合などはそれを王手していた駒で取ってみてそれで詰むかどうかを調べる。


そこで、この判定関数は「3手で詰む」とは考えず、「簡単な詰み」と捉えたほうが理解しやすい。mate3ply.cで定義されている関数は次の関数である。シグネチャは私がいくつか理解しやすいように変更してある。


このソースのコメントを私が書いたのはずいぶん以前なので間違ってものがあるかも知れない。

// and接点用とor接点用の詰み判定。
// and接点は詰まされるほうの手番。すべての回避手が詰みならそれは詰み。
// or接点は詰ますほうの手番。ひとつでも詰みの手があればその接点は詰み。
// 詰み判定は、詰ますほうの手番で敵玉が詰むかどうかだからor接点だと考えることが出来る。
bool mate3_and( Tree * restrict ptree, Turn turn, Ply ply );
bool mate_weak_or( Tree * restrict ptree, Turn turn, Ply ply, BoardPos from, BoardPos to );

// turn側の自玉に王手がかけている駒を列挙(最大2つ)。
// 列挙した駒は psq[0] , psq[1]に。psq[1]は2つ目の駒がなければ nsquareが返る。
// 前提 : turn側に王手がかかっていないといけない。
// 両王手の場合、片方は直接王手である。直接王手しているほうをpsq[0]にする。
void checker( const Tree * restrict ptree, BoardPos *psq, Turn turn );

// toが王手をしている駒。この駒をとる王の移動を生成する。
// 指し手がなければ0を返す。toの駒が王の移動範囲になかったり、toの駒に敵の利きがあったり
// すれば0が返る。さもなくば、指し手を生成してそれが返る。
Move gen_king_cap_checker( const Tree * restrict ptree, BoardPos to, Turn turn );

// 王手している駒(to)を捕獲するように駒を移動させる手の生成
// to : 駒を移動させる地点
Move *gen_move_to( const Tree * restrict ptree, BoardPos sq, Turn turn, Move * restrict pmove );

// 王手されているときに王の移動手を生成する
// is_capture == true なら駒を取る王の移動手のみ生成する
// is_capture == false なら駒を取らない王の移動手のみ生成する
// psqは王手している駒のBoardPos。最大2つ。2つある場合は、psq[0]は近接王手をしているほうの駒。
// psq[1] == nsquareならば2つ目の王手駒は無し。
// 利きのないすべての退路に移動する手を生成する。
Move *gen_king_move( const Tree * restrict ptree, const BoardPos *psq, Turn turn, 
		bool is_capture,  Move * restrict pmove );

// 合駒する手を生成する。移動合いも生成する。
// よさげな手 = 利きのあるところに合駒/移動合いする手
//   は優先して生成される。
// premaining : 生成したよさげな手の数 pmove[0]..pmove[*premaining-1]までがよさげな手。
// ↑remaining(残り)のポインタでp + remainingと命名されている。
// turn : 詰みをチェックするほうの手番。blackならば先手手番で、かつ先手玉が王手されている。
// sq_checker : 王手している駒
Move *gen_intercept( Tree * restrict __ptree__, BoardPos sq_checker, Turn turn,
		 u32 * restrict premaining , Move * restrict pmove );

// 王手の回避手を生成する。ここで生成される手によって王手は100%回避できている。
// 生成された指し手は、MOVE_CURRに入る。呼び出されるごとに新しい手が生成されて、
// それ以上生成できなくなれば(回避する手がない)、この場合、この関数の返し値としてfalseが返る。
// すなわち、この関数はcoroutineになっている。
bool gen_next_evasion_mate( Tree * restrict ptree, const BoardPos *psq, Ply ply, Turn turn );