From bf6cc961dcdcd268f9638a5c53919100849d96cd Mon Sep 17 00:00:00 2001 From: Paul-Nicolas Madelaine Date: Mon, 3 Nov 2025 16:56:49 +0100 Subject: [PATCH] wip --- src/board.rs | 173 ++++++++++++++++++++++++++++++-------------------- src/lookup.rs | 26 ++++---- src/setup.rs | 9 ++- 3 files changed, 122 insertions(+), 86 deletions(-) diff --git a/src/board.rs b/src/board.rs index 1794cdd..2cc880e 100644 --- a/src/board.rs +++ b/src/board.rs @@ -3,28 +3,31 @@ use crate::bitboard::*; macro_rules! container { - ($a:ident, $b:ident, $n:literal) => { + ($v:vis, $a:ident, $b:ident, $n:literal) => { #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] - pub(crate) struct $b(pub(crate) [T; $n]); + $v struct $b(pub(crate) [T; $n]); #[allow(unused)] impl $b { #[inline] - pub fn new(f: F) -> Self + pub const fn new(values: [T; $n]) -> Self { + Self(values) + } + #[inline] + pub fn with(f: F) -> Self where F: FnMut($a) -> T, { Self($a::all().map(f)) } #[inline] - pub fn get(&self, k: $a) -> &T { - unsafe { self.0.get_unchecked(k as usize) } + pub const fn get(&self, k: $a) -> &T { + // unsafe { self.0.get_unchecked(k as usize) } + &self.0[k as usize] } #[inline] - pub fn get_mut(&mut self, k: $a) -> &mut T { - unsafe { self.0.get_unchecked_mut(k as usize) } - } - pub(crate) const fn get_const(&self, k: $a) -> &T { - &self.0[k as usize] + pub const fn get_mut(&mut self, k: $a) -> &mut T { + // unsafe { self.0.get_unchecked_mut(k as usize) } + &mut self.0[k as usize] } } }; @@ -38,11 +41,11 @@ pub enum Color { Black, } -container!(Color, ByColor, 2); +container!(pub, Color, ByColor, 2); impl Color { #[inline] - pub fn all() -> [Self; 2] { + pub const fn all() -> [Self; 2] { [Self::White, Self::Black] } @@ -96,11 +99,11 @@ pub enum File { H, } -container!(File, ByFile, 8); +container!(pub(crate), File, ByFile, 8); impl File { #[inline] - pub fn all() -> [Self; 8] { + pub const fn all() -> [Self; 8] { [ Self::A, Self::B, @@ -114,7 +117,35 @@ impl File { } #[inline] - pub fn to_char(self) -> char { + pub const fn new(_index: u8) -> Option { + todo!() + } + + #[inline] + pub const unsafe fn new_unchecked(index: u8) -> Self { + debug_assert!(index < 8); + std::mem::transmute(index) + } + + #[inline] + pub const fn to_ascii(self) -> u8 { + self as u8 + b'a' + } + + #[inline] + pub const fn from_ascii(c: u8) -> Option { + if c <= b'h' { + match c.checked_sub(b'a') { + Some(i) => Some(unsafe { Self::new_unchecked(i) }), + None => None, + } + } else { + None + } + } + + #[inline] + pub const fn to_char(self) -> char { self.to_ascii() as char } @@ -123,28 +154,10 @@ impl File { u8::try_from(file).ok().and_then(Self::from_ascii) } - #[inline] - pub(crate) fn to_ascii(self) -> u8 { - self as u8 + b'a' - } - - #[inline] - pub(crate) fn from_ascii(c: u8) -> Option { - (c <= b'h') - .then(|| c.checked_sub(b'a').map(|i| unsafe { Self::transmute(i) })) - .flatten() - } - #[inline] pub(crate) const fn bitboard(self) -> Bitboard { Bitboard(0x0101010101010101 << (self as u8)) } - - #[inline] - pub(crate) const unsafe fn transmute(value: u8) -> Self { - debug_assert!(value < 8); - std::mem::transmute(value) - } } impl std::fmt::Display for File { @@ -168,11 +181,11 @@ pub enum Rank { Eighth, } -container!(Rank, ByRank, 8); +container!(pub(crate), Rank, ByRank, 8); impl Rank { #[inline] - pub fn all() -> [Self; 8] { + pub const fn all() -> [Self; 8] { [ Self::First, Self::Second, @@ -186,7 +199,35 @@ impl Rank { } #[inline] - pub fn to_char(self) -> char { + pub const fn new(_index: u8) -> Option { + todo!() + } + + #[inline] + pub const unsafe fn new_unchecked(index: u8) -> Self { + debug_assert!(index < 8); + std::mem::transmute(index) + } + + #[inline] + pub const fn to_ascii(self) -> u8 { + self as u8 + b'1' + } + + #[inline] + pub const fn from_ascii(c: u8) -> Option { + if c <= b'8' { + match c.checked_sub(b'1') { + Some(i) => Some(unsafe { Self::new_unchecked(i) }), + None => None, + } + } else { + None + } + } + + #[inline] + pub const fn to_char(self) -> char { self.to_ascii() as char } @@ -196,32 +237,14 @@ impl Rank { } #[inline] - pub fn mirror(self) -> Self { - unsafe { Self::transmute(!(self as u8)) } - } - - #[inline] - pub(crate) fn to_ascii(self) -> u8 { - self as u8 + b'1' - } - - #[inline] - pub(crate) fn from_ascii(c: u8) -> Option { - (c <= b'8') - .then(|| c.checked_sub(b'1').map(|i| unsafe { Self::transmute(i) })) - .flatten() + pub const fn mirror(self) -> Self { + unsafe { Self::new_unchecked(!(self as u8)) } } #[inline] pub(crate) const fn bitboard(self) -> Bitboard { Bitboard(0xFF << ((self as u64) << 3)) } - - #[inline] - pub(crate) const unsafe fn transmute(value: u8) -> Self { - debug_assert!(value < 8); - std::mem::transmute(value) - } } impl std::fmt::Display for Rank { @@ -246,12 +269,12 @@ pub enum Square{ A8, B8, C8, D8, E8, F8, G8, H8, } -container!(Square, BySquare, 64); +container!(pub, Square, BySquare, 64); impl Square { #[inline] #[rustfmt::skip] - pub fn all() -> [Self; 64] { + pub const fn all() -> [Self; 64] { [ Self::A1, Self::B1, Self::C1, Self::D1, Self::E1, Self::F1, Self::G1, Self::H1, Self::A2, Self::B2, Self::C2, Self::D2, Self::E2, Self::F2, Self::G2, Self::H2, @@ -282,22 +305,22 @@ impl Square { } #[inline] - pub fn from_coords(file: File, rank: Rank) -> Self { + pub const fn from_coords(file: File, rank: Rank) -> Self { unsafe { Self::new_unchecked(((rank as u8) << 3) | file as u8) } } #[inline] pub const fn file(self) -> File { - unsafe { File::transmute((self as u8) & 7) } + unsafe { File::new_unchecked((self as u8) & 7) } } #[inline] pub const fn rank(self) -> Rank { - unsafe { Rank::transmute((self as u8) >> 3) } + unsafe { Rank::new_unchecked((self as u8) >> 3) } } #[inline] - pub fn mirror(self) -> Self { + pub const fn mirror(self) -> Self { let sq = self as u8; unsafe { Self::new_unchecked(sq & 0b000111 | (!sq & 0b111000)) } } @@ -465,7 +488,7 @@ pub enum Role { impl Role { #[inline] - pub fn all() -> [Self; 6] { + pub const fn all() -> [Self; 6] { [ Self::Pawn, Self::Knight, @@ -525,7 +548,7 @@ pub(crate) struct ByRole(pub(crate) [T; 6]); #[allow(unused)] impl ByRole { #[inline] - pub fn new(f: F) -> Self + pub fn with(f: F) -> Self where F: FnMut(Role) -> T, { @@ -533,13 +556,23 @@ impl ByRole { } #[inline] - pub fn get(&self, kind: Role) -> &T { - unsafe { self.0.get_unchecked((kind as usize).unchecked_sub(1)) } + pub const fn new(values: [T; 6]) -> Self { + Self(values) } #[inline] - pub fn get_mut(&mut self, kind: Role) -> &mut T { - unsafe { self.0.get_unchecked_mut((kind as usize).unchecked_sub(1)) } + pub const fn get(&self, kind: Role) -> &T { + // unsafe { self.0.get_unchecked((kind as usize).unchecked_sub(1)) } + let i = unsafe { (kind as usize).unchecked_sub(1) }; + unsafe { std::hint::assert_unchecked(i < 6) }; + &self.0[i] + } + + #[inline] + pub const fn get_mut(&mut self, kind: Role) -> &mut T { + let i = unsafe { (kind as usize).unchecked_sub(1) }; + unsafe { std::hint::assert_unchecked(i < 6) }; + &mut self.0[i] } } @@ -593,7 +626,7 @@ pub(crate) enum Direction { West, } -container!(Direction, ByDirection, 8); +container!(pub(crate), Direction, ByDirection, 8); impl Direction { #[inline] @@ -644,7 +677,7 @@ pub enum CastlingSide { Long, } -container!(CastlingSide, ByCastlingSide, 2); +container!(pub(crate), CastlingSide, ByCastlingSide, 2); impl CastlingSide { #[inline] diff --git a/src/lookup.rs b/src/lookup.rs index 743ee42..64c7c13 100644 --- a/src/lookup.rs +++ b/src/lookup.rs @@ -127,7 +127,7 @@ static LINES: BySquare> = by_square!(a, BySquare([Bitboard(0) by_square!(b, Bitboard(0), { let mut res = Bitboard(0); loop_all_directions!(d, { - let r = *RAYS.get_const(a).get_const(d); + let r = *RAYS.get(a).get(d); if r.contains(b) { res = r; } @@ -140,9 +140,9 @@ static SEGMENTS: BySquare> = by_square!(a, BySquare([Bitboard by_square!(b, Bitboard(0), { let mut res = 0; loop_all_directions!(d, { - let r = *RAYS.get_const(a).get_const(d); + let r = *RAYS.get(a).get(d); if r.contains(b) { - res = r.0 & !RAYS.get_const(b).get_const(d).0; + res = r.0 & !RAYS.get(b).get(d).0; } }); Bitboard(res | b.bitboard().0) @@ -218,7 +218,7 @@ static PAWN_ATTACKS: ByColor> = { }; const fn blocked_ray(square: Square, direction: Direction, blockers: Bitboard) -> Bitboard { - let ray = *RAYS.get_const(square).get_const(direction); + let ray = *RAYS.get(square).get(direction); let blockers = Bitboard(blockers.0 & ray.0); let square = if (direction as u8) < 4 { Bitboard::first(&blockers) @@ -227,7 +227,7 @@ const fn blocked_ray(square: Square, direction: Direction, blockers: Bitboard) - }; match square { None => ray, - Some(square) => Bitboard(ray.0 & !RAYS.get_const(square).get_const(direction).0), + Some(square) => Bitboard(ray.0 & !RAYS.get(square).get(direction).0), } } @@ -259,7 +259,7 @@ pub(crate) fn pawn_attack(color: Color, square: Square) -> Bitboard { const fn bishop_premask(square: Square) -> Bitboard { let mut premask = 0; loop_bishop_directions!(direction, { - premask |= RAYS.get_const(square).get_const(direction).0; + premask |= RAYS.get(square).get(direction).0; }); premask &= !Rank::First.bitboard().0; premask &= !Rank::Eighth.bitboard().0; @@ -269,12 +269,12 @@ const fn bishop_premask(square: Square) -> Bitboard { } const fn rook_premask(square: Square) -> Bitboard { - let rays = RAYS.get_const(square); + let rays = RAYS.get(square); let mut premask = 0; - premask |= rays.get_const(Direction::East).0 & !File::H.bitboard().0; - premask |= rays.get_const(Direction::North).0 & !Rank::Eighth.bitboard().0; - premask |= rays.get_const(Direction::West).0 & !File::A.bitboard().0; - premask |= rays.get_const(Direction::South).0 & !Rank::First.bitboard().0; + premask |= rays.get(Direction::East).0 & !File::H.bitboard().0; + premask |= rays.get(Direction::North).0 & !Rank::Eighth.bitboard().0; + premask |= rays.get(Direction::West).0 & !File::A.bitboard().0; + premask |= rays.get(Direction::South).0 & !Rank::First.bitboard().0; Bitboard(premask) } @@ -360,7 +360,7 @@ static MAGIC_TABLE: [Bitboard; MAGICS.2] = { premask, factor, offset, - } = *MAGICS.0.get_const(square); + } = *MAGICS.0.get(square); let premask = !premask.0; loop_subsets!(premask, blockers, { let index = (hash(BISHOP_SHR, factor, Bitboard(blockers | !premask)) as isize + offset) @@ -378,7 +378,7 @@ static MAGIC_TABLE: [Bitboard; MAGICS.2] = { premask, factor, offset, - } = *MAGICS.1.get_const(square); + } = *MAGICS.1.get(square); let premask = !premask.0; loop_subsets!(premask, blockers, { let index = diff --git a/src/setup.rs b/src/setup.rs index eb30431..d9ca758 100644 --- a/src/setup.rs +++ b/src/setup.rs @@ -92,7 +92,10 @@ impl Setup { (file < 8).then_some(())?; setup.set( unsafe { - Square::from_coords(File::transmute(file), Rank::transmute(rank)) + Square::from_coords( + File::new_unchecked(file), + Rank::new_unchecked(rank), + ) }, Some(Piece { role, color }), ); @@ -495,12 +498,12 @@ impl Setup { let n = n_b_k ^ b ^ k; let r = r_q_k ^ q ^ k; let p = p_b_q ^ b ^ q; - ByColor::new(|color| { + ByColor::with(|color| { let mask = match color { Color::White => w, Color::Black => !w, }; - ByRole::new(|kind| { + ByRole::with(|kind| { mask & match kind { Role::Pawn => p, Role::Knight => n,