wip: introduce MoveSet
This commit is contained in:
parent
42ccddc12b
commit
a8b7b9ca63
2 changed files with 245 additions and 209 deletions
14
src/moves.rs
14
src/moves.rs
|
|
@ -120,11 +120,8 @@ impl<'l> Move<'l> {
|
||||||
self.to
|
self.to
|
||||||
}
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
fn extend<I>(&mut self, iter: I) -> ControlFlow<Infallible>
|
fn extend(&mut self, s: MoveSet) -> ControlFlow<Infallible> {
|
||||||
where
|
s.for_each(|raw| {
|
||||||
I: Iterator<Item = RawMove> + ExactSizeIterator,
|
|
||||||
{
|
|
||||||
iter.for_each(|raw| {
|
|
||||||
debug_assert!(raw.role() as u8 == ROLE);
|
debug_assert!(raw.role() as u8 == ROLE);
|
||||||
debug_assert!(self.to.contains(raw.to()));
|
debug_assert!(self.to.contains(raw.to()));
|
||||||
self.candidates.insert(raw.from);
|
self.candidates.insert(raw.from);
|
||||||
|
|
@ -236,11 +233,8 @@ impl<'l> MoveGen<Infallible> for Moves<'l> {
|
||||||
ControlFlow::Continue(())
|
ControlFlow::Continue(())
|
||||||
}
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
fn extend<I>(&mut self, iter: I) -> ControlFlow<Infallible>
|
fn extend(&mut self, s: MoveSet) -> ControlFlow<Infallible> {
|
||||||
where
|
s.for_each(|raw| unsafe { self.array.push_unchecked(raw) });
|
||||||
I: Iterator<Item = RawMove> + ExactSizeIterator,
|
|
||||||
{
|
|
||||||
iter.for_each(|raw| unsafe { self.array.push_unchecked(raw) });
|
|
||||||
ControlFlow::Continue(())
|
ControlFlow::Continue(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
426
src/position.rs
426
src/position.rs
|
|
@ -9,7 +9,6 @@ use crate::setup::*;
|
||||||
use crate::uci::*;
|
use crate::uci::*;
|
||||||
|
|
||||||
use core::convert::Infallible;
|
use core::convert::Infallible;
|
||||||
use core::iter::{ExactSizeIterator, FusedIterator};
|
|
||||||
use core::ops::ControlFlow;
|
use core::ops::ControlFlow;
|
||||||
|
|
||||||
/// **A chess position.**
|
/// **A chess position.**
|
||||||
|
|
@ -118,11 +117,8 @@ impl Position {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl MoveGen<Infallible> for MoveGenImpl {
|
impl MoveGen<Infallible> for MoveGenImpl {
|
||||||
fn extend<I>(&mut self, iter: I) -> ControlFlow<Infallible>
|
fn extend(&mut self, s: MoveSet) -> ControlFlow<Infallible> {
|
||||||
where
|
self.len += s.len();
|
||||||
I: Iterator<Item = RawMove> + ExactSizeIterator,
|
|
||||||
{
|
|
||||||
self.len += iter.len();
|
|
||||||
ControlFlow::Continue(())
|
ControlFlow::Continue(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -322,19 +318,17 @@ impl Position {
|
||||||
self.to
|
self.to
|
||||||
}
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
fn extend<I>(&mut self, iter: I) -> ControlFlow<RawMove>
|
fn extend(&mut self, s: MoveSet) -> ControlFlow<RawMove> {
|
||||||
where
|
let mut res = ControlFlow::Continue(());
|
||||||
I: Iterator<Item = RawMove> + ExactSizeIterator,
|
s.for_each(|raw| {
|
||||||
{
|
|
||||||
for raw in iter {
|
|
||||||
debug_assert!(raw.role() as u8 == ROLE);
|
debug_assert!(raw.role() as u8 == ROLE);
|
||||||
debug_assert!(self.from.contains(raw.from()));
|
debug_assert!(self.from.contains(raw.from()));
|
||||||
debug_assert!(self.to.contains(raw.to()));
|
debug_assert!(self.to.contains(raw.to()));
|
||||||
if raw.role == self.role {
|
if raw.role == self.role {
|
||||||
return ControlFlow::Break(raw);
|
res = ControlFlow::Break(raw);
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
ControlFlow::Continue(())
|
res
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let UciMove {
|
let UciMove {
|
||||||
|
|
@ -393,11 +387,8 @@ impl Position {
|
||||||
self.to
|
self.to
|
||||||
}
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
fn extend<I>(&mut self, iter: I) -> ControlFlow<Infallible>
|
fn extend(&mut self, s: MoveSet) -> ControlFlow<Infallible> {
|
||||||
where
|
s.for_each(|raw| {
|
||||||
I: Iterator<Item = RawMove> + ExactSizeIterator,
|
|
||||||
{
|
|
||||||
iter.for_each(|raw| {
|
|
||||||
debug_assert!(raw.role() as u8 == ROLE);
|
debug_assert!(raw.role() as u8 == ROLE);
|
||||||
debug_assert!(self.from.contains(raw.from()));
|
debug_assert!(self.from.contains(raw.from()));
|
||||||
debug_assert!(self.to.contains(raw.to()));
|
debug_assert!(self.to.contains(raw.to()));
|
||||||
|
|
@ -567,6 +558,194 @@ impl RawMove {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) enum MoveSet {
|
||||||
|
CastleShort {
|
||||||
|
from: Square,
|
||||||
|
to: Square,
|
||||||
|
},
|
||||||
|
CastleLong {
|
||||||
|
from: Square,
|
||||||
|
to: Square,
|
||||||
|
},
|
||||||
|
KingMove {
|
||||||
|
from: Square,
|
||||||
|
to: Bitboard,
|
||||||
|
},
|
||||||
|
PieceMove {
|
||||||
|
role: Role,
|
||||||
|
from: Square,
|
||||||
|
to: Bitboard,
|
||||||
|
},
|
||||||
|
PawnAttack {
|
||||||
|
from: Direction,
|
||||||
|
to: Bitboard,
|
||||||
|
},
|
||||||
|
PawnAdvance {
|
||||||
|
from: Direction,
|
||||||
|
to: Bitboard,
|
||||||
|
},
|
||||||
|
PawnDoubleAdvance {
|
||||||
|
from: Direction,
|
||||||
|
to: Bitboard,
|
||||||
|
},
|
||||||
|
EnPassant {
|
||||||
|
from: Square,
|
||||||
|
to: Square,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MoveSet {
|
||||||
|
#[inline]
|
||||||
|
pub fn len(&self) -> usize {
|
||||||
|
match self {
|
||||||
|
Self::CastleShort { .. } | Self::CastleLong { .. } | Self::EnPassant { .. } => 1,
|
||||||
|
Self::KingMove { to, .. }
|
||||||
|
| Self::PieceMove { to, .. }
|
||||||
|
| Self::PawnDoubleAdvance { to, .. } => to.len(),
|
||||||
|
Self::PawnAdvance { to, .. } | Self::PawnAttack { to, .. } => {
|
||||||
|
let mask = Rank::First.bitboard() | Rank::Eighth.bitboard();
|
||||||
|
to.len() + (*to & mask).len() * 3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
Self::CastleShort { .. } | Self::CastleLong { .. } | Self::EnPassant { .. } => false,
|
||||||
|
Self::KingMove { to, .. }
|
||||||
|
| Self::PieceMove { to, .. }
|
||||||
|
| Self::PawnDoubleAdvance { to, .. }
|
||||||
|
| Self::PawnAdvance { to, .. }
|
||||||
|
| Self::PawnAttack { to, .. } => to.is_empty(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub fn for_each<F: FnMut(RawMove)>(self, mut f: F) {
|
||||||
|
match self {
|
||||||
|
Self::CastleShort { from, to } => f(RawMove {
|
||||||
|
kind: MoveType::CastleShort,
|
||||||
|
role: Role::King,
|
||||||
|
from,
|
||||||
|
to,
|
||||||
|
}),
|
||||||
|
Self::CastleLong { from, to } => f(RawMove {
|
||||||
|
kind: MoveType::CastleLong,
|
||||||
|
role: Role::King,
|
||||||
|
from,
|
||||||
|
to,
|
||||||
|
}),
|
||||||
|
Self::EnPassant { from, to } => f(RawMove {
|
||||||
|
kind: MoveType::EnPassant,
|
||||||
|
role: Role::Pawn,
|
||||||
|
from,
|
||||||
|
to,
|
||||||
|
}),
|
||||||
|
Self::KingMove { from, to } => to.for_each(|to| {
|
||||||
|
f(RawMove {
|
||||||
|
kind: MoveType::KingMove,
|
||||||
|
role: Role::King,
|
||||||
|
from,
|
||||||
|
to,
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
Self::PieceMove { role, from, to } => to.for_each(|to| {
|
||||||
|
f(RawMove {
|
||||||
|
kind: MoveType::PieceMove,
|
||||||
|
role,
|
||||||
|
from,
|
||||||
|
to,
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
Self::PawnDoubleAdvance { from, to } => to.for_each(|to| {
|
||||||
|
f(RawMove {
|
||||||
|
kind: MoveType::PawnDoubleAdvance,
|
||||||
|
role: Role::Pawn,
|
||||||
|
from: unsafe { to.trans_unchecked(from).trans_unchecked(from) },
|
||||||
|
to,
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
Self::PawnAdvance { from, to } => {
|
||||||
|
let mask = Rank::First.bitboard() | Rank::Eighth.bitboard();
|
||||||
|
(to & !mask).for_each(|to| {
|
||||||
|
f(RawMove {
|
||||||
|
kind: MoveType::PawnAdvance,
|
||||||
|
role: Role::Pawn,
|
||||||
|
from: unsafe { to.trans_unchecked(from) },
|
||||||
|
to,
|
||||||
|
})
|
||||||
|
});
|
||||||
|
(to & mask).for_each(|to| {
|
||||||
|
let kind = MoveType::PawnAdvancePromotion;
|
||||||
|
let from = unsafe { to.trans_unchecked(from) };
|
||||||
|
f(RawMove {
|
||||||
|
kind,
|
||||||
|
role: Role::Queen,
|
||||||
|
from,
|
||||||
|
to,
|
||||||
|
});
|
||||||
|
f(RawMove {
|
||||||
|
kind,
|
||||||
|
role: Role::Rook,
|
||||||
|
from,
|
||||||
|
to,
|
||||||
|
});
|
||||||
|
f(RawMove {
|
||||||
|
kind,
|
||||||
|
role: Role::Bishop,
|
||||||
|
from,
|
||||||
|
to,
|
||||||
|
});
|
||||||
|
f(RawMove {
|
||||||
|
kind,
|
||||||
|
role: Role::Knight,
|
||||||
|
from,
|
||||||
|
to,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Self::PawnAttack { from, to } => {
|
||||||
|
let mask = Rank::First.bitboard() | Rank::Eighth.bitboard();
|
||||||
|
(to & !mask).for_each(|to| {
|
||||||
|
f(RawMove {
|
||||||
|
kind: MoveType::PawnAttack,
|
||||||
|
role: Role::Pawn,
|
||||||
|
from: unsafe { to.trans_unchecked(from) },
|
||||||
|
to,
|
||||||
|
})
|
||||||
|
});
|
||||||
|
(to & mask).for_each(|to| {
|
||||||
|
let kind = MoveType::PawnAttackPromotion;
|
||||||
|
let from = unsafe { to.trans_unchecked(from) };
|
||||||
|
f(RawMove {
|
||||||
|
kind,
|
||||||
|
role: Role::Queen,
|
||||||
|
from,
|
||||||
|
to,
|
||||||
|
});
|
||||||
|
f(RawMove {
|
||||||
|
kind,
|
||||||
|
role: Role::Rook,
|
||||||
|
from,
|
||||||
|
to,
|
||||||
|
});
|
||||||
|
f(RawMove {
|
||||||
|
kind,
|
||||||
|
role: Role::Bishop,
|
||||||
|
from,
|
||||||
|
to,
|
||||||
|
});
|
||||||
|
f(RawMove {
|
||||||
|
kind,
|
||||||
|
role: Role::Knight,
|
||||||
|
from,
|
||||||
|
to,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) trait MoveGen<S> {
|
pub(crate) trait MoveGen<S> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn roles(&self, _role: Role) -> bool {
|
fn roles(&self, _role: Role) -> bool {
|
||||||
|
|
@ -589,10 +768,8 @@ pub(crate) trait MoveGen<S> {
|
||||||
fn en_passant_is_legal(&mut self) -> ControlFlow<S> {
|
fn en_passant_is_legal(&mut self) -> ControlFlow<S> {
|
||||||
ControlFlow::Continue(())
|
ControlFlow::Continue(())
|
||||||
}
|
}
|
||||||
fn extend<I>(&mut self, _iter: I) -> ControlFlow<S>
|
#[inline]
|
||||||
where
|
fn extend(&mut self, _s: MoveSet) -> ControlFlow<S> {
|
||||||
I: Iterator<Item = RawMove> + ExactSizeIterator,
|
|
||||||
{
|
|
||||||
ControlFlow::Continue(())
|
ControlFlow::Continue(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -670,14 +847,10 @@ impl Position {
|
||||||
.reduce_or()
|
.reduce_or()
|
||||||
};
|
};
|
||||||
// king moves
|
// king moves
|
||||||
moves.extend(
|
moves.extend(MoveSet::KingMove {
|
||||||
(global_mask_to & lookup::king(king_square) & !us & !attacked).map(|to| RawMove {
|
|
||||||
kind: MoveType::KingMove,
|
|
||||||
from: king_square,
|
from: king_square,
|
||||||
to,
|
to: global_mask_to & lookup::king(king_square) & !us & !attacked,
|
||||||
role: Role::King,
|
})?;
|
||||||
}),
|
|
||||||
)?;
|
|
||||||
// castling
|
// castling
|
||||||
if castling_rights.get(turn, CastlingSide::Short) {
|
if castling_rights.get(turn, CastlingSide::Short) {
|
||||||
let (x, y) = match turn {
|
let (x, y) = match turn {
|
||||||
|
|
@ -691,12 +864,7 @@ impl Position {
|
||||||
.trans_unchecked(Direction::East)
|
.trans_unchecked(Direction::East)
|
||||||
};
|
};
|
||||||
if global_mask_to.contains(to) {
|
if global_mask_to.contains(to) {
|
||||||
moves.extend(core::iter::once(RawMove {
|
moves.extend(MoveSet::CastleShort { from, to })?;
|
||||||
kind: MoveType::CastleShort,
|
|
||||||
from,
|
|
||||||
to,
|
|
||||||
role: Role::King,
|
|
||||||
}))?;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -712,12 +880,7 @@ impl Position {
|
||||||
.trans_unchecked(Direction::West)
|
.trans_unchecked(Direction::West)
|
||||||
};
|
};
|
||||||
if global_mask_to.contains(to) {
|
if global_mask_to.contains(to) {
|
||||||
moves.extend(core::iter::once(RawMove {
|
moves.extend(MoveSet::CastleLong { from, to })?;
|
||||||
kind: MoveType::CastleLong,
|
|
||||||
from,
|
|
||||||
to,
|
|
||||||
role: Role::King,
|
|
||||||
}))?;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -757,80 +920,34 @@ impl Position {
|
||||||
let adv = (global_mask_from & ours.pawn() & (!pinned | king_square.file().bitboard()))
|
let adv = (global_mask_from & ours.pawn() & (!pinned | king_square.file().bitboard()))
|
||||||
.trans(forward)
|
.trans(forward)
|
||||||
& !blockers;
|
& !blockers;
|
||||||
let promotion = turn.promotion_rank().bitboard();
|
|
||||||
// pawn advances
|
// pawn advances
|
||||||
{
|
{
|
||||||
let targets = adv & target_mask;
|
moves.extend(MoveSet::PawnAdvance {
|
||||||
moves.extend((targets & !promotion).map(|to| RawMove {
|
from: !forward,
|
||||||
kind: MoveType::PawnAdvance,
|
to: adv & target_mask,
|
||||||
from: unsafe { to.trans_unchecked(!forward) },
|
})?;
|
||||||
to,
|
|
||||||
role: Role::Pawn,
|
|
||||||
}))?;
|
|
||||||
moves.extend(MoveAndPromote::new((targets & promotion).map(|to| {
|
|
||||||
RawMove {
|
|
||||||
kind: MoveType::PawnAdvancePromotion,
|
|
||||||
from: unsafe { to.trans_unchecked(!forward) },
|
|
||||||
to,
|
|
||||||
role: Role::Pawn,
|
|
||||||
}
|
|
||||||
})))?;
|
|
||||||
}
|
}
|
||||||
// pawn attacks kingside
|
// pawn attacks kingside
|
||||||
{
|
moves.extend(MoveSet::PawnAttack {
|
||||||
let targets =
|
from: !kside,
|
||||||
(global_mask_from & ours.pawn() & (!pinned | lookup::ray(king_square, kside)))
|
to: (global_mask_from & ours.pawn() & (!pinned | lookup::ray(king_square, kside)))
|
||||||
.trans(kside)
|
.trans(kside)
|
||||||
& them
|
& them
|
||||||
& target_mask;
|
& target_mask,
|
||||||
moves.extend((targets & !promotion).map(|to| RawMove {
|
})?;
|
||||||
kind: MoveType::PawnAttack,
|
|
||||||
from: unsafe { to.trans_unchecked(!kside) },
|
|
||||||
to,
|
|
||||||
role: Role::Pawn,
|
|
||||||
}))?;
|
|
||||||
moves.extend(MoveAndPromote::new((targets & promotion).map(|to| {
|
|
||||||
RawMove {
|
|
||||||
kind: MoveType::PawnAttackPromotion,
|
|
||||||
from: unsafe { to.trans_unchecked(!kside) },
|
|
||||||
to,
|
|
||||||
role: Role::Pawn,
|
|
||||||
}
|
|
||||||
})))?;
|
|
||||||
}
|
|
||||||
// pawn attacks queenside
|
// pawn attacks queenside
|
||||||
{
|
moves.extend(MoveSet::PawnAttack {
|
||||||
let targets =
|
from: !qside,
|
||||||
(global_mask_from & ours.pawn() & (!pinned | lookup::ray(king_square, qside)))
|
to: (global_mask_from & ours.pawn() & (!pinned | lookup::ray(king_square, qside)))
|
||||||
.trans(qside)
|
.trans(qside)
|
||||||
& them
|
& them
|
||||||
& target_mask;
|
& target_mask,
|
||||||
moves.extend((targets & !promotion).map(|to| RawMove {
|
})?;
|
||||||
kind: MoveType::PawnAttack,
|
|
||||||
from: unsafe { to.trans_unchecked(!qside) },
|
|
||||||
to,
|
|
||||||
role: Role::Pawn,
|
|
||||||
}))?;
|
|
||||||
moves.extend(MoveAndPromote::new((targets & promotion).map(|to| {
|
|
||||||
RawMove {
|
|
||||||
kind: MoveType::PawnAttackPromotion,
|
|
||||||
from: unsafe { to.trans_unchecked(!qside) },
|
|
||||||
to,
|
|
||||||
role: Role::Pawn,
|
|
||||||
}
|
|
||||||
})))?;
|
|
||||||
}
|
|
||||||
// pawn double advances
|
// pawn double advances
|
||||||
moves.extend(
|
moves.extend(MoveSet::PawnDoubleAdvance {
|
||||||
((adv & third_rank.bitboard()).trans(forward) & !blockers & target_mask).map(
|
from: !forward,
|
||||||
|to| RawMove {
|
to: (adv & third_rank.bitboard()).trans(forward) & !blockers & target_mask,
|
||||||
kind: MoveType::PawnDoubleAdvance,
|
})?;
|
||||||
from: unsafe { to.trans_unchecked(!forward).trans_unchecked(!forward) },
|
|
||||||
to,
|
|
||||||
role: Role::Pawn,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
)?;
|
|
||||||
// en passant
|
// en passant
|
||||||
if let Some(to) = en_passant {
|
if let Some(to) = en_passant {
|
||||||
if global_mask_to.contains(to) {
|
if global_mask_to.contains(to) {
|
||||||
|
|
@ -855,12 +972,7 @@ impl Position {
|
||||||
& (!pinned | lookup::segment(king_square, to))
|
& (!pinned | lookup::segment(king_square, to))
|
||||||
{
|
{
|
||||||
moves.en_passant_is_legal()?;
|
moves.en_passant_is_legal()?;
|
||||||
moves.extend(core::iter::once(RawMove {
|
moves.extend(MoveSet::EnPassant { from, to })?;
|
||||||
kind: MoveType::EnPassant,
|
|
||||||
from,
|
|
||||||
to,
|
|
||||||
role: Role::Pawn,
|
|
||||||
}))?;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -871,16 +983,11 @@ impl Position {
|
||||||
{
|
{
|
||||||
let aux = |moves: &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 {
|
||||||
moves.extend(
|
moves.extend(MoveSet::PieceMove {
|
||||||
(lookup::targets(role, from, blockers) & !us & target_mask).map(|to| {
|
|
||||||
RawMove {
|
|
||||||
kind: MoveType::PieceMove,
|
|
||||||
from,
|
|
||||||
to,
|
|
||||||
role,
|
role,
|
||||||
}
|
from,
|
||||||
}),
|
to: lookup::targets(role, from, blockers) & !us & target_mask,
|
||||||
)?;
|
})?;
|
||||||
}
|
}
|
||||||
ControlFlow::Continue(())
|
ControlFlow::Continue(())
|
||||||
};
|
};
|
||||||
|
|
@ -907,16 +1014,11 @@ impl Position {
|
||||||
{
|
{
|
||||||
let aux = |moves: &mut T, role, role_mask| {
|
let aux = |moves: &mut T, role, role_mask| {
|
||||||
for from in global_mask_from & pinned & role_mask & *ours.get(role) {
|
for from in global_mask_from & pinned & role_mask & *ours.get(role) {
|
||||||
moves.extend(
|
moves.extend(MoveSet::PieceMove {
|
||||||
(global_mask_to & !us & pinned & lookup::line(king_square, from)).map(
|
|
||||||
|to| RawMove {
|
|
||||||
kind: MoveType::PieceMove,
|
|
||||||
from,
|
|
||||||
to,
|
|
||||||
role,
|
role,
|
||||||
},
|
from,
|
||||||
),
|
to: global_mask_to & !us & pinned & lookup::line(king_square, from),
|
||||||
)?;
|
})?;
|
||||||
}
|
}
|
||||||
ControlFlow::Continue(())
|
ControlFlow::Continue(())
|
||||||
};
|
};
|
||||||
|
|
@ -1136,68 +1238,8 @@ impl MoveGen<Infallible> for MateMoveGenImpl {
|
||||||
ControlFlow::Continue(())
|
ControlFlow::Continue(())
|
||||||
}
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
fn extend<I>(&mut self, iter: I) -> ControlFlow<Infallible>
|
fn extend(&mut self, s: MoveSet) -> ControlFlow<Infallible> {
|
||||||
where
|
self.is_mate &= s.is_empty();
|
||||||
I: Iterator<Item = RawMove> + ExactSizeIterator,
|
|
||||||
{
|
|
||||||
self.is_mate &= iter.len() == 0;
|
|
||||||
ControlFlow::Continue(())
|
ControlFlow::Continue(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct MoveAndPromote<I: Iterator<Item = RawMove> + ExactSizeIterator + FusedIterator> {
|
|
||||||
role: u8,
|
|
||||||
inner: I,
|
|
||||||
cur: core::mem::MaybeUninit<RawMove>,
|
|
||||||
}
|
|
||||||
impl<I> MoveAndPromote<I>
|
|
||||||
where
|
|
||||||
I: Iterator<Item = RawMove> + ExactSizeIterator + FusedIterator,
|
|
||||||
{
|
|
||||||
#[inline]
|
|
||||||
fn new(inner: I) -> Self {
|
|
||||||
Self {
|
|
||||||
role: 1,
|
|
||||||
inner,
|
|
||||||
cur: core::mem::MaybeUninit::uninit(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<I> Iterator for MoveAndPromote<I>
|
|
||||||
where
|
|
||||||
I: Iterator<Item = RawMove> + ExactSizeIterator + FusedIterator,
|
|
||||||
{
|
|
||||||
type Item = RawMove;
|
|
||||||
#[inline]
|
|
||||||
fn next(&mut self) -> Option<RawMove> {
|
|
||||||
if self.role == 1 {
|
|
||||||
self.cur.write(self.inner.next()?);
|
|
||||||
self.role = 5;
|
|
||||||
}
|
|
||||||
let raw = unsafe { self.cur.assume_init() };
|
|
||||||
let res = RawMove {
|
|
||||||
role: unsafe { Role::transmute(self.role) },
|
|
||||||
..raw
|
|
||||||
};
|
|
||||||
self.role = unsafe { self.role.unchecked_sub(1) };
|
|
||||||
Some(res)
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
|
||||||
let len = self.len();
|
|
||||||
(len, Some(len))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<I> FusedIterator for MoveAndPromote<I> where
|
|
||||||
I: Iterator<Item = RawMove> + ExactSizeIterator + FusedIterator
|
|
||||||
{
|
|
||||||
}
|
|
||||||
impl<I> ExactSizeIterator for MoveAndPromote<I>
|
|
||||||
where
|
|
||||||
I: Iterator<Item = RawMove> + ExactSizeIterator + FusedIterator,
|
|
||||||
{
|
|
||||||
#[inline]
|
|
||||||
fn len(&self) -> usize {
|
|
||||||
self.inner.len() * 4 + self.role as usize - 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue