diff --git a/bitboard/src/bitboard.rs b/bitboard/src/bitboard.rs index f9babd4..fa91c16 100644 --- a/bitboard/src/bitboard.rs +++ b/bitboard/src/bitboard.rs @@ -44,6 +44,10 @@ impl BitBoard { library().pawn_attacks(sq, color) } + pub fn pawn_pushes(sq: Square, color: Color) -> BitBoard { + library().pawn_pushes(sq, color) + } + moves_getter!(knight_moves); moves_getter!(bishop_moves); moves_getter!(rook_moves); diff --git a/bitboard/src/library.rs b/bitboard/src/library.rs index cc37100..6e51f24 100644 --- a/bitboard/src/library.rs +++ b/bitboard/src/library.rs @@ -58,6 +58,7 @@ pub(super) struct MoveLibrary { // Piecewise move tables pawn_attacks: [[BitBoard; 64]; 2], + pawn_pushes: [[BitBoard; 64]; 2], knight_moves: [BitBoard; 64], bishop_moves: [BitBoard; 64], rook_moves: [BitBoard; 64], @@ -70,6 +71,7 @@ impl MoveLibrary { MoveLibrary { rays: [[BitBoard::empty(); 8]; Square::NUM], pawn_attacks: [[BitBoard::empty(); 64]; 2], + pawn_pushes: [[BitBoard::empty(); 64]; 2], knight_moves: [BitBoard::empty(); 64], bishop_moves: [BitBoard::empty(); 64], rook_moves: [BitBoard::empty(); 64], @@ -169,10 +171,29 @@ impl MoveLibrary { fn init_pawn_moves(&mut self, sq: Square) { let bitboard: BitBoard = sq.into(); + self.pawn_attacks[Color::White as usize][sq as usize] = bitboard.shift_north_west_one() | bitboard.shift_north_east_one(); self.pawn_attacks[Color::Black as usize][sq as usize] = bitboard.shift_south_west_one() | bitboard.shift_south_east_one(); + + self.pawn_pushes[Color::White as usize][sq as usize] = { + let mut push = bitboard.shift_north_one(); + if !(bitboard & RANKS[1]).is_empty() { + push |= push.shift_north_one(); + } + + push + }; + + self.pawn_pushes[Color::Black as usize][sq as usize] = { + let mut push = bitboard.shift_south_one(); + if !(bitboard & RANKS[6]).is_empty() { + push |= push.shift_south_one(); + } + + push + }; } #[inline] @@ -192,6 +213,10 @@ impl MoveLibrary { self.rays[sq as usize][dir as usize] } + pub(super) fn pawn_pushes(&self, sq: Square, color: Color) -> BitBoard { + self.pawn_pushes[color as usize][sq as usize] + } + pub(super) fn pawn_attacks(&self, sq: Square, color: Color) -> BitBoard { self.pawn_attacks[color as usize][sq as usize] } diff --git a/position/src/move_generator/pawn.rs b/position/src/move_generator/pawn.rs index 860c564..3d6d5f4 100644 --- a/position/src/move_generator/pawn.rs +++ b/position/src/move_generator/pawn.rs @@ -1,27 +1,13 @@ // Eryn Wells use super::{move_generator_declaration, MoveGeneratorInternal, MoveSet}; -use crate::{Move, MoveBuilder, Position}; +use crate::{MoveBuilder, Position}; use chessfriend_bitboard::BitBoard; -use chessfriend_core::{Color, Piece, PlacedPiece, Shape, Square}; - -enum MoveList { - Quiet = 0, - Promotions = 1, - Captures = 2, -} +use chessfriend_core::{Color, Piece, PlacedPiece, Square}; #[derive(Debug)] struct MoveIterator(usize, usize); -struct MoveGenerationParameters { - starting_rank: BitBoard, - promotion_rank: BitBoard, - push_shift: fn(&BitBoard) -> BitBoard, - left_capture_shift: fn(&BitBoard) -> BitBoard, - right_capture_shift: fn(&BitBoard) -> BitBoard, -} - move_generator_declaration!(PawnMoveGenerator); impl MoveGeneratorInternal for PawnMoveGenerator { @@ -31,12 +17,9 @@ impl MoveGeneratorInternal for PawnMoveGenerator { fn move_set_for_piece(position: &Position, placed_piece: PlacedPiece) -> MoveSet { let from_square = placed_piece.square(); - let parameters = Self::move_generation_parameters(placed_piece.color()); - let opposing_pieces = position.opposing_pieces(); - - let captures_bitboard = Self::attacks(position, placed_piece, ¶meters); - let quiet_moves_bitboard = Self::pushes(position, placed_piece, ¶meters); + let captures_bitboard = Self::attacks(position, placed_piece); + let quiet_moves_bitboard = Self::pushes(position, placed_piece); let quiet_moves = quiet_moves_bitboard.occupied_squares().map(|to_square| { MoveBuilder::new(*placed_piece.piece(), from_square, to_square).build() @@ -55,67 +38,34 @@ impl MoveGeneratorInternal for PawnMoveGenerator { } impl PawnMoveGenerator { - fn move_generation_parameters(color: Color) -> MoveGenerationParameters { - match color { - Color::White => MoveGenerationParameters { - starting_rank: BitBoard::rank(1), - promotion_rank: BitBoard::rank(7), - push_shift: BitBoard::shift_north_one, - left_capture_shift: BitBoard::shift_north_west_one, - right_capture_shift: BitBoard::shift_north_east_one, - }, - Color::Black => MoveGenerationParameters { - starting_rank: BitBoard::rank(6), - promotion_rank: BitBoard::rank(0), - push_shift: BitBoard::shift_south_one, - left_capture_shift: BitBoard::shift_south_east_one, - right_capture_shift: BitBoard::shift_south_west_one, - }, - } - } - - fn pushes( - position: &Position, - piece: PlacedPiece, - parameters: &MoveGenerationParameters, - ) -> BitBoard { + fn pushes(position: &Position, piece: PlacedPiece) -> BitBoard { let empty_squares = position.empty_squares(); - let from_square: BitBoard = piece.square().into(); - - (parameters.push_shift)(&from_square) & empty_squares + BitBoard::pawn_pushes(piece.square(), piece.color()) & empty_squares } - fn attacks( - position: &Position, - piece: PlacedPiece, - parameters: &MoveGenerationParameters, - ) -> BitBoard { + fn attacks(position: &Position, piece: PlacedPiece) -> BitBoard { let color = piece.color(); let opponent_pieces = position.bitboard_for_color(color.other()); - let en_passant_square = position - .en_passant_square() - .map(|square| >::into(square)) - .unwrap_or(BitBoard::empty()); + let en_passant_bitboard = match position.en_passant_square() { + Some(square) => >::into(square), + None => BitBoard::empty(), + }; - let from_square: BitBoard = piece.square().into(); - - ((parameters.left_capture_shift)(&from_square) - | (parameters.right_capture_shift)(&from_square)) - & (opponent_pieces | en_passant_square) + BitBoard::pawn_attacks(piece.square(), color) & (opponent_pieces | en_passant_bitboard) } } #[cfg(test)] mod tests { use super::*; - use crate::{position, position::DiagramFormatter}; + use crate::{position::DiagramFormatter, test_position, Move}; use chessfriend_core::{piece, Square}; use std::collections::HashSet; #[test] fn one_2square_push() { - let pos = position![White Pawn on E2]; + let pos = test_position![White Pawn on E2]; let generator = PawnMoveGenerator::new(&pos, Color::White); @@ -131,7 +81,7 @@ mod tests { #[test] fn one_1square_push() { - let mut pos = position![White Pawn on E3]; + let pos = test_position![White Pawn on E3]; let generator = PawnMoveGenerator::new(&pos, Color::White); @@ -149,7 +99,7 @@ mod tests { #[test] fn one_obstructed_2square_push() { - let pos = position![ + let pos = test_position![ White Pawn on E2, White Knight on E4, ]; @@ -172,11 +122,10 @@ mod tests { #[test] fn one_obstructed_1square_push() { - let mut pos = position![ + let pos = test_position![ White Pawn on E2, White Knight on E3, ]; - println!("{}", DiagramFormatter::new(&pos)); let generator = PawnMoveGenerator::new(&pos, Color::White); @@ -187,12 +136,11 @@ mod tests { #[test] fn one_attack() { - let pos = position![ + let pos = test_position![ White Pawn on E4, White Bishop on E5, Black Knight on D5, ]; - println!("{}", DiagramFormatter::new(&pos)); let generator = PawnMoveGenerator::new(&pos, Color::White); @@ -210,13 +158,12 @@ mod tests { #[test] fn one_double_attack() { - let pos = position![ + let pos = test_position![ White Pawn on E4, White Bishop on E5, Black Knight on D5, Black Queen on F5, ]; - println!("{}", DiagramFormatter::new(&pos)); let generator = PawnMoveGenerator::new(&pos, Color::White);