[position] Refactor sight routines

- Break out the actual routines into file-private helper functions
- Declare traits for each piece type that call the corresponding helper function
- Implement these traits on PlacedPiece

The sight routines changed slightly such that they include the player's own pieces
in the resulting BitBoard. The tests neeeded to be updated to account for this.
This commit is contained in:
Eryn Wells 2024-03-08 08:04:21 -08:00
parent f0b9681cef
commit 069f94e8c2

View file

@ -1,5 +1,9 @@
// Eryn Wells <eryn@erynwells.me>
//! Defines routines for computing sight of a piece. Sight is the set of squares
//! that a piece can see. In other words, it's the set of squares attacked or
//! controled by a piece.
use crate::position::piece_sets::PieceBitBoards;
use chessfriend_bitboard::BitBoard;
use chessfriend_core::{Color, Direction, PlacedPiece, Shape, Square};
@ -18,8 +22,84 @@ macro_rules! ray_in_direction {
}};
}
pub(crate) trait SightExt {
fn sight(&self, pieces: &PieceBitBoards, en_passant_square: Option<Square>) -> BitBoard;
/// Compute sight of a white pawn.
fn _white_pawn_sight(
pawn: &BitBoard,
occupancy: &BitBoard,
blockers: &BitBoard,
en_passant_square: &BitBoard,
) -> BitBoard {
let possible_squares = !occupancy | blockers | en_passant_square;
let pawn = pawn.shift_north_west_one() | pawn.shift_north_east_one();
pawn & possible_squares
}
fn _black_pawn_sight(
pawn: &BitBoard,
occupancy: &BitBoard,
blockers: &BitBoard,
en_passant_square: &BitBoard,
) -> BitBoard {
let possible_squares = !occupancy | blockers | en_passant_square;
let pawn = pawn.shift_south_west_one() | pawn.shift_south_east_one();
pawn & possible_squares
}
fn _knight_sight(knight_square: Square, blockers: &BitBoard) -> BitBoard {
BitBoard::knight_moves(knight_square) & !blockers
}
fn _bishop_sight(bishop_square: Square, occupancy: &BitBoard) -> BitBoard {
#[rustfmt::skip]
let sight = ray_in_direction!(bishop_square, occupancy, NorthEast, occupied_squares_trailing)
| ray_in_direction!(bishop_square, occupancy, NorthWest, occupied_squares_trailing)
| ray_in_direction!(bishop_square, occupancy, SouthEast, occupied_squares)
| ray_in_direction!(bishop_square, occupancy, SouthWest, occupied_squares);
sight
}
fn _rook_sight(rook_square: Square, occupancy: &BitBoard) -> BitBoard {
#[rustfmt::skip]
let sight = ray_in_direction!(rook_square, occupancy, North, occupied_squares_trailing)
| ray_in_direction!(rook_square, occupancy, East, occupied_squares_trailing)
| ray_in_direction!(rook_square, occupancy, South, occupied_squares)
| ray_in_direction!(rook_square, occupancy, West, occupied_squares);
sight
}
fn _queen_sight(queen_square: Square, occupancy: &BitBoard) -> BitBoard {
#[rustfmt::skip]
let sight = ray_in_direction!(queen_square, occupancy, NorthWest, occupied_squares_trailing)
| ray_in_direction!(queen_square, occupancy, North, occupied_squares_trailing)
| ray_in_direction!(queen_square, occupancy, NorthEast, occupied_squares_trailing)
| ray_in_direction!(queen_square, occupancy, East, occupied_squares_trailing)
| ray_in_direction!(queen_square, occupancy, SouthEast, occupied_squares)
| ray_in_direction!(queen_square, occupancy, South, occupied_squares)
| ray_in_direction!(queen_square, occupancy, SouthWest, occupied_squares)
| ray_in_direction!(queen_square, occupancy, West, occupied_squares);
sight
}
fn _king_sight(king_square: Square, blockers: &BitBoard) -> BitBoard {
BitBoard::king_moves(king_square) & !blockers
}
pub(crate) trait BishopSightExt {
fn bishop_sight(&self, occupancy: &BitBoard) -> BitBoard;
}
pub(crate) trait KingSightExt {
fn king_sight(&self, pieces: &PieceBitBoards) -> BitBoard;
}
pub(crate) trait KnightSightExt {
fn knight_sight(&self, pieces: &PieceBitBoards) -> BitBoard;
}
pub(crate) trait PawnSightExt {
fn pawn_sight(&self, pieces: &PieceBitBoards, en_passant_square: Option<Square>) -> BitBoard;
fn white_pawn_sight(
&self,
@ -32,12 +112,19 @@ pub(crate) trait SightExt {
pieces: &PieceBitBoards,
en_passant_square: Option<Square>,
) -> BitBoard;
}
pub(crate) trait QueenSightExt {
fn queen_sight(&self, occupancy: &BitBoard) -> BitBoard;
}
fn knight_sight(&self, pieces: &PieceBitBoards) -> BitBoard;
fn bishop_sight(&self, pieces: &PieceBitBoards) -> BitBoard;
fn rook_sight(&self, pieces: &PieceBitBoards) -> BitBoard;
fn queen_sight(&self, pieces: &PieceBitBoards) -> BitBoard;
fn king_sight(&self, pieces: &PieceBitBoards) -> BitBoard;
pub(crate) trait RookSightExt {
fn rook_sight(&self, occupancy: &BitBoard) -> BitBoard;
}
pub(crate) trait SliderSightExt: BishopSightExt + QueenSightExt + RookSightExt {}
pub(crate) trait SightExt {
fn sight(&self, pieces: &PieceBitBoards, en_passant_square: Option<Square>) -> BitBoard;
}
pub(crate) trait SliderRayToSquareExt {
@ -52,12 +139,33 @@ impl SightExt for PlacedPiece {
Color::Black => self.black_pawn_sight(pieces, en_passant_square),
},
Shape::Knight => self.knight_sight(pieces),
Shape::Bishop => self.bishop_sight(pieces),
Shape::Rook => self.rook_sight(pieces),
Shape::Queen => self.queen_sight(pieces),
Shape::Bishop => self.bishop_sight(pieces.all_pieces()),
Shape::Rook => self.rook_sight(pieces.all_pieces()),
Shape::Queen => self.queen_sight(pieces.all_pieces()),
Shape::King => self.king_sight(pieces),
}
}
}
impl KingSightExt for PlacedPiece {
fn king_sight(&self, pieces: &PieceBitBoards) -> BitBoard {
_king_sight(self.square(), pieces.all_pieces_of_color(self.color()))
}
}
impl KnightSightExt for PlacedPiece {
fn knight_sight(&self, pieces: &PieceBitBoards) -> BitBoard {
_knight_sight(self.square(), pieces.all_pieces_of_color(self.color()))
}
}
impl PawnSightExt for PlacedPiece {
fn pawn_sight(&self, pieces: &PieceBitBoards, en_passant_square: Option<Square>) -> BitBoard {
match self.color() {
Color::White => self.white_pawn_sight(pieces, en_passant_square),
Color::Black => self.black_pawn_sight(pieces, en_passant_square),
}
}
fn white_pawn_sight(
&self,
@ -65,16 +173,12 @@ impl SightExt for PlacedPiece {
en_passant_square: Option<Square>,
) -> BitBoard {
let opponent = self.color().other();
let pawn: BitBoard = self.square().into();
let pawn = pawn.shift_north_west_one() | pawn.shift_north_east_one();
let mut possible_squares = pieces.empty_squares() | pieces.all_pieces_of_color(opponent);
if let Some(en_passant) = en_passant_square {
let en_passant_bitboard: BitBoard = en_passant.into();
possible_squares |= en_passant_bitboard;
}
pawn & possible_squares
_white_pawn_sight(
&self.square().into(),
pieces.all_pieces(),
pieces.all_pieces_of_color(opponent),
&en_passant_square.into(),
)
}
fn black_pawn_sight(
@ -83,79 +187,35 @@ impl SightExt for PlacedPiece {
en_passant_square: Option<Square>,
) -> BitBoard {
let opponent = self.color().other();
let pawn: BitBoard = self.square().into();
let pawn = pawn.shift_south_west_one() | pawn.shift_south_east_one();
let mut possible_squares = pieces.empty_squares() | pieces.all_pieces_of_color(opponent);
if let Some(en_passant) = en_passant_square {
possible_squares |= &en_passant.into();
}
pawn & possible_squares
}
fn knight_sight(&self, pieces: &PieceBitBoards) -> BitBoard {
BitBoard::knight_moves(self.square()) & !pieces.all_pieces_of_color(self.color())
}
fn bishop_sight(&self, pieces: &PieceBitBoards) -> BitBoard {
let square = self.square();
let mut sight = BitBoard::empty();
let blockers = pieces.all_pieces();
sight |= ray_in_direction!(square, blockers, NorthEast, occupied_squares_trailing);
sight |= ray_in_direction!(square, blockers, NorthWest, occupied_squares_trailing);
sight |= ray_in_direction!(square, blockers, SouthEast, occupied_squares);
sight |= ray_in_direction!(square, blockers, SouthWest, occupied_squares);
let friendly_pieces = pieces.all_pieces_of_color(self.color());
sight & !friendly_pieces
}
fn rook_sight(&self, pieces: &PieceBitBoards) -> BitBoard {
let square = self.square();
let mut sight = BitBoard::empty();
let blockers = pieces.all_pieces();
sight |= ray_in_direction!(square, blockers, North, occupied_squares_trailing);
sight |= ray_in_direction!(square, blockers, East, occupied_squares_trailing);
sight |= ray_in_direction!(square, blockers, South, occupied_squares);
sight |= ray_in_direction!(square, blockers, West, occupied_squares);
let friendly_pieces = pieces.all_pieces_of_color(self.color());
sight & !friendly_pieces
}
fn queen_sight(&self, pieces: &PieceBitBoards) -> BitBoard {
let square = self.square();
let mut sight = BitBoard::empty();
let blockers = pieces.all_pieces();
sight |= ray_in_direction!(square, blockers, NorthWest, occupied_squares_trailing);
sight |= ray_in_direction!(square, blockers, North, occupied_squares_trailing);
sight |= ray_in_direction!(square, blockers, NorthEast, occupied_squares_trailing);
sight |= ray_in_direction!(square, blockers, East, occupied_squares_trailing);
sight |= ray_in_direction!(square, blockers, SouthEast, occupied_squares);
sight |= ray_in_direction!(square, blockers, South, occupied_squares);
sight |= ray_in_direction!(square, blockers, SouthWest, occupied_squares);
sight |= ray_in_direction!(square, blockers, West, occupied_squares);
let friendly_pieces = pieces.all_pieces_of_color(self.color());
sight & !friendly_pieces
}
fn king_sight(&self, pieces: &PieceBitBoards) -> BitBoard {
BitBoard::king_moves(self.square()) & !pieces.all_pieces_of_color(self.color())
_black_pawn_sight(
&self.square().into(),
pieces.all_pieces(),
pieces.all_pieces_of_color(opponent),
&en_passant_square.into(),
)
}
}
impl BishopSightExt for PlacedPiece {
fn bishop_sight(&self, occupancy: &BitBoard) -> BitBoard {
_bishop_sight(self.square(), occupancy)
}
}
impl RookSightExt for PlacedPiece {
fn rook_sight(&self, occupancy: &BitBoard) -> BitBoard {
_rook_sight(self.square(), occupancy)
}
}
impl QueenSightExt for PlacedPiece {
fn queen_sight(&self, occupancy: &BitBoard) -> BitBoard {
_queen_sight(self.square(), occupancy)
}
}
impl SliderSightExt for PlacedPiece {}
impl SliderRayToSquareExt for Shape {
fn ray_to_square(&self, origin: Square, target: Square) -> Option<BitBoard> {
macro_rules! ray {
@ -210,6 +270,24 @@ impl SliderRayToSquareExt for Shape {
}
}
impl BishopSightExt for Square {
fn bishop_sight(&self, occupancy: &BitBoard) -> BitBoard {
_bishop_sight(*self, occupancy)
}
}
impl QueenSightExt for Square {
fn queen_sight(&self, occupancy: &BitBoard) -> BitBoard {
_queen_sight(*self, occupancy)
}
}
impl RookSightExt for Square {
fn rook_sight(&self, occupancy: &BitBoard) -> BitBoard {
_rook_sight(*self, occupancy)
}
}
#[cfg(test)]
mod tests {
use super::*;
@ -345,7 +423,7 @@ mod tests {
Black King on E7,
],
piece!(White Rook on E4),
bitboard!(A4, B4, C4, D4, F4, G4, H4, E2, E3, E5, E6, E7)
bitboard!(A4, B4, C4, D4, F4, G4, H4, E2, E3, E5, E6, E7, E1)
);
#[test]