diff --git a/src/board.rs b/src/board.rs index eb545f3..4476012 100644 --- a/src/board.rs +++ b/src/board.rs @@ -486,6 +486,11 @@ impl OptionSquare { pub(crate) fn from_square(square: Square) -> Self { unsafe { std::mem::transmute(square) } } + + #[inline] + pub(crate) fn bitboard(&self) -> Bitboard { + Bitboard(1 << (*self as u8)) + } } /// A type of piece. diff --git a/src/moves.rs b/src/moves.rs index 6166f5c..f1b2826 100644 --- a/src/moves.rs +++ b/src/moves.rs @@ -265,18 +265,24 @@ impl<'l> Moves<'l> { self.array.len() } - /// Returns `true` if en passant is legal. - #[inline] - pub fn en_passant_is_legal(&self) -> bool { - self.en_passant_is_legal - } - /// Returns `true` if the king is in check. #[inline] pub fn is_check(&self) -> bool { self.is_check } + /// Returns `true` if there is no legal move on the position. + #[inline] + pub fn is_mate(&self) -> bool { + self.array.len() == 0 + } + + /// Returns `true` if taking en passant is legal on the position. + #[inline] + pub fn en_passant_is_legal(&self) -> bool { + self.en_passant_is_legal + } + /// Returns the move at the given index, if it exists. #[inline] pub fn get(&self, index: usize) -> Option> { diff --git a/src/position.rs b/src/position.rs index 3b28e88..c7bffc4 100644 --- a/src/position.rs +++ b/src/position.rs @@ -77,21 +77,13 @@ impl Position { }) } - /// Returns all the legal moves on the position. + /// Returns the number of legal moves on the position. #[inline] pub fn legal_moves<'l>(&'l self) -> Moves<'l> { Moves::compute(self) } /// Counts the legal moves on the position. - /// - /// This is equivalent but faster than: - /// ``` - /// # use eschac::position::Position; - /// # |position: &Position| -> usize { - /// position.legal_moves().len() - /// # }; - /// ``` #[must_use] #[inline] pub fn count_legal_moves(&self) -> usize { @@ -116,14 +108,101 @@ impl Position { self.len += iter.len(); } } - fn aux(position: &Position, moves: &mut MoveGenImpl) { - position.generate_moves(moves); - } let mut moves = MoveGenImpl::new(); - aux(self, &mut moves); + self.generate_moves(&mut moves); moves.len } + /// Returns `true` if the king is in check. + #[must_use] + pub fn is_check(&self) -> bool { + struct MoveGenImpl { + is_check: bool, + } + impl MoveGen for MoveGenImpl { + #[inline] + fn roles(&self, _role: Role) -> bool { + false + } + #[inline] + fn from(&self) -> Bitboard { + Bitboard::new() + } + #[inline] + fn to(&self) -> Bitboard { + Bitboard::new() + } + #[inline] + fn is_check(&mut self) { + self.is_check = true; + } + #[inline] + fn en_passant_is_legal(&mut self) {} + #[inline] + fn extend(&mut self, _iter: I) + where + I: Iterator + ExactSizeIterator, + { + } + } + let mut moves = MoveGenImpl { is_check: false }; + self.generate_moves(&mut moves); + moves.is_check + } + + /// Returns `true` if there is no legal move on the position. + #[must_use] + pub fn is_mate(&self) -> bool { + self.count_legal_moves() == 0 + } + + /// Returns `true` if taking en passant is legal on the position. + #[must_use] + pub fn en_passant_is_legal(&self) -> bool { + if self.as_setup().en_passant == OptionSquare::None { + return false; + } + struct MoveGenImpl { + to: Bitboard, + en_passant_is_legal: bool, + } + impl MoveGen for MoveGenImpl { + #[inline] + fn roles(&self, role: Role) -> bool { + match role { + Role::Pawn => true, + _ => false, + } + } + #[inline] + fn from(&self) -> Bitboard { + !Bitboard::new() + } + #[inline] + fn to(&self) -> Bitboard { + self.to + } + #[inline] + fn is_check(&mut self) {} + #[inline] + fn en_passant_is_legal(&mut self) { + self.en_passant_is_legal = true; + } + #[inline] + fn extend(&mut self, _iter: I) + where + I: Iterator + ExactSizeIterator, + { + } + } + let mut moves = MoveGenImpl { + to: self.as_setup().en_passant.bitboard(), + en_passant_is_legal: false, + }; + self.generate_moves(&mut moves); + moves.en_passant_is_legal + } + /// Discards the en passant target square. /// /// This function is useful to check for position equality, notably when implementing FIDE's diff --git a/tests/tests.rs b/tests/tests.rs index 69c9876..f22dc40 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -61,7 +61,12 @@ fn recursive_check_aux(position: Position, depth: usize) { match depth.checked_sub(1) { None => (), Some(depth) => { - position.legal_moves().into_iter().for_each(|m| { + let moves = position.legal_moves(); + assert_eq!(moves.len(), position.count_legal_moves()); + assert_eq!(moves.is_check(), position.is_check()); + assert_eq!(moves.is_mate(), position.is_mate()); + assert_eq!(moves.en_passant_is_legal(), position.en_passant_is_legal()); + moves.into_iter().for_each(|m| { let uci = m.to_uci(); assert_eq!(uci, uci.to_move(&position).unwrap().to_uci()); let san: San = m.to_san();