[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:
parent
77f419ad3b
commit
ea74b214da
3 changed files with 48 additions and 72 deletions
|
@ -44,6 +44,10 @@ impl BitBoard {
|
||||||
library().pawn_attacks(sq, color)
|
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!(knight_moves);
|
||||||
moves_getter!(bishop_moves);
|
moves_getter!(bishop_moves);
|
||||||
moves_getter!(rook_moves);
|
moves_getter!(rook_moves);
|
||||||
|
|
|
@ -58,6 +58,7 @@ pub(super) struct MoveLibrary {
|
||||||
|
|
||||||
// Piecewise move tables
|
// Piecewise move tables
|
||||||
pawn_attacks: [[BitBoard; 64]; 2],
|
pawn_attacks: [[BitBoard; 64]; 2],
|
||||||
|
pawn_pushes: [[BitBoard; 64]; 2],
|
||||||
knight_moves: [BitBoard; 64],
|
knight_moves: [BitBoard; 64],
|
||||||
bishop_moves: [BitBoard; 64],
|
bishop_moves: [BitBoard; 64],
|
||||||
rook_moves: [BitBoard; 64],
|
rook_moves: [BitBoard; 64],
|
||||||
|
@ -70,6 +71,7 @@ impl MoveLibrary {
|
||||||
MoveLibrary {
|
MoveLibrary {
|
||||||
rays: [[BitBoard::empty(); 8]; Square::NUM],
|
rays: [[BitBoard::empty(); 8]; Square::NUM],
|
||||||
pawn_attacks: [[BitBoard::empty(); 64]; 2],
|
pawn_attacks: [[BitBoard::empty(); 64]; 2],
|
||||||
|
pawn_pushes: [[BitBoard::empty(); 64]; 2],
|
||||||
knight_moves: [BitBoard::empty(); 64],
|
knight_moves: [BitBoard::empty(); 64],
|
||||||
bishop_moves: [BitBoard::empty(); 64],
|
bishop_moves: [BitBoard::empty(); 64],
|
||||||
rook_moves: [BitBoard::empty(); 64],
|
rook_moves: [BitBoard::empty(); 64],
|
||||||
|
@ -169,10 +171,29 @@ impl MoveLibrary {
|
||||||
|
|
||||||
fn init_pawn_moves(&mut self, sq: Square) {
|
fn init_pawn_moves(&mut self, sq: Square) {
|
||||||
let bitboard: BitBoard = sq.into();
|
let bitboard: BitBoard = sq.into();
|
||||||
|
|
||||||
self.pawn_attacks[Color::White as usize][sq as usize] =
|
self.pawn_attacks[Color::White as usize][sq as usize] =
|
||||||
bitboard.shift_north_west_one() | bitboard.shift_north_east_one();
|
bitboard.shift_north_west_one() | bitboard.shift_north_east_one();
|
||||||
self.pawn_attacks[Color::Black as usize][sq as usize] =
|
self.pawn_attacks[Color::Black as usize][sq as usize] =
|
||||||
bitboard.shift_south_west_one() | bitboard.shift_south_east_one();
|
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]
|
#[inline]
|
||||||
|
@ -192,6 +213,10 @@ impl MoveLibrary {
|
||||||
self.rays[sq as usize][dir as usize]
|
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 {
|
pub(super) fn pawn_attacks(&self, sq: Square, color: Color) -> BitBoard {
|
||||||
self.pawn_attacks[color as usize][sq as usize]
|
self.pawn_attacks[color as usize][sq as usize]
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,27 +1,13 @@
|
||||||
// Eryn Wells <eryn@erynwells.me>
|
// Eryn Wells <eryn@erynwells.me>
|
||||||
|
|
||||||
use super::{move_generator_declaration, MoveGeneratorInternal, MoveSet};
|
use super::{move_generator_declaration, MoveGeneratorInternal, MoveSet};
|
||||||
use crate::{Move, MoveBuilder, Position};
|
use crate::{MoveBuilder, Position};
|
||||||
use chessfriend_bitboard::BitBoard;
|
use chessfriend_bitboard::BitBoard;
|
||||||
use chessfriend_core::{Color, Piece, PlacedPiece, Shape, Square};
|
use chessfriend_core::{Color, Piece, PlacedPiece, Square};
|
||||||
|
|
||||||
enum MoveList {
|
|
||||||
Quiet = 0,
|
|
||||||
Promotions = 1,
|
|
||||||
Captures = 2,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct MoveIterator(usize, usize);
|
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);
|
move_generator_declaration!(PawnMoveGenerator);
|
||||||
|
|
||||||
impl MoveGeneratorInternal for PawnMoveGenerator {
|
impl MoveGeneratorInternal for PawnMoveGenerator {
|
||||||
|
@ -31,12 +17,9 @@ impl MoveGeneratorInternal for PawnMoveGenerator {
|
||||||
|
|
||||||
fn move_set_for_piece(position: &Position, placed_piece: PlacedPiece) -> MoveSet {
|
fn move_set_for_piece(position: &Position, placed_piece: PlacedPiece) -> MoveSet {
|
||||||
let from_square = placed_piece.square();
|
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);
|
||||||
|
let quiet_moves_bitboard = Self::pushes(position, placed_piece);
|
||||||
let captures_bitboard = Self::attacks(position, placed_piece, ¶meters);
|
|
||||||
let quiet_moves_bitboard = Self::pushes(position, placed_piece, ¶meters);
|
|
||||||
|
|
||||||
let quiet_moves = quiet_moves_bitboard.occupied_squares().map(|to_square| {
|
let quiet_moves = quiet_moves_bitboard.occupied_squares().map(|to_square| {
|
||||||
MoveBuilder::new(*placed_piece.piece(), from_square, to_square).build()
|
MoveBuilder::new(*placed_piece.piece(), from_square, to_square).build()
|
||||||
|
@ -55,67 +38,34 @@ impl MoveGeneratorInternal for PawnMoveGenerator {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PawnMoveGenerator {
|
impl PawnMoveGenerator {
|
||||||
fn move_generation_parameters(color: Color) -> MoveGenerationParameters {
|
fn pushes(position: &Position, piece: PlacedPiece) -> BitBoard {
|
||||||
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 {
|
|
||||||
let empty_squares = position.empty_squares();
|
let empty_squares = position.empty_squares();
|
||||||
let from_square: BitBoard = piece.square().into();
|
BitBoard::pawn_pushes(piece.square(), piece.color()) & empty_squares
|
||||||
|
|
||||||
(parameters.push_shift)(&from_square) & empty_squares
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn attacks(
|
fn attacks(position: &Position, piece: PlacedPiece) -> BitBoard {
|
||||||
position: &Position,
|
|
||||||
piece: PlacedPiece,
|
|
||||||
parameters: &MoveGenerationParameters,
|
|
||||||
) -> BitBoard {
|
|
||||||
let color = piece.color();
|
let color = piece.color();
|
||||||
|
|
||||||
let opponent_pieces = position.bitboard_for_color(color.other());
|
let opponent_pieces = position.bitboard_for_color(color.other());
|
||||||
let en_passant_square = position
|
let en_passant_bitboard = match position.en_passant_square() {
|
||||||
.en_passant_square()
|
Some(square) => <Square as Into<BitBoard>>::into(square),
|
||||||
.map(|square| <Square as Into<BitBoard>>::into(square))
|
None => BitBoard::empty(),
|
||||||
.unwrap_or(BitBoard::empty());
|
};
|
||||||
|
|
||||||
let from_square: BitBoard = piece.square().into();
|
BitBoard::pawn_attacks(piece.square(), color) & (opponent_pieces | en_passant_bitboard)
|
||||||
|
|
||||||
((parameters.left_capture_shift)(&from_square)
|
|
||||||
| (parameters.right_capture_shift)(&from_square))
|
|
||||||
& (opponent_pieces | en_passant_square)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::{position, position::DiagramFormatter};
|
use crate::{position::DiagramFormatter, test_position, Move};
|
||||||
use chessfriend_core::{piece, Square};
|
use chessfriend_core::{piece, Square};
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn one_2square_push() {
|
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);
|
let generator = PawnMoveGenerator::new(&pos, Color::White);
|
||||||
|
|
||||||
|
@ -131,7 +81,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn one_1square_push() {
|
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);
|
let generator = PawnMoveGenerator::new(&pos, Color::White);
|
||||||
|
|
||||||
|
@ -149,7 +99,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn one_obstructed_2square_push() {
|
fn one_obstructed_2square_push() {
|
||||||
let pos = position![
|
let pos = test_position![
|
||||||
White Pawn on E2,
|
White Pawn on E2,
|
||||||
White Knight on E4,
|
White Knight on E4,
|
||||||
];
|
];
|
||||||
|
@ -172,11 +122,10 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn one_obstructed_1square_push() {
|
fn one_obstructed_1square_push() {
|
||||||
let mut pos = position![
|
let pos = test_position![
|
||||||
White Pawn on E2,
|
White Pawn on E2,
|
||||||
White Knight on E3,
|
White Knight on E3,
|
||||||
];
|
];
|
||||||
println!("{}", DiagramFormatter::new(&pos));
|
|
||||||
|
|
||||||
let generator = PawnMoveGenerator::new(&pos, Color::White);
|
let generator = PawnMoveGenerator::new(&pos, Color::White);
|
||||||
|
|
||||||
|
@ -187,12 +136,11 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn one_attack() {
|
fn one_attack() {
|
||||||
let pos = position![
|
let pos = test_position![
|
||||||
White Pawn on E4,
|
White Pawn on E4,
|
||||||
White Bishop on E5,
|
White Bishop on E5,
|
||||||
Black Knight on D5,
|
Black Knight on D5,
|
||||||
];
|
];
|
||||||
println!("{}", DiagramFormatter::new(&pos));
|
|
||||||
|
|
||||||
let generator = PawnMoveGenerator::new(&pos, Color::White);
|
let generator = PawnMoveGenerator::new(&pos, Color::White);
|
||||||
|
|
||||||
|
@ -210,13 +158,12 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn one_double_attack() {
|
fn one_double_attack() {
|
||||||
let pos = position![
|
let pos = test_position![
|
||||||
White Pawn on E4,
|
White Pawn on E4,
|
||||||
White Bishop on E5,
|
White Bishop on E5,
|
||||||
Black Knight on D5,
|
Black Knight on D5,
|
||||||
Black Queen on F5,
|
Black Queen on F5,
|
||||||
];
|
];
|
||||||
println!("{}", DiagramFormatter::new(&pos));
|
|
||||||
|
|
||||||
let generator = PawnMoveGenerator::new(&pos, Color::White);
|
let generator = PawnMoveGenerator::new(&pos, Color::White);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue