Rework the Pawn move generator to correctly compute en passant moves

This commit is contained in:
Eryn Wells 2024-02-11 09:57:29 -07:00
parent 3b8b6b36e3
commit c03a804c79

View file

@ -1,14 +1,22 @@
// Eryn Wells <eryn@erynwells.me>
use super::{move_generator_declaration, MoveGeneratorInternal, MoveSet};
use crate::Position;
use crate::{r#move::Move, MoveBuilder, Position};
use chessfriend_bitboard::BitBoard;
use chessfriend_core::{Color, PlacedPiece, Rank, Shape, Square};
use std::collections::BTreeMap;
#[derive(Debug)]
struct MoveIterator(usize, usize);
move_generator_declaration!(PawnMoveGenerator);
#[derive(Clone, Debug, Eq, PartialEq)]
pub(super) struct PawnMoveGenerator {
color: chessfriend_core::Color,
move_sets: BTreeMap<Square, MoveSet>,
en_passant_captures: Vec<Move>,
}
move_generator_declaration!(PawnMoveGenerator, getters);
impl MoveGeneratorInternal for PawnMoveGenerator {
fn shape() -> Shape {
@ -31,7 +39,50 @@ impl MoveGeneratorInternal for PawnMoveGenerator {
}
impl PawnMoveGenerator {
fn pushes(position: &Position, piece: PlacedPiece) -> BitBoard {
pub(super) fn new(
position: &Position,
color: Color,
capture_mask: BitBoard,
push_mask: BitBoard,
) -> Self {
let move_sets = if !capture_mask.is_empty() && !push_mask.is_empty() {
Self::move_sets(position, color, capture_mask, push_mask)
} else {
std::collections::BTreeMap::new()
};
Self {
color,
move_sets,
en_passant_captures: Vec::new(),
}
}
fn move_sets(
position: &Position,
color: Color,
capture_mask: BitBoard,
push_mask: BitBoard,
) -> BTreeMap<Square, MoveSet> {
let piece = Self::piece(color);
let mut moves_for_pieces =
BTreeMap::from_iter(position.bitboard_for_piece(piece).occupied_squares().map(
|square| {
let piece = PlacedPiece::new(piece, square);
let move_set =
Self::move_set_for_piece(position, &piece, capture_mask, push_mask);
(square, move_set)
},
));
if position.has_en_passant_square() {
}
moves_for_pieces
}
fn pushes(position: &Position, piece: &PlacedPiece) -> BitBoard {
let color = piece.color();
let square = piece.square();
let bitboard: BitBoard = square.into();
@ -59,16 +110,40 @@ impl PawnMoveGenerator {
}
}
fn attacks(position: &Position, piece: PlacedPiece) -> BitBoard {
fn attacks(position: &Position, piece: &PlacedPiece) -> BitBoard {
let color = piece.color();
let opponent_pieces = position.bitboard_for_color(color.other());
let en_passant_bitboard = match position.en_passant_square() {
Some(square) => <Square as Into<BitBoard>>::into(square),
None => BitBoard::empty(),
};
BitBoard::pawn_attacks(piece.square(), color) & (opponent_pieces | en_passant_bitboard)
BitBoard::pawn_attacks(piece.square(), color) & opponent_pieces
}
fn en_passant_attack(position: &Position, piece: &PlacedPiece) -> Option<Move> {
match position.en_passant() {
Some(en_passant) => {
let en_passant_bitboard: BitBoard = en_passant.target_square().into();
let capture =
BitBoard::pawn_attacks(piece.square(), piece.color()) & en_passant_bitboard;
if capture.is_empty() {
return None;
}
match position.piece_on_square(en_passant.capture_square()) {
Some(captured_piece) => Some(
MoveBuilder::new(
*piece.piece(),
piece.square(),
en_passant.target_square(),
)
.capturing_en_passant(captured_piece)
.build(),
),
None => None,
}
}
None => None,
}
}
}