diff --git a/position/src/sight.rs b/position/src/sight.rs index 29cbf91..3b9170d 100644 --- a/position/src/sight.rs +++ b/position/src/sight.rs @@ -1,5 +1,9 @@ // Eryn Wells +//! 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) -> 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) -> BitBoard; fn white_pawn_sight( &self, @@ -32,12 +112,19 @@ pub(crate) trait SightExt { pieces: &PieceBitBoards, en_passant_square: Option, ) -> 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) -> 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) -> 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, ) -> 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, ) -> 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 { 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]