[position] Calculate push and capture masks on CheckingPieces
This commit is contained in:
parent
ac07a8d6cf
commit
31903cb514
1 changed files with 78 additions and 10 deletions
|
@ -1,13 +1,12 @@
|
|||
// Eryn Wells <eryn@erynwells.me>
|
||||
|
||||
use chessfriend_bitboard::BitBoard;
|
||||
use chessfriend_core::{Color, Direction, Shape, Square};
|
||||
|
||||
use crate::sight::SliderRayToSquareExt;
|
||||
|
||||
pub struct CheckingPieces {
|
||||
pawn: BitBoard,
|
||||
knight: BitBoard,
|
||||
bishop: BitBoard,
|
||||
rook: BitBoard,
|
||||
queen: BitBoard,
|
||||
bitboards: [BitBoard; 5],
|
||||
}
|
||||
|
||||
impl CheckingPieces {
|
||||
|
@ -19,11 +18,80 @@ impl CheckingPieces {
|
|||
queen: BitBoard,
|
||||
) -> CheckingPieces {
|
||||
CheckingPieces {
|
||||
pawn,
|
||||
knight,
|
||||
bishop,
|
||||
rook,
|
||||
queen,
|
||||
bitboards: [pawn, knight, bishop, rook, queen],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn count(&self) -> u32 {
|
||||
self.bitboards.iter().map(|b| b.population_count()).sum()
|
||||
}
|
||||
|
||||
/// A BitBoard representing the set of pieces that must be captured to
|
||||
/// resolve check.
|
||||
pub fn capture_mask(&self) -> BitBoard {
|
||||
if self.count() == 0 {
|
||||
BitBoard::FULL
|
||||
} else {
|
||||
self.bitboards
|
||||
.iter()
|
||||
.fold(BitBoard::EMPTY, std::ops::BitOr::bitor)
|
||||
}
|
||||
}
|
||||
|
||||
/// A BitBoard representing the set of squares to which a player can move a
|
||||
/// piece to block a checking piece.
|
||||
pub fn push_mask(&self, king: &BitBoard) -> BitBoard {
|
||||
let target = king.first_occupied_square().unwrap();
|
||||
|
||||
macro_rules! push_mask_for_shape {
|
||||
($push_mask:expr, $shape:ident, $king:expr) => {{
|
||||
let checking_pieces = self.bitboard_for_shape(Shape::$shape);
|
||||
if !checking_pieces.is_empty() {
|
||||
if let Some(checking_ray) = checking_pieces
|
||||
.occupied_squares()
|
||||
.flat_map(|sq| Shape::$shape.ray_to_square(sq, target).into_iter())
|
||||
.find(|bb| !(bb & $king).is_empty())
|
||||
{
|
||||
$push_mask |= checking_ray & !$king
|
||||
}
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
let mut push_mask = BitBoard::EMPTY;
|
||||
|
||||
push_mask_for_shape!(push_mask, Bishop, king);
|
||||
push_mask_for_shape!(push_mask, Rook, king);
|
||||
push_mask_for_shape!(push_mask, Queen, king);
|
||||
|
||||
push_mask
|
||||
}
|
||||
|
||||
fn bitboard_for_shape(&self, shape: Shape) -> &BitBoard {
|
||||
&self.bitboards[shape as usize]
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use chessfriend_bitboard::{bitboard, BitBoard};
|
||||
|
||||
/// This is a test position from [this execellent blog post][1] about how to
|
||||
/// efficiently generate legal chess moves.
|
||||
///
|
||||
/// [1]: https://peterellisjones.com/posts/generating-legal-chess-moves-efficiently/
|
||||
#[test]
|
||||
fn rook_push_mask() {
|
||||
let checks = CheckingPieces::new(
|
||||
BitBoard::EMPTY,
|
||||
BitBoard::EMPTY,
|
||||
BitBoard::EMPTY,
|
||||
bitboard![E5],
|
||||
BitBoard::EMPTY,
|
||||
);
|
||||
|
||||
let push_mask = checks.push_mask(&bitboard![E8]);
|
||||
assert_eq!(push_mask, bitboard![E6, E7]);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue