1
0
Fork 0

update board representation

This commit is contained in:
Paul-Nicolas Madelaine 2025-11-26 23:03:23 +01:00
parent 9a74ac0123
commit 85c7c8eb52
3 changed files with 184 additions and 147 deletions

View file

@ -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);