1
0
Fork 0

new quad-bitboard representation

This commit is contained in:
Paul-Nicolas Madelaine 2025-11-29 14:12:20 +01:00
parent 57b78880f2
commit 4c137d3c95
3 changed files with 43 additions and 39 deletions

View file

@ -73,6 +73,12 @@ impl Color {
Self::Black => Direction::South, Self::Black => Direction::South,
} }
} }
#[inline]
pub(crate) unsafe fn new_unchecked(color: u8) -> Self {
debug_assert!(color < 2);
unsafe { core::mem::transmute(color) }
}
} }
impl core::ops::Not for Color { impl core::ops::Not for Color {

View file

@ -90,7 +90,7 @@ impl Position {
Bitboard(0x2CFF00000000FF2C), Bitboard(0x2CFF00000000FF2C),
Bitboard(0x7600000000000076), Bitboard(0x7600000000000076),
Bitboard(0x9900000000000099), Bitboard(0x9900000000000099),
Bitboard(0x000000000000FFFF), Bitboard(0xFFFF000000000000),
], ],
turn: Color::White, turn: Color::White,
castling_rights: CastlingRights::full(), castling_rights: CastlingRights::full(),
@ -230,7 +230,7 @@ impl Position {
/// play and discards the en passant square. /// play and discards the en passant square.
pub fn pass(&self) -> Option<Self> { pub fn pass(&self) -> Option<Self> {
let Setup { let Setup {
bitboards: [p_b_q, n_b_k, r_q_k, w], bitboards: [p_b_q, n_b_k, r_q_k, black],
turn, turn,
en_passant: _, en_passant: _,
castling_rights: _, castling_rights: _,
@ -243,8 +243,8 @@ impl Position {
let r = r_q_k ^ q ^ k; let r = r_q_k ^ q ^ k;
let p = p_b_q ^ b ^ q; let p = p_b_q ^ b ^ q;
let (us, them) = match turn { let (us, them) = match turn {
Color::White => (w, blockers ^ w), Color::White => (blockers ^ black, black),
Color::Black => (blockers ^ w, w), Color::Black => (black, blockers ^ black),
}; };
let king_square = (us & k).next().unwrap(); let king_square = (us & k).next().unwrap();
let checkers = them let checkers = them
@ -580,7 +580,7 @@ impl Position {
let global_mask_to = moves.to(); let global_mask_to = moves.to();
let Setup { let Setup {
bitboards: [p_b_q, n_b_k, r_q_k, w], bitboards: [p_b_q, n_b_k, r_q_k, black],
turn, turn,
en_passant, en_passant,
castling_rights, castling_rights,
@ -588,8 +588,8 @@ impl Position {
let blockers = p_b_q | n_b_k | r_q_k; let blockers = p_b_q | n_b_k | r_q_k;
let (us, them) = match turn { let (us, them) = match turn {
Color::White => (w, blockers ^ w), Color::White => (blockers ^ black, black),
Color::Black => (blockers ^ w, w), Color::Black => (black, blockers ^ black),
}; };
let k = n_b_k & r_q_k; let k = n_b_k & r_q_k;
@ -938,9 +938,9 @@ impl Position {
MoveType::EnPassant => { MoveType::EnPassant => {
let direction = !setup.turn.forward(); let direction = !setup.turn.forward();
let x = (unsafe { to.trans_unchecked(direction) }).bitboard(); let x = (unsafe { to.trans_unchecked(direction) }).bitboard();
let [p_b_q, _, _, w] = &mut setup.bitboards; let [p_b_q, _, _, black] = &mut setup.bitboards;
*p_b_q ^= x; *p_b_q ^= x;
*w &= !x; *black &= !x;
aux_play_pawn_advance(setup, Role::Pawn, from, to); aux_play_pawn_advance(setup, Role::Pawn, from, to);
} }
} }
@ -952,7 +952,7 @@ impl Position {
#[inline] #[inline]
fn aux_play_normal( fn aux_play_normal(
Setup { Setup {
bitboards: [p_b_q, n_b_k, r_q_k, w], bitboards: [p_b_q, n_b_k, r_q_k, black],
turn, turn,
en_passant: _, en_passant: _,
castling_rights, castling_rights,
@ -967,7 +967,7 @@ fn aux_play_normal(
*p_b_q &= mask; *p_b_q &= mask;
*n_b_k &= mask; *n_b_k &= mask;
*r_q_k &= mask; *r_q_k &= mask;
*w &= mask; *black &= mask;
if target == Square::from_coords(File::H, turn.promotion_rank()) { if target == Square::from_coords(File::H, turn.promotion_rank()) {
castling_rights.unset(!*turn, CastlingSide::Short); castling_rights.unset(!*turn, CastlingSide::Short);
} }
@ -1005,15 +1005,15 @@ fn aux_play_normal(
*p_b_q |= to; *p_b_q |= to;
} }
} }
if let Color::White = *turn { if let Color::Black = *turn {
*w |= to; *black |= to;
} }
} }
#[inline] #[inline]
fn aux_play_pawn_advance( fn aux_play_pawn_advance(
Setup { Setup {
bitboards: [p_b_q, n_b_k, r_q_k, w], bitboards: [p_b_q, n_b_k, r_q_k, black],
turn, turn,
en_passant: _, en_passant: _,
castling_rights: _, castling_rights: _,
@ -1044,15 +1044,15 @@ fn aux_play_pawn_advance(
} }
Role::Pawn => *p_b_q ^= from | to, Role::Pawn => *p_b_q ^= from | to,
} }
if let Color::White = *turn { if let Color::Black = *turn {
*w ^= from | to; *black ^= from | to;
} }
} }
#[inline] #[inline]
fn aux_play_castle( fn aux_play_castle(
Setup { Setup {
bitboards: [_, n_b_k, r_q_k, w], bitboards: [_, n_b_k, r_q_k, black],
turn, turn,
en_passant: _, en_passant: _,
castling_rights, castling_rights,
@ -1075,8 +1075,8 @@ fn aux_play_castle(
), ),
}; };
if let Color::White = *turn { if let Color::Black = *turn {
*w ^= king_flip | rook_flip; *black ^= king_flip | rook_flip;
} }
*n_b_k ^= king_flip; *n_b_k ^= king_flip;
*r_q_k ^= king_flip | rook_flip; *r_q_k ^= king_flip | rook_flip;

View file

@ -29,7 +29,7 @@ use alloc::string::String;
/// [`from_text_record`](Setup::from_text_record) and [`to_text_record`](Setup::to_text_record). /// [`from_text_record`](Setup::from_text_record) and [`to_text_record`](Setup::to_text_record).
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)] #[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct Setup { pub struct Setup {
/// bitboards = [pawns | bishops | queens, knights | bishops | kings, rooks | queens | kings, white] /// bitboards = [pawns | bishops | queens, knights | bishops | kings, rooks | queens | kings, black]
pub(crate) bitboards: [Bitboard; 4], pub(crate) bitboards: [Bitboard; 4],
pub(crate) turn: Color, pub(crate) turn: Color,
pub(crate) en_passant: OptionSquare, pub(crate) en_passant: OptionSquare,
@ -221,15 +221,12 @@ impl Setup {
Ok(()) Ok(())
} }
/// Returns the occupancy of a square. /// Returns the piece on the square, if any.
#[inline] #[inline]
pub fn get(&self, square: Square) -> Option<Piece> { pub fn get(&self, square: Square) -> Option<Piece> {
Some(Piece { Some(Piece {
role: self.role(square)?, role: self.role(square)?,
color: match self.is_white(square) { color: self.color(square),
true => Color::White,
false => Color::Black,
},
}) })
} }
@ -255,11 +252,11 @@ impl Setup {
#[inline] #[inline]
pub fn set(&mut self, square: Square, piece: Option<Piece>) { pub fn set(&mut self, square: Square, piece: Option<Piece>) {
let mask = !square.bitboard(); let mask = !square.bitboard();
let [p_b_q, n_b_k, r_q_k, w] = &mut self.bitboards; let [p_b_q, n_b_k, r_q_k, black] = &mut self.bitboards;
*p_b_q &= mask; *p_b_q &= mask;
*n_b_k &= mask; *n_b_k &= mask;
*r_q_k &= mask; *r_q_k &= mask;
*w &= mask; *black &= mask;
if let Some(piece) = piece { if let Some(piece) = piece {
let to = square.bitboard(); let to = square.bitboard();
match piece.role { match piece.role {
@ -286,8 +283,8 @@ impl Setup {
} }
} }
match piece.color { match piece.color {
Color::White => *w |= to, Color::White => (),
Color::Black => (), Color::Black => *black |= to,
} }
} }
} }
@ -319,7 +316,7 @@ impl Setup {
/// - pawns, bishops and queens /// - pawns, bishops and queens
/// - knights, bishops and kings /// - knights, bishops and kings
/// - rooks, queens and kings /// - rooks, queens and kings
/// - white pieces /// - black pieces
#[inline] #[inline]
pub fn bitboards(&self) -> [Bitboard; 4] { pub fn bitboards(&self) -> [Bitboard; 4] {
self.bitboards self.bitboards
@ -335,13 +332,13 @@ impl Setup {
/// is `rnbqkbnr/pppp1ppp/8/4p3/8/8/PPPPPPPP/RNBQKBNR w Qk e6`. /// is `rnbqkbnr/pppp1ppp/8/4p3/8/8/PPPPPPPP/RNBQKBNR w Qk e6`.
#[inline] #[inline]
pub fn mirror(&self) -> Self { pub fn mirror(&self) -> Self {
let [p_b_q, n_b_k, r_q_k, w] = self.bitboards; let [p_b_q, n_b_k, r_q_k, black] = self.bitboards;
Self { Self {
bitboards: [ bitboards: [
p_b_q.mirror(), p_b_q.mirror(),
n_b_k.mirror(), n_b_k.mirror(),
r_q_k.mirror(), r_q_k.mirror(),
(w ^ (p_b_q | n_b_k | r_q_k)).mirror(), (black ^ (p_b_q | n_b_k | r_q_k)).mirror(),
], ],
turn: !self.turn, turn: !self.turn,
en_passant: self en_passant: self
@ -359,9 +356,9 @@ impl Setup {
pub fn into_position(self) -> Result<Position, IllegalPosition> { pub fn into_position(self) -> Result<Position, IllegalPosition> {
let mut reasons = IllegalPositionReasons::new(); let mut reasons = IllegalPositionReasons::new();
let [p_b_q, n_b_k, r_q_k, w] = self.bitboards; let [p_b_q, n_b_k, r_q_k, black] = 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) & black).is_empty());
debug_assert!((p_b_q & n_b_k & r_q_k).is_empty()); debug_assert!((p_b_q & n_b_k & r_q_k).is_empty());
let k = n_b_k & r_q_k; let k = n_b_k & r_q_k;
@ -372,8 +369,8 @@ impl Setup {
let p = p_b_q ^ b ^ q; let p = p_b_q ^ b ^ q;
let pieces = ByColor::with(|color| { let pieces = ByColor::with(|color| {
let mask = match color { let mask = match color {
Color::White => w, Color::White => !black,
Color::Black => !w, Color::Black => black,
}; };
ByRole::with(|role| { ByRole::with(|role| {
mask & match role { mask & match role {
@ -518,10 +515,11 @@ impl Setup {
} }
} }
/// Returns the color of the piece on the square if any, and `Black` if the square is not occupied.
#[inline] #[inline]
pub(crate) fn is_white(&self, square: Square) -> bool { pub(crate) fn color(&self, square: Square) -> Color {
let [_, _, _, w] = self.bitboards; let [_, _, _, black] = self.bitboards;
w.contains(square) unsafe { Color::new_unchecked(((black & square.bitboard()).0 >> square as u8) as u8) }
} }
} }