Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

基本操作

Bitboard はマス集合なので、基本操作は集合演算として読める。

let occupied = black | white;
let empty = Bitboard::ALL & !occupied;
let capturable = enemy & attacks;
let quiet_targets = attacks.and_not(occupied);

!Bitboard::not は盤外ビットを必ず 0 にする。

and_not(a, b)a & !b を表し、対象集合から除外集合を引くホットパス用の操作である。

マスの操作

from_square は一つだけビットが立つ集合を作る。

可変の集合には setcleartest を使う。

test_index は検証済みの生インデックスを持つホットパス向けであり、通常は Square を受け取る test を使う。

いずれも盤上の Square を前提とし、開発時には debug_assert が範囲外利用を検出する。

走査

lsbmsb はそれぞれ最小・最大の SquareOption で返す。

pop_lsb は最小ビットを返して集合から消すため、候補集合を消費しながら列挙できる。

let mut targets = attacks & !own;
while let Some(to) = targets.pop_lsb() {
    // to ごとの候補手を処理する。
}

pop_lsb_unchecked は空でないことを呼び出し側が保証するときだけ使う。

BitIterIntoIterator for &Bitboard は同じ LSB 順の走査を提供する。

countanyis_emptymore_than_one は候補数による分岐に使う。

盤面マスクと変換

file_maskrank_mask は静的に構築された 9 個ずつのマスクを返す。

promotion_zone は色ごとの三段を返すため、成りの可否を判定する集合式に使える。

flip は 180 度回転、mirror_file は筋方向の反転を返す。

これらは各盤上マスを走査する変換であり、飛び利きの内部ビット反転とは役割が異なる。

byte_reverseunpackdecrementdecrement_pair は内部の二レーン計算を補助する操作である。

これらを局面の対称変換や保存形式として解釈せず、必要なときは意図に対応する flip または mirror_file を選ぶ。

SIMD とフォールバック

AND、OR、XOR、AND NOT は、x86_64 で SSE2 が有効なら 128 ビット intrinsic を使う。

それ以外では二つの u64 に同じ意味の演算を適用する。

intersects は SSE4.1 が有効なら ptest を使い、それ以外では二ワードの交差判定に戻る。

どちらの経路でも API の結果とビットの意味は同一である。

集合式の定石

ビット演算は優先順位よりも意味が読めることを優先し、中間集合に名前を付ける。

let own = bitboards.by_color(us);
let enemy = bitboards.by_color(!us);
let occupied = own | enemy;
let targets = rook_attacks(from, occupied).and_not(own);

この形なら、利きの計算が占有を必要とし、最終的な移動先では自駒を除くことが明確になる。

attacks & enemy は捕獲候補、attacks.and_not(occupied) は空きマスへの候補になる。

捕獲可能な駒を先に取り出すか、移動先を先に取り出すかは後続処理が必要とする情報で選ぶ。

破壊的走査の注意

pop_lsb は受け手を変更する。

元の集合を後で使うなら、値コピーを別のローカル変数に置いてから走査する。

let attackers = position.attackers_to(king, occupied);
let mut remaining = attackers;
while let Some(from) = remaining.pop_lsb() {
    // attackers は元の集合として残る。
}

BitboardCopy なので、このコピーにヒープ割り当てはない。

空集合で pop_lsb_unchecked を呼ぶことは unsafe 契約違反であり、候補が一つ以上あることを別の条件で確立した後だけに限定する。

更新の形

駒を一マス動かすときは、色別集合、駒種別集合、全占有のすべてで始点を消し終点を立てる。

捕獲があれば、捕獲された色と駒種の集合から終点を消してから移動駒を置く。

この操作は XOR だけで一般化できるように見えても、駒種の変化や捕獲があるため、局面更新の既存 API を通す方が安全である。