詰み判定
前提知識: 合法手生成(指し手生成パイプラインの全体像)
このページの要点
- rsshogi は 1 手詰めの高速判定を提供し、探索のリーフノードでの詰み検出に使用される
- テーブル駆動方式で、事前計算された 65,536 エントリのテーブルを参照して判定する
なぜ詰み判定が必要か
Alpha-Beta 探索のリーフノード(静止探索の末端)で、現局面が詰みかどうかを高速に判定できると、 探索効率が大きく向上します。全合法手を生成して「合法手なし」を確認する方式は、 王手がかかっていない局面では無駄な手生成が発生します。
専用の詰み判定ルーチンは、王手をかけられる手だけを候補に絞り、 相手の応手(王の逃げ、合駒、取り返し)を効率的に検証することで、 通常の合法手生成よりも桁違いに高速に動作します。
公開 API
// 1 手詰め判定
pub fn solve_mate_in_one(pos: &Position) -> Option<Move32>
ソースファイル: crates/rsshogi/src/mate/
テーブル駆動方式
mate_constant.rs で事前計算される 65,536 エントリ(= 16 ビット)のテーブルを使用する方式です。
玉の周囲 8 方向の状況を 16 ビットのインデックスにエンコードします。
- 下位 8 ビット(drop candidates): 周囲 8 方向のうち自駒がなく、駒を打ち込める方向
- 上位 8 ビット(king movable): 玉が逃げられる方向(味方駒がなく、かつ攻め方の利きも届かない方向)
このインデックスでテーブルを引くと、各エントリ MateInfo から
「どの持ち駒種を打てば詰むか」(hand_kind)と
「盤上の駒を動かして詰む方向」(directions)が得られます。
#![allow(unused)]
fn main() {
pub struct MateInfo {
pub hand_kind: u8, // 打ち駒で詰む持ち駒種のビットマスク
pub directions: u8, // 盤上の駒(馬・竜のような全方向利き)を動かして詰む方向のビットマスク
}
}
アルゴリズム概要
1 手詰めとは「手番側が 1 手指せば相手玉が詰む」状態です。判定は 2 段階で行い、 テーブル駆動の打ち駒判定を先に試すのが高速化の肝です。
// 1. 玉の周囲 8 方向から 16 ビットの index を作り、MateInfo を引く let info = mate_table[index];
// 2. 打ち駒による詰み(テーブル先行) for 持ち駒種 in info.hand_kind に立つ駒種(手元にあるもの): for dir in 周囲の打てる方向: let mv = その方向へ持ち駒を打つ手; if mv が王手 AND is_mate_bitboard(mv): // 相手の全応手を検証 return Some(mv)
// 3. 打ち駒で詰まなければ、盤上の駒による王手手を列挙して検証 for mv in generate_checks(局面): if mv が合法 AND is_mate_bitboard(mv): return Some(mv)
return None // 詰みなし
打ち駒の候補は MateInfo(hand_kind / directions)でテーブルから直接得られるため、
多くの局面で盤上駒の手生成(手順 3)に到達する前に判定が確定します。
応手の網羅的検証(is_mate_bitboard)
王手候補が見つかったら、is_mate_bitboard で相手の全応手を検証し、詰みかどうかを確認します。
- 王の逃げ: 王手された駒の利きと味方駒の利きで塞がれていない方向への移動
- 合駒: 遠方駒(香・角・飛、および成り遠方駒の馬・竜)の利き線上への駒打ちまたは移動。近接王手の場合は合駒不可
- 取り返し: 王手している駒を王以外の駒で取る。ピンされた駒は取り返しに参加できない
すべての応手が不可能なら詰みです。
落とし穴
打ち歩詰めの見落とし
歩を打って王手する場合、それが打ち歩詰め(歩を打って相手玉が詰む最終手)に該当すると 反則負けになります。1 手詰め判定でもこのチェックを行う必要があります。
成り忘れ
王手をかける手で成れる場合は成りを優先する必要があります。 成らないと王手にならないケース(例: 銀が成って金の利きで王手)を見落とすと、 詰み手順の一部が欠落します。
探索エンジンでの拡張
3 手以上の詰み探索やより高度な詰み判定は、探索エンジン側で実装することを推奨します。
rsshogi の solve_mate_in_one をビルディングブロックとして使用し、
反復深化やアルファベータ探索と組み合わせることで、任意の手数の詰み探索が可能です。
まとめ
- 1 手詰め: テーブル駆動方式で 65,536 エントリのテーブルを参照して判定
- 探索エンジンとの統合が容易なシンプルな API
次に読む
→ パフォーマンス最適化: SIMD による高速化と、perft を使った合法手生成の検証について解説します。
参考資料
- Chess Programming Wiki - Checkmate - チェスにおける詰み判定の一般的な手法