From 437cc801640f08c0f7fb122e3d0fcbcdce89ec21 Mon Sep 17 00:00:00 2001 From: Michael Whiteley Date: Mon, 13 Apr 2026 12:10:47 -0600 Subject: [PATCH 01/10] Use lsb and msb to simplify rook from squares. bench 2864276 --- src/board/parser.rs | 24 ++++-------------------- src/types/bitboard.rs | 4 ++++ 2 files changed, 8 insertions(+), 20 deletions(-) diff --git a/src/board/parser.rs b/src/board/parser.rs index 1a5cfc1ad..698fd0141 100644 --- a/src/board/parser.rs +++ b/src/board/parser.rs @@ -69,38 +69,22 @@ impl Board { 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 rook_from = self.colored_pieces(Color::White, PieceType::Rook).msb(); 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 rook_from = self.colored_pieces(Color::White, PieceType::Rook).lsb(); 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 rook_from = self.colored_pieces(Color::Black, PieceType::Rook).msb(); 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 rook_from = self.colored_pieces(Color::Black, PieceType::Rook).lsb(); let king_from = self.king_square(Color::Black); self.set_castling_for(CastlingKind::BlackQueenside, king_from, Square::C8, rook_from, Square::D8); } 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) } } From 8a655ce70670f01016f09a18f5602bd8d866833b Mon Sep 17 00:00:00 2001 From: Michael Whiteley Date: Mon, 13 Apr 2026 13:23:58 -0600 Subject: [PATCH 02/10] compiles --- src/board/parser.rs | 38 ++++++++++++++++++++++++++++++++++---- src/types/mod.rs | 8 ++++++-- src/types/square.rs | 2 +- 3 files changed, 41 insertions(+), 7 deletions(-) diff --git a/src/board/parser.rs b/src/board/parser.rs index 698fd0141..abf7a9cc3 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}, + types::{CastlingKind, Color, File, HOME_RANK, KING_TO_FILE, Piece, ROOK_TO_FILE, Square}, }; #[derive(Debug)] @@ -67,11 +67,41 @@ impl Board { fn set_castling(&mut self, rights: &str) { for right in rights.chars() { - match right { + + let color = if right.is_uppercase() { Color::White } else { Color::Black }; + //let rook_file = Square::from_rank_file(color, token as u8 - b'A'); + let mut rook_file = right.to_ascii_uppercase() as u8 - b'A'; + + //If not FRC, the move the file + if right.to_ascii_uppercase() == 'K' { + rook_file = File::H as u8; + } else if right.to_ascii_uppercase() == 'Q' { + rook_file = File::A as u8; + }; + + let king_from = self.king_square(color); + let rook_from = Square::from_rank_file(HOME_RANK[color].clone() as u8, rook_file as u8); + let king_side = rook_from > king_from; + + let rights = if color == Color::White { + if king_side { CastlingKind::WhiteKingside } else { CastlingKind::WhiteQueenside } + } else { + if king_side { CastlingKind::BlackKingside } else { CastlingKind::BlackQueenside } + }; + + 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); +/* 'K' => { + let rights = CastlingKind::WhiteKingside; let rook_from = self.colored_pieces(Color::White, PieceType::Rook).msb(); let king_from = self.king_square(Color::White); - self.set_castling_for(CastlingKind::WhiteKingside, king_from, Square::G1, rook_from, Square::F1); + let king_to = CastlingKind::landing_square(rights); + self.set_castling_for(rights, king_from, king_to, rook_from, Square::F1); } 'Q' => { let rook_from = self.colored_pieces(Color::White, PieceType::Rook).lsb(); @@ -125,7 +155,7 @@ impl Board { self.set_castling_for(kind, king_from, king_to, rook_from, rook_to); } _ => continue, - } + */ } } 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 { From a789d5e095dc8e721a63318a2f9455bd5e2cd747 Mon Sep 17 00:00:00 2001 From: Michael Whiteley Date: Mon, 13 Apr 2026 13:50:35 -0600 Subject: [PATCH 03/10] Working and adds some FRC positions. bench 2989979 --- src/board/parser.rs | 72 +++++---------------------------------------- src/tools/bench.rs | 3 ++ 2 files changed, 10 insertions(+), 65 deletions(-) diff --git a/src/board/parser.rs b/src/board/parser.rs index abf7a9cc3..c4648455c 100644 --- a/src/board/parser.rs +++ b/src/board/parser.rs @@ -67,6 +67,9 @@ impl Board { fn set_castling(&mut self, rights: &str) { for right in rights.chars() { + if !matches!(right, 'a'..='h' | 'A'..='H' | 'K' | 'Q' | 'k' | 'q') { + continue; + } let color = if right.is_uppercase() { Color::White } else { Color::Black }; //let rook_file = Square::from_rank_file(color, token as u8 - b'A'); @@ -89,73 +92,12 @@ impl Board { if king_side { CastlingKind::BlackKingside } else { CastlingKind::BlackQueenside } }; - 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); + 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); -/* - 'K' => { - let rights = CastlingKind::WhiteKingside; - let rook_from = self.colored_pieces(Color::White, PieceType::Rook).msb(); - let king_from = self.king_square(Color::White); - let king_to = CastlingKind::landing_square(rights); - self.set_castling_for(rights, king_from, king_to, rook_from, Square::F1); - } - 'Q' => { - let rook_from = self.colored_pieces(Color::White, PieceType::Rook).lsb(); - let king_from = self.king_square(Color::White); - self.set_castling_for(CastlingKind::WhiteQueenside, king_from, Square::C1, rook_from, Square::D1); - } - 'k' => { - let rook_from = self.colored_pieces(Color::Black, PieceType::Rook).msb(); - let king_from = self.king_square(Color::Black); - self.set_castling_for(CastlingKind::BlackKingside, king_from, Square::G8, rook_from, Square::F8); - } - 'q' => { - let rook_from = self.colored_pieces(Color::Black, PieceType::Rook).lsb(); - 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, - */ } } diff --git a/src/tools/bench.rs b/src/tools/bench.rs index ce50a4c8b..bc2896113 100644 --- a/src/tools/bench.rs +++ b/src/tools/bench.rs @@ -63,6 +63,9 @@ 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", ]; const DEFAULT_DEPTH: i32 = 12; From eb015246a0ef9bb1f1271a900f50a33b7ca333bf Mon Sep 17 00:00:00 2001 From: Michael Whiteley Date: Mon, 13 Apr 2026 13:54:04 -0600 Subject: [PATCH 04/10] cleanup. bench 2989979 --- src/board/parser.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/board/parser.rs b/src/board/parser.rs index c4648455c..964cbc23e 100644 --- a/src/board/parser.rs +++ b/src/board/parser.rs @@ -67,15 +67,13 @@ impl Board { fn set_castling(&mut self, rights: &str) { for right in rights.chars() { - if !matches!(right, 'a'..='h' | 'A'..='H' | 'K' | 'Q' | 'k' | 'q') { + if !matches!(right.to_ascii_uppercase(), 'A'..='H' | 'K' | 'Q') { continue; } let color = if right.is_uppercase() { Color::White } else { Color::Black }; - //let rook_file = Square::from_rank_file(color, token as u8 - b'A'); let mut rook_file = right.to_ascii_uppercase() as u8 - b'A'; - //If not FRC, the move the file if right.to_ascii_uppercase() == 'K' { rook_file = File::H as u8; } else if right.to_ascii_uppercase() == 'Q' { From 72778bef64b0e52109b8859cb413c332fbd6f495 Mon Sep 17 00:00:00 2001 From: Michael Whiteley Date: Mon, 13 Apr 2026 14:26:18 -0600 Subject: [PATCH 05/10] clippy changes. bench 2989979 --- src/board/parser.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/board/parser.rs b/src/board/parser.rs index 964cbc23e..4c7981f64 100644 --- a/src/board/parser.rs +++ b/src/board/parser.rs @@ -74,14 +74,14 @@ impl Board { let color = if right.is_uppercase() { Color::White } else { Color::Black }; let mut rook_file = right.to_ascii_uppercase() as u8 - b'A'; - if right.to_ascii_uppercase() == 'K' { + if right.eq_ignore_ascii_case(&'K') { rook_file = File::H as u8; - } else if right.to_ascii_uppercase() == 'Q' { + } else if right.eq_ignore_ascii_case(&'Q') { rook_file = File::A as u8; }; let king_from = self.king_square(color); - let rook_from = Square::from_rank_file(HOME_RANK[color].clone() as u8, rook_file as u8); + let rook_from = Square::from_rank_file(HOME_RANK[color].clone() as u8, rook_file); let king_side = rook_from > king_from; let rights = if color == Color::White { From 410e5707ec46973665840e144aecf1899560e2f0 Mon Sep 17 00:00:00 2001 From: Michael Whiteley Date: Tue, 14 Apr 2026 08:41:59 -0600 Subject: [PATCH 06/10] Always search for rooks and add an XFEN position to bench. bench 3072380 --- src/board/parser.rs | 21 ++++++++++++--------- src/tools/bench.rs | 1 + 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/board/parser.rs b/src/board/parser.rs index 4c7981f64..fd36d1d90 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, File, HOME_RANK, KING_TO_FILE, Piece, ROOK_TO_FILE, Square}, + lookup::{between, ray_pass}, + types::{CastlingKind, Color, HOME_RANK, KING_TO_FILE, Piece, PieceType, ROOK_TO_FILE, Square}, }; #[derive(Debug)] @@ -72,16 +72,19 @@ impl Board { } let color = if right.is_uppercase() { Color::White } else { Color::Black }; - let mut rook_file = right.to_ascii_uppercase() as u8 - b'A'; + 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') { - rook_file = File::H as u8; - } else if right.eq_ignore_ascii_case(&'Q') { - rook_file = File::A as u8; - }; + 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_from = self.king_square(color); - let rook_from = Square::from_rank_file(HOME_RANK[color].clone() as u8, rook_file); let king_side = rook_from > king_from; let rights = if color == Color::White { diff --git a/src/tools/bench.rs b/src/tools/bench.rs index bc2896113..e5593a736 100644 --- a/src/tools/bench.rs +++ b/src/tools/bench.rs @@ -66,6 +66,7 @@ const POSITIONS: &[&str] = &[ "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", ]; const DEFAULT_DEPTH: i32 = 12; From 80baf0bd56ea005e3b4ddea1ee88b8df19cf3522 Mon Sep 17 00:00:00 2001 From: Michael Whiteley Date: Tue, 14 Apr 2026 08:43:05 -0600 Subject: [PATCH 07/10] Formatting. bench 3072380 --- src/board/parser.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/board/parser.rs b/src/board/parser.rs index fd36d1d90..ff9ec31c3 100644 --- a/src/board/parser.rs +++ b/src/board/parser.rs @@ -82,8 +82,8 @@ impl Board { search_step = Square::LEFT; } - let rook_from = (ray_pass(king_from, king_from.shift(search_step)) - & self.colored_pieces(color, PieceType::Rook)).lsb(); + 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; From 81a478a40ddfbd066ce5386ddc78384f1ef363bd Mon Sep 17 00:00:00 2001 From: Michael Whiteley Date: Tue, 14 Apr 2026 08:51:38 -0600 Subject: [PATCH 08/10] Simplify. bench 3072380 --- src/board/parser.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/board/parser.rs b/src/board/parser.rs index ff9ec31c3..69caf60ee 100644 --- a/src/board/parser.rs +++ b/src/board/parser.rs @@ -87,10 +87,10 @@ impl Board { let king_side = rook_from > king_from; - let rights = if color == Color::White { - if king_side { CastlingKind::WhiteKingside } else { CastlingKind::WhiteQueenside } + let rights = if king_side { + CastlingKind::KINGSIDE[color] } else { - if king_side { CastlingKind::BlackKingside } else { CastlingKind::BlackQueenside } + CastlingKind::QUEENSIDE[color] }; let king_to = From e3bf8c0b0e75db208e73bdbc5b37f9ed2e51ecbd Mon Sep 17 00:00:00 2001 From: Michael Whiteley Date: Tue, 14 Apr 2026 08:52:17 -0600 Subject: [PATCH 09/10] Formatting. bench 3072380 --- src/board/parser.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/board/parser.rs b/src/board/parser.rs index 69caf60ee..f0b1c77bb 100644 --- a/src/board/parser.rs +++ b/src/board/parser.rs @@ -87,11 +87,7 @@ impl Board { let king_side = rook_from > king_from; - let rights = if king_side { - CastlingKind::KINGSIDE[color] - } else { - CastlingKind::QUEENSIDE[color] - }; + 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); From 7cbe35513534cf2a554542f6ccff5f777710b367 Mon Sep 17 00:00:00 2001 From: Michael Whiteley Date: Tue, 14 Apr 2026 11:35:09 -0600 Subject: [PATCH 10/10] Add DFRC fen into bench positions. bench 3126459 --- src/tools/bench.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tools/bench.rs b/src/tools/bench.rs index e5593a736..dc4e1c8b3 100644 --- a/src/tools/bench.rs +++ b/src/tools/bench.rs @@ -67,6 +67,7 @@ const POSITIONS: &[&str] = &[ "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;