From 5764bc0fce223b42fd4f3d5f5a21ecdc2fb244fb Mon Sep 17 00:00:00 2001 From: Paul-Nicolas Madelaine Date: Mon, 3 Nov 2025 17:36:30 +0100 Subject: [PATCH] movegen --- src/position.rs | 170 ++++++++++++++++++++++++------------------------ 1 file changed, 85 insertions(+), 85 deletions(-) diff --git a/src/position.rs b/src/position.rs index 3d40f8c..82e169d 100644 --- a/src/position.rs +++ b/src/position.rs @@ -79,17 +79,17 @@ impl Position { /// Returns all the legal moves on the position. #[inline] pub fn legal_moves<'l>(&'l self) -> Moves<'l> { - fn aux(position: &Position, visitor: &mut Moves) { - position.generate_moves(visitor); + fn aux(position: &Position, moves: &mut Moves) { + position.generate_moves(moves); } - let mut visitor = Moves { + let mut moves = Moves { position: self, is_check: false, en_passant_is_legal: false, array: ArrayVec::new(), }; - aux(self, &mut visitor); - visitor + aux(self, &mut moves); + moves } /// Counts the legal moves on the position. @@ -103,33 +103,33 @@ impl Position { /// ``` #[inline] pub fn count_legal_moves(&self) -> usize { - struct VisitorImpl { + struct MoveGenImpl { len: usize, } - impl VisitorImpl { + impl MoveGenImpl { fn new() -> Self { Self { len: 0 } } } - impl Visitor for VisitorImpl { + impl MoveGen for MoveGenImpl { #[inline] fn is_check(&mut self) {} #[inline] fn en_passant_is_legal(&mut self) {} #[inline] - fn moves(&mut self, iter: I) + fn extend(&mut self, iter: I) where I: Iterator + ExactSizeIterator, { self.len += iter.len(); } } - fn aux(position: &Position, visitor: &mut VisitorImpl) { - position.generate_moves(visitor); + fn aux(position: &Position, moves: &mut MoveGenImpl) { + position.generate_moves(moves); } - let mut visitor = VisitorImpl::new(); - aux(self, &mut visitor); - visitor.len + let mut moves = MoveGenImpl::new(); + aux(self, &mut moves); + moves.len } /// Discards the optional en passant target square. @@ -221,13 +221,13 @@ impl Position { } pub(crate) fn move_from_uci<'l>(&'l self, uci: UciMove) -> Result, InvalidUciMove> { - struct VisitorImpl { + struct MoveGenImpl { role: Role, from: Bitboard, to: Bitboard, found: Option, } - impl VisitorImpl { + impl MoveGenImpl { #[inline] fn new(role: Role, from: Bitboard, to: Bitboard) -> Self { Self { @@ -238,7 +238,7 @@ impl Position { } } } - impl Visitor for VisitorImpl { + impl MoveGen for MoveGenImpl { #[inline] fn roles(&self, role: Role) -> bool { role as u8 == ROLE @@ -256,7 +256,7 @@ impl Position { #[inline] fn en_passant_is_legal(&mut self) {} #[inline] - fn moves(&mut self, iter: I) + fn extend(&mut self, iter: I) where I: Iterator + ExactSizeIterator, { @@ -284,9 +284,9 @@ impl Position { from: Square, to: Square, ) -> Result, InvalidUciMove> { - let mut visitor = VisitorImpl::::new(role, from.bitboard(), to.bitboard()); - position.generate_moves(&mut visitor); - let raw = visitor.found.ok_or(InvalidUciMove::Illegal)?; + let mut moves = MoveGenImpl::::new(role, from.bitboard(), to.bitboard()); + position.generate_moves(&mut moves); + let raw = moves.found.ok_or(InvalidUciMove::Illegal)?; Ok(Move { position, raw }) } let promotion = if role == Role::Pawn { @@ -307,14 +307,14 @@ impl Position { } pub(crate) fn move_from_san<'l>(&'l self, san: &San) -> Result, InvalidSan> { - struct VisitorImpl { + struct MoveGenImpl { role: Role, from: Bitboard, to: Bitboard, found: Option, found_other: bool, } - impl VisitorImpl { + impl MoveGenImpl { #[inline] fn new(role: Role, from: Bitboard, to: Bitboard) -> Self { Self { @@ -326,7 +326,7 @@ impl Position { } } } - impl Visitor for VisitorImpl { + impl MoveGen for MoveGenImpl { #[inline] fn roles(&self, role: Role) -> bool { role as u8 == ROLE @@ -344,7 +344,7 @@ impl Position { #[inline] fn en_passant_is_legal(&mut self) {} #[inline] - fn moves(&mut self, iter: I) + fn extend(&mut self, iter: I) where I: Iterator + ExactSizeIterator, { @@ -402,11 +402,11 @@ impl Position { from: Bitboard, to: Bitboard, ) -> Result, InvalidSan> { - let mut visitor = VisitorImpl::::new(role, from, to); - position.generate_moves(&mut visitor); - match visitor.found { + let mut moves = MoveGenImpl::::new(role, from, to); + position.generate_moves(&mut moves); + match moves.found { None => Err(InvalidSan::Illegal), - Some(raw) => match visitor.found_other { + Some(raw) => match moves.found_other { true => Err(InvalidSan::Ambiguous), false => Ok(Move { position, raw }), }, @@ -505,11 +505,11 @@ impl<'l> Move<'l> { /// Returns the standard algebraic notation of the move. pub fn to_san(self) -> San { - struct VisitorImpl { + struct MoveGenImpl { to: Bitboard, candidates: Bitboard, } - impl VisitorImpl { + impl MoveGenImpl { #[inline] fn new(to: Square) -> Self { Self { @@ -518,7 +518,7 @@ impl<'l> Move<'l> { } } } - impl Visitor for VisitorImpl { + impl MoveGen for MoveGenImpl { #[inline] fn roles(&self, role: Role) -> bool { role as u8 == ROLE @@ -532,7 +532,7 @@ impl<'l> Move<'l> { #[inline] fn en_passant_is_legal(&mut self) {} #[inline] - fn moves(&mut self, iter: I) + fn extend(&mut self, iter: I) where I: Iterator + ExactSizeIterator, { @@ -569,9 +569,9 @@ impl<'l> Move<'l> { } _ => { fn aux(m: &Move) -> SanInner { - let mut visitor = VisitorImpl::::new(m.to()); - m.position().generate_moves(&mut visitor); - let candidates = visitor.candidates; + let mut moves = MoveGenImpl::::new(m.to()); + m.position().generate_moves(&mut moves); + let candidates = moves.candidates; let (file, rank) = if candidates == m.from().bitboard() { (None, None) } else if candidates & m.from().file().bitboard() == m.from().bitboard() { @@ -602,9 +602,9 @@ impl<'l> Move<'l> { }, suffix: { let pos = self.make(); - let mut visitor = MateVisitorImpl::new(); - pos.generate_moves(&mut visitor); - visitor.is_check.then(|| match visitor.is_mate { + let mut moves = MateMoveGenImpl::new(); + pos.generate_moves(&mut moves); + moves.is_check.then(|| match moves.is_mate { true => SanSuffix::Checkmate, false => SanSuffix::Check, }) @@ -821,7 +821,7 @@ impl RawMove { } } -trait Visitor { +trait MoveGen { #[inline] fn roles(&self, _role: Role) -> bool { true @@ -837,12 +837,12 @@ trait Visitor { fn is_check(&mut self); fn en_passant_is_legal(&mut self); - fn moves(&mut self, iter: I) + fn extend(&mut self, iter: I) where I: Iterator + ExactSizeIterator; } -impl<'l> Visitor for Moves<'l> { +impl<'l> MoveGen for Moves<'l> { #[inline] fn is_check(&mut self) { self.is_check = true; @@ -852,7 +852,7 @@ impl<'l> Visitor for Moves<'l> { self.en_passant_is_legal = true; } #[inline] - fn moves(&mut self, iter: I) + fn extend(&mut self, iter: I) where I: Iterator + ExactSizeIterator, { @@ -866,12 +866,12 @@ impl Position { Self(setup) } - fn generate_moves(&self, visitor: &mut T) + fn generate_moves(&self, moves: &mut T) where - T: Visitor, + T: MoveGen, { - let global_mask_from = visitor.from(); - let global_mask_to = visitor.to(); + let global_mask_from = moves.from(); + let global_mask_to = moves.to(); let Setup { w, @@ -918,7 +918,7 @@ impl Position { | x & theirs.bishop() | y & theirs.rook(); - if visitor.roles(Role::King) && global_mask_from.contains(king_square) { + if moves.roles(Role::King) && global_mask_from.contains(king_square) { let attacked = { let blockers = blockers ^ ours.king(); theirs @@ -936,7 +936,7 @@ impl Position { .reduce_or() }; // king moves - visitor.moves( + moves.extend( (global_mask_to & lookup::king(king_square) & !us & !attacked).map(|to| RawMove { kind: MoveType::KingMove, from: king_square, @@ -957,7 +957,7 @@ impl Position { .trans_unchecked(Direction::East) }; if global_mask_to.contains(to) { - visitor.moves(std::iter::once(RawMove { + moves.extend(std::iter::once(RawMove { kind: MoveType::CastleShort, from, to, @@ -978,7 +978,7 @@ impl Position { .trans_unchecked(Direction::West) }; if global_mask_to.contains(to) { - visitor.moves(std::iter::once(RawMove { + moves.extend(std::iter::once(RawMove { kind: MoveType::CastleLong, from, to, @@ -990,7 +990,7 @@ impl Position { } if checkers.len() > 1 { - visitor.is_check(); + moves.is_check(); return; } @@ -1007,7 +1007,7 @@ impl Position { let target_mask = global_mask_to & block_check; // pawns - if visitor.roles(Role::Pawn) { + if moves.roles(Role::Pawn) { let kside = match turn { Color::White => Direction::NorthEast, Color::Black => Direction::SouthEast, @@ -1027,13 +1027,13 @@ impl Position { // pawn advances { let targets = adv & target_mask; - visitor.moves((targets & !promotion).map(|to| RawMove { + moves.extend((targets & !promotion).map(|to| RawMove { kind: MoveType::PawnAdvance, from: unsafe { to.trans_unchecked(!forward) }, to, role: Role::Pawn, })); - visitor.moves(MoveAndPromote::new((targets & promotion).map(|to| { + moves.extend(MoveAndPromote::new((targets & promotion).map(|to| { RawMove { kind: MoveType::PawnAdvancePromotion, from: unsafe { to.trans_unchecked(!forward) }, @@ -1049,13 +1049,13 @@ impl Position { .trans(kside) & them & target_mask; - visitor.moves((targets & !promotion).map(|to| RawMove { + moves.extend((targets & !promotion).map(|to| RawMove { kind: MoveType::PawnAttack, from: unsafe { to.trans_unchecked(!kside) }, to, role: Role::Pawn, })); - visitor.moves(MoveAndPromote::new((targets & promotion).map(|to| { + moves.extend(MoveAndPromote::new((targets & promotion).map(|to| { RawMove { kind: MoveType::PawnAttackPromotion, from: unsafe { to.trans_unchecked(!kside) }, @@ -1071,13 +1071,13 @@ impl Position { .trans(qside) & them & target_mask; - visitor.moves((targets & !promotion).map(|to| RawMove { + moves.extend((targets & !promotion).map(|to| RawMove { kind: MoveType::PawnAttack, from: unsafe { to.trans_unchecked(!qside) }, to, role: Role::Pawn, })); - visitor.moves(MoveAndPromote::new((targets & promotion).map(|to| { + moves.extend(MoveAndPromote::new((targets & promotion).map(|to| { RawMove { kind: MoveType::PawnAttackPromotion, from: unsafe { to.trans_unchecked(!qside) }, @@ -1087,7 +1087,7 @@ impl Position { }))); } // pawn double advances - visitor.moves( + moves.extend( ((adv & third_rank.bitboard()).trans(forward) & !blockers & target_mask).map( |to| RawMove { kind: MoveType::PawnDoubleAdvance, @@ -1120,8 +1120,8 @@ impl Position { & candidates & (!pinned | lookup::segment(king_square, to))) .for_each(|from| { - visitor.en_passant_is_legal(); - visitor.moves(std::iter::once(RawMove { + moves.en_passant_is_legal(); + moves.extend(std::iter::once(RawMove { kind: MoveType::EnPassant, from, to, @@ -1135,9 +1135,9 @@ impl Position { // pieces not pinned { - let aux = |visitor: &mut T, role| { + let aux = |moves: &mut T, role| { for from in global_mask_from & *ours.get(role) & !pinned { - visitor.moves( + moves.extend( (lookup::targets(role, from, blockers) & !us & target_mask).map(|to| { RawMove { kind: MoveType::PieceMove, @@ -1149,30 +1149,30 @@ impl Position { ) } }; - if visitor.roles(Role::Knight) { - aux(visitor, Role::Knight) + if moves.roles(Role::Knight) { + aux(moves, Role::Knight) } - if visitor.roles(Role::Bishop) { - aux(visitor, Role::Bishop) + if moves.roles(Role::Bishop) { + aux(moves, Role::Bishop) } - if visitor.roles(Role::Rook) { - aux(visitor, Role::Rook) + if moves.roles(Role::Rook) { + aux(moves, Role::Rook) } - if visitor.roles(Role::Queen) { - aux(visitor, Role::Queen) + if moves.roles(Role::Queen) { + aux(moves, Role::Queen) } } if checker.is_some() { - visitor.is_check(); + moves.is_check(); return; } // pinned pieces { - let aux = |visitor: &mut T, role| { + let aux = |moves: &mut T, role| { for from in global_mask_from & *ours.get(role) & pinned { - visitor.moves( + moves.extend( (global_mask_to & !us & pinned @@ -1187,14 +1187,14 @@ impl Position { ) } }; - if visitor.roles(Role::Bishop) { - aux(visitor, Role::Bishop); + if moves.roles(Role::Bishop) { + aux(moves, Role::Bishop); } - if visitor.roles(Role::Rook) { - aux(visitor, Role::Rook); + if moves.roles(Role::Rook) { + aux(moves, Role::Rook); } - if visitor.roles(Role::Queen) { - aux(visitor, Role::Queen); + if moves.roles(Role::Queen) { + aux(moves, Role::Queen); } } } @@ -1354,11 +1354,11 @@ fn aux_play_castle(setup: &mut Setup, side: CastlingSide) { setup.castling_rights.unset(setup.turn, CastlingSide::Long); } -struct MateVisitorImpl { +struct MateMoveGenImpl { is_check: bool, is_mate: bool, } -impl MateVisitorImpl { +impl MateMoveGenImpl { #[inline] fn new() -> Self { Self { @@ -1367,7 +1367,7 @@ impl MateVisitorImpl { } } } -impl Visitor for MateVisitorImpl { +impl MoveGen for MateMoveGenImpl { #[inline] fn is_check(&mut self) { self.is_check = true; @@ -1375,7 +1375,7 @@ impl Visitor for MateVisitorImpl { #[inline] fn en_passant_is_legal(&mut self) {} #[inline] - fn moves(&mut self, iter: I) + fn extend(&mut self, iter: I) where I: Iterator + ExactSizeIterator, {