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