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
|
||||
}
|
||||
#[inline]
|
||||
fn extend<I>(&mut self, iter: I) -> ControlFlow<Infallible>
|
||||
where
|
||||
I: Iterator<Item = RawMove> + ExactSizeIterator,
|
||||
{
|
||||
iter.for_each(|raw| {
|
||||
fn extend(&mut self, s: MoveSet) -> ControlFlow<Infallible> {
|
||||
s.for_each(|raw| {
|
||||
debug_assert!(raw.role() as u8 == ROLE);
|
||||
debug_assert!(self.to.contains(raw.to()));
|
||||
self.candidates.insert(raw.from);
|
||||
|
|
@ -236,11 +233,8 @@ impl<'l> MoveGen<Infallible> for Moves<'l> {
|
|||
ControlFlow::Continue(())
|
||||
}
|
||||
#[inline]
|
||||
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) });
|
||||
fn extend(&mut self, s: MoveSet) -> ControlFlow<Infallible> {
|
||||
s.for_each(|raw| unsafe { self.array.push_unchecked(raw) });
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
426
src/position.rs
426
src/position.rs
|
|
@ -9,7 +9,6 @@ use crate::setup::*;
|
|||
use crate::uci::*;
|
||||
|
||||
use core::convert::Infallible;
|
||||
use core::iter::{ExactSizeIterator, FusedIterator};
|
||||
use core::ops::ControlFlow;
|
||||
|
||||
/// **A chess position.**
|
||||
|
|
@ -118,11 +117,8 @@ impl Position {
|
|||
}
|
||||
}
|
||||
impl MoveGen<Infallible> for MoveGenImpl {
|
||||
fn extend<I>(&mut self, iter: I) -> ControlFlow<Infallible>
|
||||
where
|
||||
I: Iterator<Item = RawMove> + ExactSizeIterator,
|
||||
{
|
||||
self.len += iter.len();
|
||||
fn extend(&mut self, s: MoveSet) -> ControlFlow<Infallible> {
|
||||
self.len += s.len();
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
}
|
||||
|
|
@ -322,19 +318,17 @@ impl Position {
|
|||
self.to
|
||||
}
|
||||
#[inline]
|
||||
fn extend<I>(&mut self, iter: I) -> ControlFlow<RawMove>
|
||||
where
|
||||
I: Iterator<Item = RawMove> + ExactSizeIterator,
|
||||
{
|
||||
for raw in iter {
|
||||
fn extend(&mut self, s: MoveSet) -> ControlFlow<RawMove> {
|
||||
let mut res = ControlFlow::Continue(());
|
||||
s.for_each(|raw| {
|
||||
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 {
|
||||
return ControlFlow::Break(raw);
|
||||
res = ControlFlow::Break(raw);
|
||||
}
|
||||
}
|
||||
ControlFlow::Continue(())
|
||||
});
|
||||
res
|
||||
}
|
||||
}
|
||||
let UciMove {
|
||||
|
|
@ -393,11 +387,8 @@ impl Position {
|
|||
self.to
|
||||
}
|
||||
#[inline]
|
||||
fn extend<I>(&mut self, iter: I) -> ControlFlow<Infallible>
|
||||
where
|
||||
I: Iterator<Item = RawMove> + ExactSizeIterator,
|
||||
{
|
||||
iter.for_each(|raw| {
|
||||
fn extend(&mut self, s: MoveSet) -> ControlFlow<Infallible> {
|
||||
s.for_each(|raw| {
|
||||
debug_assert!(raw.role() as u8 == ROLE);
|
||||
debug_assert!(self.from.contains(raw.from()));
|
||||
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> {
|
||||
#[inline]
|
||||
fn roles(&self, _role: Role) -> bool {
|
||||
|
|
@ -589,10 +768,8 @@ pub(crate) trait MoveGen<S> {
|
|||
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,
|
||||
{
|
||||
#[inline]
|
||||
fn extend(&mut self, _s: MoveSet) -> ControlFlow<S> {
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
}
|
||||
|
|
@ -670,14 +847,10 @@ impl Position {
|
|||
.reduce_or()
|
||||
};
|
||||
// king moves
|
||||
moves.extend(
|
||||
(global_mask_to & lookup::king(king_square) & !us & !attacked).map(|to| RawMove {
|
||||
kind: MoveType::KingMove,
|
||||
moves.extend(MoveSet::KingMove {
|
||||
from: king_square,
|
||||
to,
|
||||
role: Role::King,
|
||||
}),
|
||||
)?;
|
||||
to: global_mask_to & lookup::king(king_square) & !us & !attacked,
|
||||
})?;
|
||||
// castling
|
||||
if castling_rights.get(turn, CastlingSide::Short) {
|
||||
let (x, y) = match turn {
|
||||
|
|
@ -691,12 +864,7 @@ impl Position {
|
|||
.trans_unchecked(Direction::East)
|
||||
};
|
||||
if global_mask_to.contains(to) {
|
||||
moves.extend(core::iter::once(RawMove {
|
||||
kind: MoveType::CastleShort,
|
||||
from,
|
||||
to,
|
||||
role: Role::King,
|
||||
}))?;
|
||||
moves.extend(MoveSet::CastleShort { from, to })?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -712,12 +880,7 @@ impl Position {
|
|||
.trans_unchecked(Direction::West)
|
||||
};
|
||||
if global_mask_to.contains(to) {
|
||||
moves.extend(core::iter::once(RawMove {
|
||||
kind: MoveType::CastleLong,
|
||||
from,
|
||||
to,
|
||||
role: Role::King,
|
||||
}))?;
|
||||
moves.extend(MoveSet::CastleLong { from, to })?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -757,80 +920,34 @@ impl Position {
|
|||
let adv = (global_mask_from & ours.pawn() & (!pinned | king_square.file().bitboard()))
|
||||
.trans(forward)
|
||||
& !blockers;
|
||||
let promotion = turn.promotion_rank().bitboard();
|
||||
// pawn advances
|
||||
{
|
||||
let targets = adv & target_mask;
|
||||
moves.extend((targets & !promotion).map(|to| RawMove {
|
||||
kind: MoveType::PawnAdvance,
|
||||
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,
|
||||
}
|
||||
})))?;
|
||||
moves.extend(MoveSet::PawnAdvance {
|
||||
from: !forward,
|
||||
to: adv & target_mask,
|
||||
})?;
|
||||
}
|
||||
// pawn attacks kingside
|
||||
{
|
||||
let targets =
|
||||
(global_mask_from & ours.pawn() & (!pinned | lookup::ray(king_square, kside)))
|
||||
moves.extend(MoveSet::PawnAttack {
|
||||
from: !kside,
|
||||
to: (global_mask_from & ours.pawn() & (!pinned | lookup::ray(king_square, kside)))
|
||||
.trans(kside)
|
||||
& them
|
||||
& 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,
|
||||
}
|
||||
})))?;
|
||||
}
|
||||
& target_mask,
|
||||
})?;
|
||||
// pawn attacks queenside
|
||||
{
|
||||
let targets =
|
||||
(global_mask_from & ours.pawn() & (!pinned | lookup::ray(king_square, qside)))
|
||||
moves.extend(MoveSet::PawnAttack {
|
||||
from: !qside,
|
||||
to: (global_mask_from & ours.pawn() & (!pinned | lookup::ray(king_square, qside)))
|
||||
.trans(qside)
|
||||
& them
|
||||
& 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,
|
||||
}
|
||||
})))?;
|
||||
}
|
||||
& target_mask,
|
||||
})?;
|
||||
// pawn double advances
|
||||
moves.extend(
|
||||
((adv & third_rank.bitboard()).trans(forward) & !blockers & target_mask).map(
|
||||
|to| RawMove {
|
||||
kind: MoveType::PawnDoubleAdvance,
|
||||
from: unsafe { to.trans_unchecked(!forward).trans_unchecked(!forward) },
|
||||
to,
|
||||
role: Role::Pawn,
|
||||
},
|
||||
),
|
||||
)?;
|
||||
moves.extend(MoveSet::PawnDoubleAdvance {
|
||||
from: !forward,
|
||||
to: (adv & third_rank.bitboard()).trans(forward) & !blockers & target_mask,
|
||||
})?;
|
||||
// en passant
|
||||
if let Some(to) = en_passant {
|
||||
if global_mask_to.contains(to) {
|
||||
|
|
@ -855,12 +972,7 @@ impl Position {
|
|||
& (!pinned | lookup::segment(king_square, to))
|
||||
{
|
||||
moves.en_passant_is_legal()?;
|
||||
moves.extend(core::iter::once(RawMove {
|
||||
kind: MoveType::EnPassant,
|
||||
from,
|
||||
to,
|
||||
role: Role::Pawn,
|
||||
}))?;
|
||||
moves.extend(MoveSet::EnPassant { from, to })?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -871,16 +983,11 @@ impl Position {
|
|||
{
|
||||
let aux = |moves: &mut T, role| {
|
||||
for from in global_mask_from & *ours.get(role) & !pinned {
|
||||
moves.extend(
|
||||
(lookup::targets(role, from, blockers) & !us & target_mask).map(|to| {
|
||||
RawMove {
|
||||
kind: MoveType::PieceMove,
|
||||
from,
|
||||
to,
|
||||
moves.extend(MoveSet::PieceMove {
|
||||
role,
|
||||
}
|
||||
}),
|
||||
)?;
|
||||
from,
|
||||
to: lookup::targets(role, from, blockers) & !us & target_mask,
|
||||
})?;
|
||||
}
|
||||
ControlFlow::Continue(())
|
||||
};
|
||||
|
|
@ -907,16 +1014,11 @@ impl Position {
|
|||
{
|
||||
let aux = |moves: &mut T, role, role_mask| {
|
||||
for from in global_mask_from & pinned & role_mask & *ours.get(role) {
|
||||
moves.extend(
|
||||
(global_mask_to & !us & pinned & lookup::line(king_square, from)).map(
|
||||
|to| RawMove {
|
||||
kind: MoveType::PieceMove,
|
||||
from,
|
||||
to,
|
||||
moves.extend(MoveSet::PieceMove {
|
||||
role,
|
||||
},
|
||||
),
|
||||
)?;
|
||||
from,
|
||||
to: global_mask_to & !us & pinned & lookup::line(king_square, from),
|
||||
})?;
|
||||
}
|
||||
ControlFlow::Continue(())
|
||||
};
|
||||
|
|
@ -1136,68 +1238,8 @@ impl MoveGen<Infallible> for MateMoveGenImpl {
|
|||
ControlFlow::Continue(())
|
||||
}
|
||||
#[inline]
|
||||
fn extend<I>(&mut self, iter: I) -> ControlFlow<Infallible>
|
||||
where
|
||||
I: Iterator<Item = RawMove> + ExactSizeIterator,
|
||||
{
|
||||
self.is_mate &= iter.len() == 0;
|
||||
fn extend(&mut self, s: MoveSet) -> ControlFlow<Infallible> {
|
||||
self.is_mate &= s.is_empty();
|
||||
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