update board representation
This commit is contained in:
parent
9a74ac0123
commit
85c7c8eb52
3 changed files with 184 additions and 147 deletions
|
|
@ -67,9 +67,9 @@ impl<'l> Move<'l> {
|
|||
/// Returns `true` if the move is a capture.
|
||||
#[inline]
|
||||
pub fn is_capture(self) -> bool {
|
||||
let setup = self.position.as_setup();
|
||||
let [p_b_q, n_b_k, r_q_k, _] = self.position.as_setup().bitboards;
|
||||
self.raw.kind == MoveType::EnPassant
|
||||
|| !((setup.p_b_q | setup.n_b_k | setup.r_q_k) & self.to().bitboard()).is_empty()
|
||||
|| !((p_b_q | n_b_k | r_q_k) & self.to().bitboard()).is_empty()
|
||||
}
|
||||
|
||||
/// Returns the type of piece that is captured, if the move is a capture.
|
||||
|
|
|
|||
175
src/position.rs
175
src/position.rs
|
|
@ -86,10 +86,12 @@ impl Position {
|
|||
#[inline]
|
||||
pub fn new() -> Self {
|
||||
Self(Setup {
|
||||
w: Bitboard(0x000000000000FFFF),
|
||||
p_b_q: Bitboard(0x2CFF00000000FF2C),
|
||||
n_b_k: Bitboard(0x7600000000000076),
|
||||
r_q_k: Bitboard(0x9900000000000099),
|
||||
bitboards: [
|
||||
Bitboard(0x2CFF00000000FF2C),
|
||||
Bitboard(0x7600000000000076),
|
||||
Bitboard(0x9900000000000099),
|
||||
Bitboard(0x000000000000FFFF),
|
||||
],
|
||||
turn: Color::White,
|
||||
castling_rights: CastlingRights::full(),
|
||||
en_passant: OptionSquare::None,
|
||||
|
|
@ -227,29 +229,34 @@ impl Position {
|
|||
/// and `None` if the king in check. On success, this inverts the color to
|
||||
/// play and discards the en passant square.
|
||||
pub fn pass(&self) -> Option<Self> {
|
||||
let setup = &self.0;
|
||||
let blockers = setup.p_b_q | setup.n_b_k | setup.r_q_k;
|
||||
let k = setup.n_b_k & setup.r_q_k;
|
||||
let q = setup.p_b_q & setup.r_q_k;
|
||||
let b = setup.p_b_q & setup.n_b_k;
|
||||
let n = setup.n_b_k ^ b ^ k;
|
||||
let r = setup.r_q_k ^ q ^ k;
|
||||
let p = setup.p_b_q ^ b ^ q;
|
||||
let (us, them) = match setup.turn {
|
||||
Color::White => (setup.w, blockers ^ setup.w),
|
||||
Color::Black => (blockers ^ setup.w, setup.w),
|
||||
let Setup {
|
||||
bitboards: [p_b_q, n_b_k, r_q_k, w],
|
||||
turn,
|
||||
en_passant: _,
|
||||
castling_rights: _,
|
||||
} = self.0;
|
||||
let blockers = p_b_q | n_b_k | r_q_k;
|
||||
let k = n_b_k & r_q_k;
|
||||
let q = p_b_q & r_q_k;
|
||||
let b = p_b_q & n_b_k;
|
||||
let n = n_b_k ^ b ^ k;
|
||||
let r = r_q_k ^ q ^ k;
|
||||
let p = p_b_q ^ b ^ q;
|
||||
let (us, them) = match turn {
|
||||
Color::White => (w, blockers ^ w),
|
||||
Color::Black => (blockers ^ w, w),
|
||||
};
|
||||
let king_square = (us & k).next().unwrap();
|
||||
let checkers = them
|
||||
& (lookup::pawn_attack(setup.turn, king_square) & p
|
||||
& (lookup::pawn_attack(turn, king_square) & p
|
||||
| lookup::knight(king_square) & n
|
||||
| lookup::bishop(king_square, blockers) & (q | b)
|
||||
| lookup::rook(king_square, blockers) & (q | r));
|
||||
checkers.is_empty().then(|| {
|
||||
Self(Setup {
|
||||
turn: !setup.turn,
|
||||
turn: !turn,
|
||||
en_passant: OptionSquare::None,
|
||||
..setup.clone()
|
||||
..self.0.clone()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
|
@ -573,10 +580,7 @@ impl Position {
|
|||
let global_mask_to = moves.to();
|
||||
|
||||
let Setup {
|
||||
w,
|
||||
p_b_q,
|
||||
n_b_k,
|
||||
r_q_k,
|
||||
bitboards: [p_b_q, n_b_k, r_q_k, w],
|
||||
turn,
|
||||
en_passant,
|
||||
castling_rights,
|
||||
|
|
@ -934,8 +938,9 @@ impl Position {
|
|||
MoveType::EnPassant => {
|
||||
let direction = !setup.turn.forward();
|
||||
let x = (unsafe { to.trans_unchecked(direction) }).bitboard();
|
||||
setup.p_b_q ^= x;
|
||||
setup.w &= !x;
|
||||
let [p_b_q, _, _, w] = &mut setup.bitboards;
|
||||
*p_b_q ^= x;
|
||||
*w &= !x;
|
||||
aux_play_pawn_advance(setup, Role::Pawn, from, to);
|
||||
}
|
||||
}
|
||||
|
|
@ -945,90 +950,116 @@ impl Position {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
fn aux_play_normal(setup: &mut Setup, role: Role, from: Square, target: Square) {
|
||||
fn aux_play_normal(
|
||||
Setup {
|
||||
bitboards: [p_b_q, n_b_k, r_q_k, w],
|
||||
turn,
|
||||
en_passant: _,
|
||||
castling_rights,
|
||||
}: &mut Setup,
|
||||
role: Role,
|
||||
from: Square,
|
||||
target: Square,
|
||||
) {
|
||||
let from = from.bitboard();
|
||||
let to = target.bitboard();
|
||||
let mask = !(from | to);
|
||||
setup.w &= mask;
|
||||
setup.p_b_q &= mask;
|
||||
setup.n_b_k &= mask;
|
||||
setup.r_q_k &= mask;
|
||||
if target == Square::from_coords(File::H, setup.turn.promotion_rank()) {
|
||||
setup
|
||||
.castling_rights
|
||||
.unset(!setup.turn, CastlingSide::Short);
|
||||
*p_b_q &= mask;
|
||||
*n_b_k &= mask;
|
||||
*r_q_k &= mask;
|
||||
*w &= mask;
|
||||
if target == Square::from_coords(File::H, turn.promotion_rank()) {
|
||||
castling_rights.unset(!*turn, CastlingSide::Short);
|
||||
}
|
||||
if target == Square::from_coords(File::A, setup.turn.promotion_rank()) {
|
||||
setup.castling_rights.unset(!setup.turn, CastlingSide::Long);
|
||||
if target == Square::from_coords(File::A, turn.promotion_rank()) {
|
||||
castling_rights.unset(!*turn, CastlingSide::Long);
|
||||
}
|
||||
match role {
|
||||
Role::King => {
|
||||
setup.n_b_k |= to;
|
||||
setup.r_q_k |= to;
|
||||
setup.castling_rights.unset(setup.turn, CastlingSide::Short);
|
||||
setup.castling_rights.unset(setup.turn, CastlingSide::Long);
|
||||
*n_b_k |= to;
|
||||
*r_q_k |= to;
|
||||
castling_rights.unset(*turn, CastlingSide::Short);
|
||||
castling_rights.unset(*turn, CastlingSide::Long);
|
||||
}
|
||||
Role::Queen => {
|
||||
setup.p_b_q |= to;
|
||||
setup.r_q_k |= to;
|
||||
*p_b_q |= to;
|
||||
*r_q_k |= to;
|
||||
}
|
||||
Role::Bishop => {
|
||||
setup.p_b_q |= to;
|
||||
setup.n_b_k |= to;
|
||||
*p_b_q |= to;
|
||||
*n_b_k |= to;
|
||||
}
|
||||
Role::Knight => {
|
||||
setup.n_b_k |= to;
|
||||
*n_b_k |= to;
|
||||
}
|
||||
Role::Rook => {
|
||||
setup.r_q_k |= to;
|
||||
if from == Square::from_coords(File::H, setup.turn.home_rank()).bitboard() {
|
||||
setup.castling_rights.unset(setup.turn, CastlingSide::Short);
|
||||
*r_q_k |= to;
|
||||
if from == Square::from_coords(File::H, turn.home_rank()).bitboard() {
|
||||
castling_rights.unset(*turn, CastlingSide::Short);
|
||||
}
|
||||
if from == Square::from_coords(File::A, setup.turn.home_rank()).bitboard() {
|
||||
setup.castling_rights.unset(setup.turn, CastlingSide::Long);
|
||||
if from == Square::from_coords(File::A, turn.home_rank()).bitboard() {
|
||||
castling_rights.unset(*turn, CastlingSide::Long);
|
||||
}
|
||||
}
|
||||
Role::Pawn => {
|
||||
setup.p_b_q |= to;
|
||||
*p_b_q |= to;
|
||||
}
|
||||
}
|
||||
if setup.turn == Color::White {
|
||||
setup.w |= to;
|
||||
if let Color::White = *turn {
|
||||
*w |= to;
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn aux_play_pawn_advance(setup: &mut Setup, role: Role, from: Square, to: Square) {
|
||||
fn aux_play_pawn_advance(
|
||||
Setup {
|
||||
bitboards: [p_b_q, n_b_k, r_q_k, w],
|
||||
turn,
|
||||
en_passant: _,
|
||||
castling_rights: _,
|
||||
}: &mut Setup,
|
||||
role: Role,
|
||||
from: Square,
|
||||
to: Square,
|
||||
) {
|
||||
let from = from.bitboard();
|
||||
let to = to.bitboard();
|
||||
match role {
|
||||
Role::King => unreachable!(),
|
||||
Role::Queen => {
|
||||
setup.p_b_q ^= from | to;
|
||||
setup.r_q_k |= to;
|
||||
*p_b_q ^= from | to;
|
||||
*r_q_k |= to;
|
||||
}
|
||||
Role::Bishop => {
|
||||
setup.p_b_q ^= from | to;
|
||||
setup.n_b_k |= to;
|
||||
*p_b_q ^= from | to;
|
||||
*n_b_k |= to;
|
||||
}
|
||||
Role::Knight => {
|
||||
setup.p_b_q ^= from;
|
||||
setup.n_b_k |= to;
|
||||
*p_b_q ^= from;
|
||||
*n_b_k |= to;
|
||||
}
|
||||
Role::Rook => {
|
||||
setup.p_b_q ^= from;
|
||||
setup.r_q_k |= to;
|
||||
*p_b_q ^= from;
|
||||
*r_q_k |= to;
|
||||
}
|
||||
Role::Pawn => setup.p_b_q ^= from | to,
|
||||
Role::Pawn => *p_b_q ^= from | to,
|
||||
}
|
||||
if setup.turn == Color::White {
|
||||
setup.w ^= from | to;
|
||||
if let Color::White = *turn {
|
||||
*w ^= from | to;
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn aux_play_castle(setup: &mut Setup, side: CastlingSide) {
|
||||
let rank = setup.turn.home_rank();
|
||||
fn aux_play_castle(
|
||||
Setup {
|
||||
bitboards: [_, n_b_k, r_q_k, w],
|
||||
turn,
|
||||
en_passant: _,
|
||||
castling_rights,
|
||||
}: &mut Setup,
|
||||
side: CastlingSide,
|
||||
) {
|
||||
let rank = turn.home_rank();
|
||||
let (king_flip, rook_flip) = match side {
|
||||
CastlingSide::Short => (
|
||||
Square::from_coords(File::E, rank).bitboard()
|
||||
|
|
@ -1044,14 +1075,14 @@ fn aux_play_castle(setup: &mut Setup, side: CastlingSide) {
|
|||
),
|
||||
};
|
||||
|
||||
if setup.turn == Color::White {
|
||||
setup.w ^= king_flip | rook_flip;
|
||||
if let Color::White = *turn {
|
||||
*w ^= king_flip | rook_flip;
|
||||
}
|
||||
setup.n_b_k ^= king_flip;
|
||||
setup.r_q_k ^= king_flip | rook_flip;
|
||||
*n_b_k ^= king_flip;
|
||||
*r_q_k ^= king_flip | rook_flip;
|
||||
|
||||
setup.castling_rights.unset(setup.turn, CastlingSide::Short);
|
||||
setup.castling_rights.unset(setup.turn, CastlingSide::Long);
|
||||
castling_rights.unset(*turn, CastlingSide::Short);
|
||||
castling_rights.unset(*turn, CastlingSide::Long);
|
||||
}
|
||||
|
||||
pub(crate) struct MateMoveGenImpl {
|
||||
|
|
|
|||
152
src/setup.rs
152
src/setup.rs
|
|
@ -29,12 +29,8 @@ use alloc::string::String;
|
|||
/// [`from_text_record`](Setup::from_text_record) and [`to_text_record`](Setup::to_text_record).
|
||||
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct Setup {
|
||||
pub(crate) w: Bitboard,
|
||||
|
||||
pub(crate) p_b_q: Bitboard,
|
||||
pub(crate) n_b_k: Bitboard,
|
||||
pub(crate) r_q_k: Bitboard,
|
||||
|
||||
/// bitboards = [pawns | bishops | queens, knights | bishops | kings, rooks | queens | kings, white]
|
||||
pub(crate) bitboards: [Bitboard; 4],
|
||||
pub(crate) turn: Color,
|
||||
pub(crate) en_passant: OptionSquare,
|
||||
pub(crate) castling_rights: CastlingRights,
|
||||
|
|
@ -45,10 +41,7 @@ impl Setup {
|
|||
#[inline]
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
w: Bitboard(0),
|
||||
p_b_q: Bitboard(0),
|
||||
n_b_k: Bitboard(0),
|
||||
r_q_k: Bitboard(0),
|
||||
bitboards: [Bitboard(0); 4],
|
||||
turn: Color::White,
|
||||
en_passant: OptionSquare::None,
|
||||
castling_rights: CastlingRights::new(),
|
||||
|
|
@ -232,9 +225,9 @@ impl Setup {
|
|||
pub fn get(&self, square: Square) -> Option<Piece> {
|
||||
Some(Piece {
|
||||
role: self.role(square)?,
|
||||
color: match (self.w & square.bitboard()).is_empty() {
|
||||
false => Color::White,
|
||||
true => Color::Black,
|
||||
color: match self.is_white(square) {
|
||||
true => Color::White,
|
||||
false => Color::Black,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
|
@ -261,39 +254,40 @@ impl Setup {
|
|||
#[inline]
|
||||
pub fn set(&mut self, square: Square, piece: Option<Piece>) {
|
||||
let mask = !square.bitboard();
|
||||
self.w &= mask;
|
||||
self.p_b_q &= mask;
|
||||
self.n_b_k &= mask;
|
||||
self.r_q_k &= mask;
|
||||
let [p_b_q, n_b_k, r_q_k, w] = &mut self.bitboards;
|
||||
*p_b_q &= mask;
|
||||
*n_b_k &= mask;
|
||||
*r_q_k &= mask;
|
||||
*w &= mask;
|
||||
if let Some(piece) = piece {
|
||||
let to = square.bitboard();
|
||||
match piece.color {
|
||||
Color::White => self.w |= to,
|
||||
Color::Black => (),
|
||||
}
|
||||
match piece.role {
|
||||
Role::Pawn => {
|
||||
self.p_b_q |= to;
|
||||
*p_b_q |= to;
|
||||
}
|
||||
Role::Knight => {
|
||||
self.n_b_k |= to;
|
||||
*n_b_k |= to;
|
||||
}
|
||||
Role::Bishop => {
|
||||
self.p_b_q |= to;
|
||||
self.n_b_k |= to;
|
||||
*p_b_q |= to;
|
||||
*n_b_k |= to;
|
||||
}
|
||||
Role::Rook => {
|
||||
self.r_q_k |= to;
|
||||
*r_q_k |= to;
|
||||
}
|
||||
Role::Queen => {
|
||||
self.p_b_q |= to;
|
||||
self.r_q_k |= to;
|
||||
*p_b_q |= to;
|
||||
*r_q_k |= to;
|
||||
}
|
||||
Role::King => {
|
||||
self.n_b_k |= to;
|
||||
self.r_q_k |= to;
|
||||
*n_b_k |= to;
|
||||
*r_q_k |= to;
|
||||
}
|
||||
}
|
||||
match piece.color {
|
||||
Color::White => *w |= to,
|
||||
Color::Black => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -318,38 +312,16 @@ impl Setup {
|
|||
self.en_passant = OptionSquare::new(square);
|
||||
}
|
||||
|
||||
/// Returns, for each color and each type of piece, the bitboard of all squares occupied.
|
||||
/// Returns the quad-bitboard representation of the board.
|
||||
///
|
||||
/// This returns, in order:
|
||||
/// - the squares occupied by the pawns, bishops and queens
|
||||
/// - the squares occupied by the knights, bishops and kings
|
||||
/// - the squares occupied by the rooks, queens and kings
|
||||
/// - the squares occupied by the white pieces
|
||||
#[inline]
|
||||
pub fn bitboards(&self) -> ByColor<ByRole<Bitboard>> {
|
||||
let Self {
|
||||
w,
|
||||
p_b_q,
|
||||
n_b_k,
|
||||
r_q_k,
|
||||
..
|
||||
} = self.clone();
|
||||
let k = n_b_k & r_q_k;
|
||||
let q = p_b_q & r_q_k;
|
||||
let b = p_b_q & n_b_k;
|
||||
let n = n_b_k ^ b ^ k;
|
||||
let r = r_q_k ^ q ^ k;
|
||||
let p = p_b_q ^ b ^ q;
|
||||
ByColor::with(|color| {
|
||||
let mask = match color {
|
||||
Color::White => w,
|
||||
Color::Black => !w,
|
||||
};
|
||||
ByRole::with(|role| {
|
||||
mask & match role {
|
||||
Role::Pawn => p,
|
||||
Role::Knight => n,
|
||||
Role::Bishop => b,
|
||||
Role::Rook => r,
|
||||
Role::Queen => q,
|
||||
Role::King => k,
|
||||
}
|
||||
})
|
||||
})
|
||||
pub fn bitboards(&self) -> [Bitboard; 4] {
|
||||
self.bitboards
|
||||
}
|
||||
|
||||
/// Returns the mirror image of the position.
|
||||
|
|
@ -362,11 +334,14 @@ impl Setup {
|
|||
/// is `rnbqkbnr/pppp1ppp/8/4p3/8/8/PPPPPPPP/RNBQKBNR w Qk e6`.
|
||||
#[inline]
|
||||
pub fn mirror(&self) -> Self {
|
||||
let [p_b_q, n_b_k, r_q_k, w] = self.bitboards;
|
||||
Self {
|
||||
w: (self.w ^ (self.p_b_q | self.n_b_k | self.r_q_k)).mirror(),
|
||||
p_b_q: self.p_b_q.mirror(),
|
||||
n_b_k: self.n_b_k.mirror(),
|
||||
r_q_k: self.r_q_k.mirror(),
|
||||
bitboards: [
|
||||
p_b_q.mirror(),
|
||||
n_b_k.mirror(),
|
||||
r_q_k.mirror(),
|
||||
(w ^ (p_b_q | n_b_k | r_q_k)).mirror(),
|
||||
],
|
||||
turn: !self.turn,
|
||||
en_passant: self
|
||||
.en_passant
|
||||
|
|
@ -381,13 +356,37 @@ impl Setup {
|
|||
///
|
||||
/// Some unreachable positions are rejected, see [`IllegalPositionReason`] for details.
|
||||
pub fn into_position(self) -> Result<Position, IllegalPosition> {
|
||||
debug_assert!((self.w & !(self.p_b_q | self.n_b_k | self.r_q_k)).is_empty());
|
||||
debug_assert!((self.p_b_q & self.n_b_k & self.r_q_k).is_empty());
|
||||
|
||||
let mut reasons = IllegalPositionReasons::new();
|
||||
|
||||
let blockers = self.p_b_q | self.n_b_k | self.r_q_k;
|
||||
let pieces = self.bitboards();
|
||||
let [p_b_q, n_b_k, r_q_k, w] = self.bitboards;
|
||||
|
||||
debug_assert!((!(p_b_q | n_b_k | r_q_k) & w).is_empty());
|
||||
debug_assert!((p_b_q & n_b_k & r_q_k).is_empty());
|
||||
|
||||
let k = n_b_k & r_q_k;
|
||||
let q = p_b_q & r_q_k;
|
||||
let b = p_b_q & n_b_k;
|
||||
let n = n_b_k ^ b ^ k;
|
||||
let r = r_q_k ^ q ^ k;
|
||||
let p = p_b_q ^ b ^ q;
|
||||
let pieces = ByColor::with(|color| {
|
||||
let mask = match color {
|
||||
Color::White => w,
|
||||
Color::Black => !w,
|
||||
};
|
||||
ByRole::with(|role| {
|
||||
mask & match role {
|
||||
Role::Pawn => p,
|
||||
Role::Knight => n,
|
||||
Role::Bishop => b,
|
||||
Role::Rook => r,
|
||||
Role::Queen => q,
|
||||
Role::King => k,
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
let blockers = p_b_q | n_b_k | r_q_k;
|
||||
|
||||
if Color::all()
|
||||
.into_iter()
|
||||
|
|
@ -508,14 +507,21 @@ impl Setup {
|
|||
#[inline]
|
||||
pub(crate) fn role(&self, square: Square) -> Option<Role> {
|
||||
let mask = square.bitboard();
|
||||
let bit0 = (self.p_b_q & mask).0 >> square as u8;
|
||||
let bit1 = (self.n_b_k & mask).0 >> square as u8;
|
||||
let bit2 = (self.r_q_k & mask).0 >> square as u8;
|
||||
let [p_b_q, n_b_k, r_q_k, _] = self.bitboards;
|
||||
let bit0 = (p_b_q & mask).0 >> square as u8;
|
||||
let bit1 = (n_b_k & mask).0 >> square as u8;
|
||||
let bit2 = (r_q_k & mask).0 >> square as u8;
|
||||
match bit0 | bit1 << 1 | bit2 << 2 {
|
||||
0 => None,
|
||||
i => Some(unsafe { Role::transmute(i as u8) }),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn is_white(&self, square: Square) -> bool {
|
||||
let [_, _, _, w] = self.bitboards;
|
||||
w.contains(square)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct TextRecord<'a>(pub(crate) &'a Setup);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue