diff --git a/src/board/parser.rs b/src/board/parser.rs index 1a5cfc1ad..f0b1c77bb 100644 --- a/src/board/parser.rs +++ b/src/board/parser.rs @@ -1,7 +1,7 @@ use super::Board; use crate::{ - lookup::between, - types::{CastlingKind, Color, Piece, PieceType, Square}, + lookup::{between, ray_pass}, + types::{CastlingKind, Color, HOME_RANK, KING_TO_FILE, Piece, PieceType, ROOK_TO_FILE, Square}, }; #[derive(Debug)] @@ -67,81 +67,34 @@ impl Board { fn set_castling(&mut self, rights: &str) { for right in rights.chars() { - match right { - 'K' => { - let mut rook_from = Square::H1; - while self.piece_on(rook_from).piece_type() != PieceType::Rook { - rook_from = rook_from.shift(-1); - } - - let king_from = self.king_square(Color::White); - self.set_castling_for(CastlingKind::WhiteKingside, king_from, Square::G1, rook_from, Square::F1); - } - 'Q' => { - let mut rook_from = Square::A1; - while self.piece_on(rook_from).piece_type() != PieceType::Rook { - rook_from = rook_from.shift(1); - } - - let king_from = self.king_square(Color::White); - self.set_castling_for(CastlingKind::WhiteQueenside, king_from, Square::C1, rook_from, Square::D1); - } - 'k' => { - let mut rook_from = Square::H8; - while self.piece_on(rook_from).piece_type() != PieceType::Rook { - rook_from = rook_from.shift(-1); - } - - let king_from = self.king_square(Color::Black); - self.set_castling_for(CastlingKind::BlackKingside, king_from, Square::G8, rook_from, Square::F8); - } - 'q' => { - let mut rook_from = Square::A8; - while self.piece_on(rook_from).piece_type() != PieceType::Rook { - rook_from = rook_from.shift(1); - } - - let king_from = self.king_square(Color::Black); - self.set_castling_for(CastlingKind::BlackQueenside, king_from, Square::C8, rook_from, Square::D8); - } - token @ 'A'..='H' => { - let king_from = self.king_square(Color::White); - let rook_from = Square::from_rank_file(0, token as u8 - b'A'); - - let kind = if king_from.file() < rook_from.file() { - CastlingKind::WhiteKingside - } else { - CastlingKind::WhiteQueenside - }; - - let (king_to, rook_to) = match kind { - CastlingKind::WhiteKingside => (Square::G1, Square::F1), - CastlingKind::WhiteQueenside => (Square::C1, Square::D1), - _ => unreachable!(), - }; - - self.set_castling_for(kind, king_from, king_to, rook_from, rook_to); - } - token @ 'a'..='h' => { - let king_from = self.king_square(Color::Black); - let rook_from = Square::from_rank_file(7, token as u8 - b'a'); - - let kind = if king_from.file() < rook_from.file() { - CastlingKind::BlackKingside - } else { - CastlingKind::BlackQueenside - }; - - let (king_to, rook_to) = match kind { - CastlingKind::BlackKingside => (Square::G8, Square::F8), - CastlingKind::BlackQueenside => (Square::C8, Square::D8), - _ => unreachable!(), - }; - - self.set_castling_for(kind, king_from, king_to, rook_from, rook_to); - } - _ => continue, + if !matches!(right.to_ascii_uppercase(), 'A'..='H' | 'K' | 'Q') { + continue; } + + let color = if right.is_uppercase() { Color::White } else { Color::Black }; + let king_from = self.king_square(color); + let mut search_step = right.to_ascii_uppercase() as i8 - b'A' as i8 - king_from.file() as i8; + + if right.eq_ignore_ascii_case(&'K') { + search_step = Square::RIGHT; + } + if right.eq_ignore_ascii_case(&'Q') { + search_step = Square::LEFT; + } + + let rook_from = + (ray_pass(king_from, king_from.shift(search_step)) & self.colored_pieces(color, PieceType::Rook)).lsb(); + + let king_side = rook_from > king_from; + + let rights = if king_side { CastlingKind::KINGSIDE[color] } else { CastlingKind::QUEENSIDE[color] }; + + let king_to = + Square::from_rank_file(HOME_RANK[color].clone() as u8, KING_TO_FILE[king_side as usize].clone() as u8); + let rook_to = + Square::from_rank_file(HOME_RANK[color].clone() as u8, ROOK_TO_FILE[king_side as usize].clone() as u8); + + self.set_castling_for(rights, king_from, king_to, rook_from, rook_to); } } diff --git a/src/tools/bench.rs b/src/tools/bench.rs index ce50a4c8b..dc4e1c8b3 100644 --- a/src/tools/bench.rs +++ b/src/tools/bench.rs @@ -63,6 +63,11 @@ const POSITIONS: &[&str] = &[ "8/8/1k1r2p1/p1p2nPp/P3RN1P/8/4KP2/8 b - - 13 55", "5r1k/1p3p1p/2p2p2/1q2bP1Q/3p1P2/1PP1R1P1/6KP/2N5 w - - 0 25", "8/8/5pk1/5Nn1/R3r1P1/8/6K1/8 w - - 4 65", + "rbbnkqrn/pppppppp/8/8/8/8/PPPPPPPP/RBBNKQRN w AGag - 0 1", + "nbrknrbq/pppppppp/8/8/8/8/PPPPPPPP/NBRKNRBQ w CFcf - 0 1", + "nqnbbrkr/pppppppp/8/8/8/8/PPPPPPPP/NQNBBRKR w FHfh - 0 1", + "nqrnbkrb/pppppppp/8/8/8/8/PPPPPPPP/NQRNBKRB w KQkq - 0 1", + "rqkbbnnr/pppppppp/8/8/8/8/PPPPPPPP/BBNNRKRQ w GEha - 0 1", ]; const DEFAULT_DEPTH: i32 = 12; diff --git a/src/types/bitboard.rs b/src/types/bitboard.rs index 263935ab0..2cfc2d032 100644 --- a/src/types/bitboard.rs +++ b/src/types/bitboard.rs @@ -45,6 +45,10 @@ impl Bitboard { Square::new(self.0.trailing_zeros() as u8) } + pub const fn msb(self) -> Square { + Square::new(63 - self.0.leading_zeros() as u8) + } + pub const fn shift(self, offset: i8) -> Self { if offset > 0 { Self(self.0 << offset) } else { Self(self.0 >> -offset) } } diff --git a/src/types/mod.rs b/src/types/mod.rs index 14d416223..3baaedb82 100644 --- a/src/types/mod.rs +++ b/src/types/mod.rs @@ -30,17 +30,21 @@ pub const MAX_MOVES: usize = 256; #[rustfmt::skip] #[repr(u8)] -#[derive(PartialEq, PartialOrd)] +#[derive(Clone, PartialEq, PartialOrd)] pub enum Rank { R1, R2, R3, R4, R5, R6, R7, R8 } pub const PROMO_RANK: [Rank; 2] = [Rank::R8, Rank::R1]; +pub const HOME_RANK: [Rank; 2] = [Rank::R1, Rank::R8]; pub const PAWN_HOME_RANK: [Rank; 2] = [Rank::R2, Rank::R7]; #[rustfmt::skip] #[repr(u8)] -#[derive(PartialEq, PartialOrd)] +#[derive(Clone, PartialEq, PartialOrd)] pub enum File { A, B, C, D, E, F, G, H } +pub const KING_TO_FILE: [File; 2] = [File::C, File::G]; +pub const ROOK_TO_FILE: [File; 2] = [File::D, File::F]; + impl File { pub fn is_kingside(&self) -> bool { *self >= File::E diff --git a/src/types/square.rs b/src/types/square.rs index 7c1d7b89f..9044bbaf9 100644 --- a/src/types/square.rs +++ b/src/types/square.rs @@ -6,7 +6,7 @@ use crate::types::{Color, File, Rank}; /// Represents a square on a bitboard corresponding to the [Little-Endian Rank-File Mapping][LERFM]. /// /// [LERFM]: https://www.chessprogramming.org/Square_Mapping_Considerations#Little-Endian_Rank-File_Mapping -#[derive(Copy, Clone, Eq, PartialEq, Debug, Default)] +#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Debug, Default)] #[repr(u8)] #[rustfmt::skip] pub enum Square {