1
0
Fork 0
This commit is contained in:
Paul-Nicolas Madelaine 2025-11-03 17:36:30 +01:00
parent e8a4a5dffb
commit 5764bc0fce

View file

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