利きの計算
利きの計算は、占有に依存しない定数パターンと、最初の遮蔽駒までを求める飛び利きに分かれる。
どちらも Bitboard を返すため、利用側は自駒集合との積集合や差集合をそのまま続けられる。
非飛び駒
build.rs は歩、桂、銀、金、玉の擬似利きを各マスと色に対して生成する。
生成物は PAWN_ATTACKS、KNIGHT_ATTACKS、SILVER_ATTACKS、GOLD_ATTACKS、KING_ATTACKS として攻撃テーブルに含まれる。
盤端で盤外へ出る候補は生成されない。
安全な高水準 API は Position の利き照会と手生成で使われる。
*_attacks_unchecked はテーブルの 81 マス範囲を呼び出し側が保証する内部ホットパスである。
ビームと飛び利き
香、角、飛の各マスについて、build.rs は遮蔽を考慮しない方向別ビームを生成する。
公開される LANCE_BEAMS、BISHOP_BEAMS、ROOK_BEAMS は方向別の Bitboard であり、ステップ利きと検査に使える。
実際の飛び利きは、占有ビットとの交差から各方向の最寄り遮蔽駒を含む範囲だけを残す。
始点 -- 空 -- 空 -- 遮蔽駒 -- その先
利き : 1 1 1 0
lance_attacks は筋の 9 ビット占有を用い、手番に対応する一方向へ結果を絞る。
rook_file_attacks は同じ筋の両方向を、rook_rank_attacks は段の両方向を返す。
rook_attacks は二つを合わせ、bishop_attacks は四つの対角方向を合わせる。
内部のレイ表現
攻撃テーブルには公開ビームとは別に、LanceRayBits、BishopRayBits、RookRayBits という private な u128 のレイ表現がある。
これらは連続盤面用と、反転方向を前向きの走査として扱うためのレイを保持する。
BishopRayBits と RookRayBits の内容は実装最適化であり、外部形式や public API の契約ではない。
角と飛の前向き二方向は paired_increasing_attacks で一組として処理し、逆方向は占有とレイをビット反転して同じ計算に帰着させる。
AVX2 が有効なビルドでは、その一組を 256 ビット演算で処理する。
AVX2 がないビルドでは同じ関数が二回のスカラー u128 演算へ分岐する。
この差は実行結果ではなく、同じレイ抽出をどう並列化するかだけの差である。
正確性の基準
攻撃テーブルのテストは、各始点と方向について最寄り遮蔽駒の全候補を列挙し、単純な一マスずつの走査と比較する。
さらに疑似乱数の占有局面でも、香・角・飛の結果をスカラー走査と比較する。
したがって最適化経路を変更するときは、遮蔽駒そのものを結果に含め、直後のマスを含めないこの契約を保つ必要がある。
利きと合法性
攻撃テーブルが返すのは駒の移動規則と占有だけから得る擬似利きである。
自駒のマスへ移動できない条件、王手を受ける玉の退避、ピンされた駒が動ける範囲、打ち歩詰めなどは別の層で処理する。
例えば rook_attacks は遮蔽駒の色を区別しないため、自駒の遮蔽駒も敵駒の遮蔽駒も到達範囲の末尾として含む。
手生成側はその結果から自駒集合を除くことで、通常の移動先候補へ変換する。
この分離により、同じ飛び利き関数を敵利きの計算、ピン検出、SEE の一時占有、候補手生成で再利用できる。
王手候補テーブル
build.rs は CHECK_CANDIDATE_BB も生成する。
これは相手玉の位置、駒種、手番から、王手を作り得る配置候補を返すテーブルである。
テーブルは候補を狭めるためのものであり、実際に王手になるかは移動後の占有と合法性で確認する。
成りによる駒種変化や遮蔽の開閉を伴う手は、この候補集合だけで確定しない。
実装を読む順序
最初に lance_attacks の 9 ビット筋方向を読むと、遮蔽駒を含めて止まる契約が分かる。
次に rook_file_attacks と rook_rank_attacks を見ると、飛車が二つの直交方向の和であることが分かる。
最後に bishop_attacks と rook_attacks の前向き・反転方向の組を読むと、private レイがなぜ二種類の u128 表現を持つかを追える。