[position] Implement a SliderRayToSquare trait
This trait declares ray_to_square() which should return a BitBoard representing a ray from a Square to another Square. The ray should include the target Square. PlacedPiece implements this trait.
This commit is contained in:
parent
cac13b4bc7
commit
722a90b860
3 changed files with 141 additions and 7 deletions
|
@ -26,6 +26,10 @@ pub(crate) trait SightExt {
|
|||
fn king_sight(&self, pieces: &PieceBitBoards) -> BitBoard;
|
||||
}
|
||||
|
||||
pub(crate) trait SliderRayToSquareExt {
|
||||
fn ray_to_square(&self, square: Square) -> Option<BitBoard>;
|
||||
}
|
||||
|
||||
impl SightExt for PlacedPiece {
|
||||
fn sight(&self, pieces: &PieceBitBoards, en_passant_square: Option<Square>) -> BitBoard {
|
||||
match self.shape() {
|
||||
|
@ -183,8 +187,80 @@ impl SightExt for PlacedPiece {
|
|||
}
|
||||
}
|
||||
|
||||
impl SliderRayToSquareExt for PlacedPiece {
|
||||
fn ray_to_square(&self, target: Square) -> Option<BitBoard> {
|
||||
macro_rules! ray {
|
||||
($square:expr, $direction:ident) => {
|
||||
(
|
||||
BitBoard::ray($square, Direction::$direction),
|
||||
Direction::$direction,
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
let square = self.square();
|
||||
let target_bitboard: BitBoard = target.into();
|
||||
|
||||
let ray_and_direction = match self.shape() {
|
||||
Shape::Bishop => [
|
||||
ray!(square, NorthEast),
|
||||
ray!(square, SouthEast),
|
||||
ray!(square, SouthWest),
|
||||
ray!(square, NorthWest),
|
||||
]
|
||||
.into_iter()
|
||||
.find(|(&ray, _)| !(target_bitboard & ray).is_empty()),
|
||||
Shape::Rook => [
|
||||
ray!(square, North),
|
||||
ray!(square, East),
|
||||
ray!(square, South),
|
||||
ray!(square, West),
|
||||
]
|
||||
.into_iter()
|
||||
.find(|(&ray, _)| !(target_bitboard & ray).is_empty()),
|
||||
Shape::Queen => [
|
||||
ray!(square, North),
|
||||
ray!(square, NorthEast),
|
||||
ray!(square, East),
|
||||
ray!(square, SouthEast),
|
||||
ray!(square, South),
|
||||
ray!(square, SouthWest),
|
||||
ray!(square, West),
|
||||
ray!(square, NorthWest),
|
||||
]
|
||||
.into_iter()
|
||||
.find(|(&ray, _)| !(target_bitboard & ray).is_empty()),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
if let Some((ray, direction)) = ray_and_direction {
|
||||
let first_occupied_square = match direction {
|
||||
Direction::East
|
||||
| Direction::NorthWest
|
||||
| Direction::NorthEast
|
||||
| Direction::North => ray.first_occupied_square_trailing(),
|
||||
Direction::West
|
||||
| Direction::SouthWest
|
||||
| Direction::SouthEast
|
||||
| Direction::South => ray.first_occupied_square(),
|
||||
};
|
||||
|
||||
if let Some(occupied_square) = first_occupied_square {
|
||||
let remainder = BitBoard::ray(target, direction);
|
||||
return Some(ray & !remainder);
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use chessfriend_bitboard::bitboard;
|
||||
use chessfriend_core::{piece, Square};
|
||||
|
||||
macro_rules! sight_test {
|
||||
($test_name:ident, $position:expr, $piece:expr, $bitboard:expr) => {
|
||||
#[test]
|
||||
|
@ -201,6 +277,12 @@ mod tests {
|
|||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pawns_and_knights_cannot_make_rays() {
|
||||
assert_eq!(piece!(White Pawn on F7).ray_to_square(Square::E8), None);
|
||||
assert_eq!(piece!(White Knight on F6).ray_to_square(Square::E8), None);
|
||||
}
|
||||
|
||||
mod pawn {
|
||||
use crate::test_position;
|
||||
use chessfriend_bitboard::{bitboard, BitBoard};
|
||||
|
@ -273,20 +355,25 @@ mod tests {
|
|||
}
|
||||
|
||||
mod bishop {
|
||||
use chessfriend_bitboard::bitboard;
|
||||
use chessfriend_core::piece;
|
||||
use super::*;
|
||||
|
||||
sight_test!(
|
||||
c2_bishop,
|
||||
piece!(Black Bishop on C2),
|
||||
bitboard!(D1, B3, A4, B1, D3, E4, F5, G6, H7)
|
||||
);
|
||||
|
||||
#[test]
|
||||
fn ray_to_square() {
|
||||
let generated_ray = piece!(White Bishop on C5).ray_to_square(Square::E7);
|
||||
let expected_ray = bitboard![D6, E7];
|
||||
assert_eq!(generated_ray, Some(expected_ray));
|
||||
}
|
||||
}
|
||||
|
||||
mod rook {
|
||||
use super::*;
|
||||
use crate::test_position;
|
||||
use chessfriend_bitboard::bitboard;
|
||||
use chessfriend_core::piece;
|
||||
|
||||
sight_test!(
|
||||
g3_rook,
|
||||
|
@ -304,6 +391,25 @@ mod tests {
|
|||
piece!(White Rook on E4),
|
||||
bitboard!(A4, B4, C4, D4, F4, G4, H4, E2, E3, E5, E6, E7)
|
||||
);
|
||||
|
||||
#[test]
|
||||
fn ray_to_square() {
|
||||
let generated_ray = piece!(White Rook on C2).ray_to_square(Square::C6);
|
||||
let expected_ray = bitboard![C3, C4, C5, C6];
|
||||
assert_eq!(generated_ray, Some(expected_ray));
|
||||
|
||||
let generated_ray = piece!(White Rook on D2).ray_to_square(Square::H2);
|
||||
let expected_ray = bitboard![E2, F2, G2, H2];
|
||||
assert_eq!(generated_ray, Some(expected_ray));
|
||||
|
||||
let generated_ray = piece!(White Rook on G6).ray_to_square(Square::B6);
|
||||
let expected_ray = bitboard![B6, C6, D6, E6, F6];
|
||||
assert_eq!(generated_ray, Some(expected_ray));
|
||||
|
||||
let generated_ray = piece!(White Rook on A6).ray_to_square(Square::A3);
|
||||
let expected_ray = bitboard![A5, A4, A3];
|
||||
assert_eq!(generated_ray, Some(expected_ray));
|
||||
}
|
||||
}
|
||||
|
||||
mod king {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue