[moves] Remove special handling of EnPassant moves
Instead of generating e.p. moves in a separate pass, check whether each capture move (left and right) targets the en passant square. If so, yield an e.p. capture otherwise just a regular capture.
This commit is contained in:
parent
bba910090c
commit
428ace13dc
1 changed files with 25 additions and 47 deletions
|
@ -27,7 +27,6 @@ enum MoveType {
|
||||||
DoublePushes,
|
DoublePushes,
|
||||||
LeftCaptures,
|
LeftCaptures,
|
||||||
RightCaptures,
|
RightCaptures,
|
||||||
EnPassant,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct PromotionIterator {
|
struct PromotionIterator {
|
||||||
|
@ -62,10 +61,6 @@ impl PawnMoveGenerator {
|
||||||
let (single_pushes, double_pushes) = Self::pushes(pawns, color, empty);
|
let (single_pushes, double_pushes) = Self::pushes(pawns, color, empty);
|
||||||
let (left_captures, right_captures) = Self::captures(pawns, color, enemies | en_passant);
|
let (left_captures, right_captures) = Self::captures(pawns, color, enemies | en_passant);
|
||||||
|
|
||||||
let en_passant = en_passant & (left_captures | right_captures);
|
|
||||||
let left_captures = left_captures & !en_passant;
|
|
||||||
let right_captures = right_captures & !en_passant;
|
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
color,
|
color,
|
||||||
single_pushes,
|
single_pushes,
|
||||||
|
@ -137,22 +132,6 @@ impl PawnMoveGenerator {
|
||||||
Color::White => target.neighbor(Direction::SouthWest),
|
Color::White => target.neighbor(Direction::SouthWest),
|
||||||
Color::Black => target.neighbor(Direction::NorthEast),
|
Color::Black => target.neighbor(Direction::NorthEast),
|
||||||
},
|
},
|
||||||
MoveType::EnPassant => match self.color {
|
|
||||||
Color::White => {
|
|
||||||
if (self.en_passant & self.left_captures).is_populated() {
|
|
||||||
target.neighbor(Direction::SouthEast)
|
|
||||||
} else {
|
|
||||||
target.neighbor(Direction::SouthWest)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Color::Black => {
|
|
||||||
if (self.en_passant & self.left_captures).is_populated() {
|
|
||||||
target.neighbor(Direction::NorthWest)
|
|
||||||
} else {
|
|
||||||
target.neighbor(Direction::NorthEast)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,7 +144,6 @@ impl PawnMoveGenerator {
|
||||||
MoveType::DoublePushes => self.double_pushes,
|
MoveType::DoublePushes => self.double_pushes,
|
||||||
MoveType::LeftCaptures => self.left_captures,
|
MoveType::LeftCaptures => self.left_captures,
|
||||||
MoveType::RightCaptures => self.right_captures,
|
MoveType::RightCaptures => self.right_captures,
|
||||||
MoveType::EnPassant => self.en_passant,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
self.target_iterator = next_bitboard.occupied_squares_trailing();
|
self.target_iterator = next_bitboard.occupied_squares_trailing();
|
||||||
|
@ -229,12 +207,16 @@ impl std::iter::Iterator for PawnMoveGenerator {
|
||||||
MoveType::DoublePushes => Some(GeneratedMove {
|
MoveType::DoublePushes => Some(GeneratedMove {
|
||||||
ply: Move::double_push(origin, target),
|
ply: Move::double_push(origin, target),
|
||||||
}),
|
}),
|
||||||
MoveType::LeftCaptures | MoveType::RightCaptures => Some(GeneratedMove {
|
MoveType::LeftCaptures | MoveType::RightCaptures => {
|
||||||
ply: Move::capture(origin, target),
|
let target_bitboard: BitBoard = target.into();
|
||||||
}),
|
Some(GeneratedMove {
|
||||||
MoveType::EnPassant => Some(GeneratedMove {
|
ply: if (target_bitboard & self.en_passant).is_populated() {
|
||||||
ply: Move::en_passant_capture(origin, target),
|
Move::en_passant_capture(origin, target)
|
||||||
}),
|
} else {
|
||||||
|
Move::capture(origin, target)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if self.next_move_type().is_some() {
|
} else if self.next_move_type().is_some() {
|
||||||
self.next()
|
self.next()
|
||||||
|
@ -252,8 +234,7 @@ impl MoveType {
|
||||||
MoveType::SinglePushes => Some(MoveType::DoublePushes),
|
MoveType::SinglePushes => Some(MoveType::DoublePushes),
|
||||||
MoveType::DoublePushes => Some(MoveType::LeftCaptures),
|
MoveType::DoublePushes => Some(MoveType::LeftCaptures),
|
||||||
MoveType::LeftCaptures => Some(MoveType::RightCaptures),
|
MoveType::LeftCaptures => Some(MoveType::RightCaptures),
|
||||||
MoveType::RightCaptures => Some(MoveType::EnPassant),
|
MoveType::RightCaptures => None,
|
||||||
MoveType::EnPassant => None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -261,8 +242,8 @@ impl MoveType {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::{assert_move_list, assert_move_list_does_not_contain, ply, Move};
|
use crate::{assert_move_list, assert_move_list_contains, assert_move_list_does_not_contain, ply, Move};
|
||||||
use chessfriend_board::test_board;
|
use chessfriend_board::{fen::FromFenStr, test_board};
|
||||||
use chessfriend_core::{Color, Square};
|
use chessfriend_core::{Color, Square};
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
|
@ -370,20 +351,8 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn black_d5_left_captures() {
|
fn black_d5_left_captures() {
|
||||||
let black_captures_board = test_board!(Black Pawn on D5, White Queen on E4);
|
let black_captures_board = test_board!(Black Pawn on D5, White Queen on E4);
|
||||||
let generated_moves: HashSet<GeneratedMove> =
|
let generated_moves = PawnMoveGenerator::new(&black_captures_board, Some(Color::Black));
|
||||||
PawnMoveGenerator::new(&black_captures_board, Some(Color::Black)).collect();
|
assert_move_list!(generated_moves, [ply!(D5 x E4), ply!(D5 - D4),]);
|
||||||
assert_eq!(
|
|
||||||
generated_moves,
|
|
||||||
[
|
|
||||||
GeneratedMove {
|
|
||||||
ply: Move::capture(Square::D5, Square::E4)
|
|
||||||
},
|
|
||||||
GeneratedMove {
|
|
||||||
ply: Move::quiet(Square::D5, Square::D4)
|
|
||||||
}
|
|
||||||
]
|
|
||||||
.into()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -527,7 +496,7 @@ mod tests {
|
||||||
|
|
||||||
let generated_moves = PawnMoveGenerator::new(&board, None);
|
let generated_moves = PawnMoveGenerator::new(&board, None);
|
||||||
|
|
||||||
assert_move_list!(generated_moves, [ply!(E5 - E6), ply!(E5 x F6 e.p.),]);
|
assert_move_list!(generated_moves, [ply!(E5 - E6), ply!(E5 x F6 e.p.)]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -556,4 +525,13 @@ mod tests {
|
||||||
|
|
||||||
assert_move_list_does_not_contain!(generated_moves, [ply!(B4 x A3 e.p.)]);
|
assert_move_list_does_not_contain!(generated_moves, [ply!(B4 x A3 e.p.)]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn black_en_passant_check() {
|
||||||
|
let board = Board::from_fen_str("8/8/8/2k5/2pP4/8/B7/4K3 b - d3 0 3").expect("invalid fen");
|
||||||
|
println!("{}", board.display());
|
||||||
|
|
||||||
|
let generated_moves: HashSet<_> = PawnMoveGenerator::new(&board, None).collect();
|
||||||
|
assert_move_list_contains!(generated_moves, [ply!(C4 x D3 e.p.)]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue