control flow
This commit is contained in:
parent
34df546eaa
commit
89e77fb977
2 changed files with 101 additions and 124 deletions
31
src/moves.rs
31
src/moves.rs
|
|
@ -7,8 +7,9 @@ use crate::position::*;
|
|||
use crate::san::*;
|
||||
use crate::uci::*;
|
||||
|
||||
use std::iter::ExactSizeIterator;
|
||||
use std::iter::FusedIterator;
|
||||
use std::convert::Infallible;
|
||||
use std::iter::{ExactSizeIterator, FusedIterator};
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
/// A legal move.
|
||||
#[must_use]
|
||||
|
|
@ -101,7 +102,7 @@ impl<'l> Move<'l> {
|
|||
}
|
||||
}
|
||||
}
|
||||
impl<const ROLE: u8> MoveGen for MoveGenImpl<ROLE> {
|
||||
impl<const ROLE: u8> MoveGen<Infallible> for MoveGenImpl<ROLE> {
|
||||
#[inline]
|
||||
fn roles(&self, role: Role) -> bool {
|
||||
role as u8 == ROLE
|
||||
|
|
@ -111,11 +112,7 @@ impl<'l> Move<'l> {
|
|||
self.to
|
||||
}
|
||||
#[inline]
|
||||
fn is_check(&mut self) {}
|
||||
#[inline]
|
||||
fn en_passant_is_legal(&mut self) {}
|
||||
#[inline]
|
||||
fn extend<I>(&mut self, iter: I)
|
||||
fn extend<I>(&mut self, iter: I) -> ControlFlow<Infallible>
|
||||
where
|
||||
I: Iterator<Item = RawMove> + ExactSizeIterator,
|
||||
{
|
||||
|
|
@ -124,6 +121,7 @@ impl<'l> Move<'l> {
|
|||
debug_assert!(self.to.contains(raw.to()));
|
||||
self.candidates.insert(raw.from);
|
||||
});
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
}
|
||||
San {
|
||||
|
|
@ -153,7 +151,7 @@ impl<'l> Move<'l> {
|
|||
_ => {
|
||||
fn aux<const ROLE: u8>(m: &Move) -> SanInner {
|
||||
let mut moves = MoveGenImpl::<ROLE>::new(m.to());
|
||||
m.position().generate_moves(&mut moves);
|
||||
let ControlFlow::Continue(()) = m.position().generate_moves(&mut moves);
|
||||
let candidates = moves.candidates;
|
||||
let (file, rank) = if candidates == m.from().bitboard() {
|
||||
(None, None)
|
||||
|
|
@ -186,7 +184,7 @@ impl<'l> Move<'l> {
|
|||
suffix: {
|
||||
let pos = self.make();
|
||||
let mut moves = MateMoveGenImpl::new();
|
||||
pos.generate_moves(&mut moves);
|
||||
let ControlFlow::Continue(()) = pos.generate_moves(&mut moves);
|
||||
let MateMoveGenImpl { is_check, is_mate } = moves;
|
||||
match (is_check, is_mate) {
|
||||
(false, _) => None,
|
||||
|
|
@ -210,21 +208,24 @@ pub struct Moves<'l> {
|
|||
array: ArrayVec<RawMove, MAX_LEGAL_MOVES>,
|
||||
}
|
||||
|
||||
impl<'l> MoveGen for Moves<'l> {
|
||||
impl<'l> MoveGen<Infallible> for Moves<'l> {
|
||||
#[inline]
|
||||
fn is_check(&mut self) {
|
||||
fn is_check(&mut self) -> ControlFlow<Infallible> {
|
||||
self.is_check = true;
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
#[inline]
|
||||
fn en_passant_is_legal(&mut self) {
|
||||
fn en_passant_is_legal(&mut self) -> ControlFlow<Infallible> {
|
||||
self.en_passant_is_legal = true;
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
#[inline]
|
||||
fn extend<I>(&mut self, iter: I)
|
||||
fn extend<I>(&mut self, iter: I) -> ControlFlow<Infallible>
|
||||
where
|
||||
I: Iterator<Item = RawMove> + ExactSizeIterator,
|
||||
{
|
||||
iter.for_each(|raw| unsafe { self.array.push_unchecked(raw) });
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -232,7 +233,7 @@ impl<'l> Moves<'l> {
|
|||
#[inline]
|
||||
pub(crate) fn compute(position: &'l Position) -> Moves<'l> {
|
||||
fn aux(position: &Position, moves: &mut Moves) {
|
||||
position.generate_moves(moves);
|
||||
let ControlFlow::Continue(()) = position.generate_moves(moves);
|
||||
}
|
||||
let mut moves = Moves {
|
||||
position,
|
||||
|
|
|
|||
194
src/position.rs
194
src/position.rs
|
|
@ -8,8 +8,9 @@ use crate::san::*;
|
|||
use crate::setup::*;
|
||||
use crate::uci::*;
|
||||
|
||||
use std::iter::ExactSizeIterator;
|
||||
use std::iter::FusedIterator;
|
||||
use std::convert::Infallible;
|
||||
use std::iter::{ExactSizeIterator, FusedIterator};
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
/// **A chess position.**
|
||||
///
|
||||
|
|
@ -115,31 +116,25 @@ impl Position {
|
|||
Self { len: 0 }
|
||||
}
|
||||
}
|
||||
impl MoveGen for MoveGenImpl {
|
||||
#[inline]
|
||||
fn is_check(&mut self) {}
|
||||
#[inline]
|
||||
fn en_passant_is_legal(&mut self) {}
|
||||
#[inline]
|
||||
fn extend<I>(&mut self, iter: I)
|
||||
impl MoveGen<Infallible> for MoveGenImpl {
|
||||
fn extend<I>(&mut self, iter: I) -> ControlFlow<Infallible>
|
||||
where
|
||||
I: Iterator<Item = RawMove> + ExactSizeIterator,
|
||||
{
|
||||
self.len += iter.len();
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
}
|
||||
let mut moves = MoveGenImpl::new();
|
||||
self.generate_moves(&mut moves);
|
||||
let ControlFlow::Continue(()) = 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 {
|
||||
struct MoveGenImpl;
|
||||
impl MoveGen<()> for MoveGenImpl {
|
||||
#[inline]
|
||||
fn roles(&self, _role: Role) -> bool {
|
||||
false
|
||||
|
|
@ -153,21 +148,11 @@ impl Position {
|
|||
Bitboard::new()
|
||||
}
|
||||
#[inline]
|
||||
fn is_check(&mut self) {
|
||||
self.is_check = true;
|
||||
}
|
||||
#[inline]
|
||||
fn en_passant_is_legal(&mut self) {}
|
||||
#[inline]
|
||||
fn extend<I>(&mut self, _iter: I)
|
||||
where
|
||||
I: Iterator<Item = RawMove> + ExactSizeIterator,
|
||||
{
|
||||
fn is_check(&mut self) -> ControlFlow<()> {
|
||||
ControlFlow::Break(())
|
||||
}
|
||||
}
|
||||
let mut moves = MoveGenImpl { is_check: false };
|
||||
self.generate_moves(&mut moves);
|
||||
moves.is_check
|
||||
self.generate_moves(&mut MoveGenImpl).is_break()
|
||||
}
|
||||
|
||||
/// Returns `true` if there is no legal move on the position.
|
||||
|
|
@ -184,9 +169,8 @@ impl Position {
|
|||
}
|
||||
struct MoveGenImpl {
|
||||
to: Bitboard,
|
||||
en_passant_is_legal: bool,
|
||||
}
|
||||
impl MoveGen for MoveGenImpl {
|
||||
impl MoveGen<()> for MoveGenImpl {
|
||||
#[inline]
|
||||
fn roles(&self, role: Role) -> bool {
|
||||
match role {
|
||||
|
|
@ -203,24 +187,14 @@ impl Position {
|
|||
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<I>(&mut self, _iter: I)
|
||||
where
|
||||
I: Iterator<Item = RawMove> + ExactSizeIterator,
|
||||
{
|
||||
fn en_passant_is_legal(&mut self) -> ControlFlow<()> {
|
||||
ControlFlow::Break(())
|
||||
}
|
||||
}
|
||||
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
|
||||
self.generate_moves(&mut moves).is_break()
|
||||
}
|
||||
|
||||
/// Discards the en passant target square.
|
||||
|
|
@ -315,20 +289,14 @@ impl Position {
|
|||
role: Role,
|
||||
from: Bitboard,
|
||||
to: Bitboard,
|
||||
found: Option<RawMove>,
|
||||
}
|
||||
impl<const ROLE: u8> MoveGenImpl<ROLE> {
|
||||
#[inline]
|
||||
fn new(role: Role, from: Bitboard, to: Bitboard) -> Self {
|
||||
Self {
|
||||
role,
|
||||
from,
|
||||
to,
|
||||
found: None,
|
||||
}
|
||||
Self { role, from, to }
|
||||
}
|
||||
}
|
||||
impl<const ROLE: u8> MoveGen for MoveGenImpl<ROLE> {
|
||||
impl<const ROLE: u8> MoveGen<RawMove> for MoveGenImpl<ROLE> {
|
||||
#[inline]
|
||||
fn roles(&self, role: Role) -> bool {
|
||||
role as u8 == ROLE
|
||||
|
|
@ -342,23 +310,19 @@ impl Position {
|
|||
self.to
|
||||
}
|
||||
#[inline]
|
||||
fn is_check(&mut self) {}
|
||||
#[inline]
|
||||
fn en_passant_is_legal(&mut self) {}
|
||||
#[inline]
|
||||
fn extend<I>(&mut self, iter: I)
|
||||
fn extend<I>(&mut self, iter: I) -> ControlFlow<RawMove>
|
||||
where
|
||||
I: Iterator<Item = RawMove> + ExactSizeIterator,
|
||||
{
|
||||
iter.for_each(|raw| {
|
||||
for raw in iter {
|
||||
debug_assert!(raw.role() as u8 == ROLE);
|
||||
debug_assert!(self.from.contains(raw.from()));
|
||||
debug_assert!(self.to.contains(raw.to()));
|
||||
if raw.role == self.role {
|
||||
debug_assert!(self.found.is_none());
|
||||
self.found = Some(raw);
|
||||
return ControlFlow::Break(raw);
|
||||
}
|
||||
});
|
||||
}
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
}
|
||||
let UciMove {
|
||||
|
|
@ -375,8 +339,10 @@ impl Position {
|
|||
to: Square,
|
||||
) -> Result<Move<'l>, InvalidUciMove> {
|
||||
let mut moves = MoveGenImpl::<ROLE>::new(role, from.bitboard(), to.bitboard());
|
||||
position.generate_moves(&mut moves);
|
||||
let raw = moves.found.ok_or(InvalidUciMove::Illegal)?;
|
||||
let raw = position
|
||||
.generate_moves(&mut moves)
|
||||
.break_value()
|
||||
.ok_or(InvalidUciMove::Illegal)?;
|
||||
Ok(unsafe { Move::new_unchecked(position, raw) })
|
||||
}
|
||||
let promotion = if role == Role::Pawn {
|
||||
|
|
@ -409,7 +375,7 @@ impl Position {
|
|||
}
|
||||
}
|
||||
}
|
||||
impl<const ROLE: u8> MoveGen for MoveGenImpl<ROLE> {
|
||||
impl<const ROLE: u8> MoveGen<Infallible> for MoveGenImpl<ROLE> {
|
||||
#[inline]
|
||||
fn roles(&self, role: Role) -> bool {
|
||||
role as u8 == ROLE
|
||||
|
|
@ -423,11 +389,7 @@ impl Position {
|
|||
self.to
|
||||
}
|
||||
#[inline]
|
||||
fn is_check(&mut self) {}
|
||||
#[inline]
|
||||
fn en_passant_is_legal(&mut self) {}
|
||||
#[inline]
|
||||
fn extend<I>(&mut self, iter: I)
|
||||
fn extend<I>(&mut self, iter: I) -> ControlFlow<Infallible>
|
||||
where
|
||||
I: Iterator<Item = RawMove> + ExactSizeIterator,
|
||||
{
|
||||
|
|
@ -442,6 +404,7 @@ impl Position {
|
|||
}
|
||||
}
|
||||
});
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
}
|
||||
let (role, promotion, from, to) = match san.inner {
|
||||
|
|
@ -486,7 +449,7 @@ impl Position {
|
|||
to: Bitboard,
|
||||
) -> Result<Move<'l>, InvalidSan> {
|
||||
let mut moves = MoveGenImpl::<ROLE>::new(role, from, to);
|
||||
position.generate_moves(&mut moves);
|
||||
let ControlFlow::Continue(()) = position.generate_moves(&mut moves);
|
||||
match moves.found {
|
||||
None => Err(InvalidSan::Illegal),
|
||||
Some(raw) => match moves.found_other {
|
||||
|
|
@ -569,7 +532,7 @@ impl RawMove {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) trait MoveGen {
|
||||
pub(crate) trait MoveGen<S> {
|
||||
#[inline]
|
||||
fn roles(&self, _role: Role) -> bool {
|
||||
true
|
||||
|
|
@ -583,11 +546,20 @@ pub(crate) trait MoveGen {
|
|||
!Bitboard::new()
|
||||
}
|
||||
|
||||
fn is_check(&mut self);
|
||||
fn en_passant_is_legal(&mut self);
|
||||
fn extend<I>(&mut self, iter: I)
|
||||
#[inline]
|
||||
fn is_check(&mut self) -> ControlFlow<S> {
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
#[inline]
|
||||
fn en_passant_is_legal(&mut self) -> ControlFlow<S> {
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
fn extend<I>(&mut self, _iter: I) -> ControlFlow<S>
|
||||
where
|
||||
I: Iterator<Item = RawMove> + ExactSizeIterator;
|
||||
I: Iterator<Item = RawMove> + ExactSizeIterator,
|
||||
{
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Position {
|
||||
|
|
@ -596,9 +568,9 @@ impl Position {
|
|||
Self(setup)
|
||||
}
|
||||
|
||||
pub(crate) fn generate_moves<T>(&self, moves: &mut T)
|
||||
pub(crate) fn generate_moves<S, T>(&self, moves: &mut T) -> ControlFlow<S>
|
||||
where
|
||||
T: MoveGen,
|
||||
T: MoveGen<S>,
|
||||
{
|
||||
let global_mask_from = moves.from();
|
||||
let global_mask_to = moves.to();
|
||||
|
|
@ -673,7 +645,7 @@ impl Position {
|
|||
to,
|
||||
role: Role::King,
|
||||
}),
|
||||
);
|
||||
)?;
|
||||
// castling
|
||||
if castling_rights.get(turn, CastlingSide::Short) {
|
||||
let (x, y) = match turn {
|
||||
|
|
@ -692,7 +664,7 @@ impl Position {
|
|||
from,
|
||||
to,
|
||||
role: Role::King,
|
||||
}))
|
||||
}))?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -713,15 +685,15 @@ impl Position {
|
|||
from,
|
||||
to,
|
||||
role: Role::King,
|
||||
}))
|
||||
}))?;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if checkers.len() > 1 {
|
||||
moves.is_check();
|
||||
return;
|
||||
moves.is_check()?;
|
||||
return ControlFlow::Continue(());
|
||||
}
|
||||
|
||||
let blockers_x_ray = blockers & !(x | y);
|
||||
|
|
@ -762,7 +734,7 @@ impl Position {
|
|||
from: unsafe { to.trans_unchecked(!forward) },
|
||||
to,
|
||||
role: Role::Pawn,
|
||||
}));
|
||||
}))?;
|
||||
moves.extend(MoveAndPromote::new((targets & promotion).map(|to| {
|
||||
RawMove {
|
||||
kind: MoveType::PawnAdvancePromotion,
|
||||
|
|
@ -770,7 +742,7 @@ impl Position {
|
|||
to,
|
||||
role: Role::Pawn,
|
||||
}
|
||||
})));
|
||||
})))?;
|
||||
}
|
||||
// pawn attacks kingside
|
||||
{
|
||||
|
|
@ -784,7 +756,7 @@ impl Position {
|
|||
from: unsafe { to.trans_unchecked(!kside) },
|
||||
to,
|
||||
role: Role::Pawn,
|
||||
}));
|
||||
}))?;
|
||||
moves.extend(MoveAndPromote::new((targets & promotion).map(|to| {
|
||||
RawMove {
|
||||
kind: MoveType::PawnAttackPromotion,
|
||||
|
|
@ -792,7 +764,7 @@ impl Position {
|
|||
to,
|
||||
role: Role::Pawn,
|
||||
}
|
||||
})));
|
||||
})))?;
|
||||
}
|
||||
// pawn attacks queenside
|
||||
{
|
||||
|
|
@ -806,7 +778,7 @@ impl Position {
|
|||
from: unsafe { to.trans_unchecked(!qside) },
|
||||
to,
|
||||
role: Role::Pawn,
|
||||
}));
|
||||
}))?;
|
||||
moves.extend(MoveAndPromote::new((targets & promotion).map(|to| {
|
||||
RawMove {
|
||||
kind: MoveType::PawnAttackPromotion,
|
||||
|
|
@ -814,7 +786,7 @@ impl Position {
|
|||
to,
|
||||
role: Role::Pawn,
|
||||
}
|
||||
})));
|
||||
})))?;
|
||||
}
|
||||
// pawn double advances
|
||||
moves.extend(
|
||||
|
|
@ -826,7 +798,7 @@ impl Position {
|
|||
role: Role::Pawn,
|
||||
},
|
||||
),
|
||||
);
|
||||
)?;
|
||||
// en passant
|
||||
if let Some(to) = en_passant.try_into_square() {
|
||||
if global_mask_to.contains(to) {
|
||||
|
|
@ -846,18 +818,18 @@ impl Position {
|
|||
) & theirs.rook())
|
||||
.map(|sq| lookup::segment(king_square, sq))
|
||||
.reduce_or();
|
||||
(global_mask_from
|
||||
for from in global_mask_from
|
||||
& candidates
|
||||
& (!pinned | lookup::segment(king_square, to)))
|
||||
.for_each(|from| {
|
||||
moves.en_passant_is_legal();
|
||||
& (!pinned | lookup::segment(king_square, to))
|
||||
{
|
||||
moves.en_passant_is_legal()?;
|
||||
moves.extend(std::iter::once(RawMove {
|
||||
kind: MoveType::EnPassant,
|
||||
from,
|
||||
to,
|
||||
role: Role::Pawn,
|
||||
}))
|
||||
})
|
||||
}))?;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -876,26 +848,27 @@ impl Position {
|
|||
role,
|
||||
}
|
||||
}),
|
||||
)
|
||||
)?;
|
||||
}
|
||||
ControlFlow::Continue(())
|
||||
};
|
||||
if moves.roles(Role::Knight) {
|
||||
aux(moves, Role::Knight)
|
||||
aux(moves, Role::Knight)?;
|
||||
}
|
||||
if moves.roles(Role::Bishop) {
|
||||
aux(moves, Role::Bishop)
|
||||
aux(moves, Role::Bishop)?;
|
||||
}
|
||||
if moves.roles(Role::Rook) {
|
||||
aux(moves, Role::Rook)
|
||||
aux(moves, Role::Rook)?;
|
||||
}
|
||||
if moves.roles(Role::Queen) {
|
||||
aux(moves, Role::Queen)
|
||||
aux(moves, Role::Queen)?;
|
||||
}
|
||||
}
|
||||
|
||||
if checker.is_some() {
|
||||
moves.is_check();
|
||||
return;
|
||||
moves.is_check()?;
|
||||
return ControlFlow::Continue(());
|
||||
}
|
||||
|
||||
// pinned pieces
|
||||
|
|
@ -911,19 +884,22 @@ impl Position {
|
|||
role,
|
||||
},
|
||||
),
|
||||
)
|
||||
)?;
|
||||
}
|
||||
ControlFlow::Continue(())
|
||||
};
|
||||
if moves.roles(Role::Bishop) {
|
||||
aux(moves, Role::Bishop, lookup::bishop_lines(king_square));
|
||||
aux(moves, Role::Bishop, lookup::bishop_lines(king_square))?;
|
||||
}
|
||||
if moves.roles(Role::Rook) {
|
||||
aux(moves, Role::Rook, lookup::rook_lines(king_square));
|
||||
aux(moves, Role::Rook, lookup::rook_lines(king_square))?;
|
||||
}
|
||||
if moves.roles(Role::Queen) {
|
||||
aux(moves, Role::Queen, !Bitboard::new());
|
||||
aux(moves, Role::Queen, !Bitboard::new())?;
|
||||
}
|
||||
}
|
||||
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
@ -1094,19 +1070,19 @@ impl MateMoveGenImpl {
|
|||
}
|
||||
}
|
||||
}
|
||||
impl MoveGen for MateMoveGenImpl {
|
||||
impl MoveGen<Infallible> for MateMoveGenImpl {
|
||||
#[inline]
|
||||
fn is_check(&mut self) {
|
||||
fn is_check(&mut self) -> ControlFlow<Infallible> {
|
||||
self.is_check = true;
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
#[inline]
|
||||
fn en_passant_is_legal(&mut self) {}
|
||||
#[inline]
|
||||
fn extend<I>(&mut self, iter: I)
|
||||
fn extend<I>(&mut self, iter: I) -> ControlFlow<Infallible>
|
||||
where
|
||||
I: Iterator<Item = RawMove> + ExactSizeIterator,
|
||||
{
|
||||
self.is_mate &= iter.len() == 0;
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue