[position] Implement generating pawn moves by looking up bitboards in the Library

This enables a bunch of clean up! Remove the MoveGenerationParameters and MoveList
types from move_generator::pawn.

Implement BitBoard::pawn_pushes to look up pawn pushes by square and color.
This commit is contained in:
Eryn Wells 2024-01-28 10:25:01 -08:00
parent 77f419ad3b
commit ea74b214da
3 changed files with 48 additions and 72 deletions

View file

@ -1,27 +1,13 @@
// Eryn Wells <eryn@erynwells.me>
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, &parameters);
let quiet_moves_bitboard = Self::pushes(position, placed_piece, &parameters);
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| <Square as Into<BitBoard>>::into(square))
.unwrap_or(BitBoard::empty());
let en_passant_bitboard = match position.en_passant_square() {
Some(square) => <Square as Into<BitBoard>>::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);