diff --git a/src/attacks.rs b/src/attacks.rs index 0c6eb93..c799678 100644 --- a/src/attacks.rs +++ b/src/attacks.rs @@ -24,6 +24,7 @@ use crate::{ bitboard::Bitboard, bootstrap::{ ATTACKS, BLACK_PAWN_ATTACKS, KING_ATTACKS, KNIGHT_ATTACKS, RAYS, WHITE_PAWN_ATTACKS, + DIAG_RANGE, ANTI_DIAG_RANGE, FILE_RANGE, RANK_RANGE, }, color::Color, magics, @@ -54,10 +55,35 @@ pub fn king_attacks(sq: Square) -> Bitboard { Bitboard(KING_ATTACKS[usize::from(sq)]) } +fn hyperbola(sq: Square, range: u64, occupied: Bitboard) -> Bitboard { + let forward = occupied & Bitboard(range); + let reverse = forward.flip_vertical(); + let forward = Bitboard(forward.0.wrapping_sub(1 << usize::from(sq))); + let reverse = Bitboard(reverse.0.wrapping_sub(1 << usize::from(sq.flip_vertical()))); + (forward ^ reverse.flip_vertical()) & range +} +fn file_attacks(sq: Square, occupied: Bitboard) -> Bitboard { + hyperbola(sq, FILE_RANGE[usize::from(sq)], occupied) +} +fn rank_attacks(sq: Square, occupied: Bitboard) -> Bitboard { + let range = RANK_RANGE[usize::from(sq)]; + let forward = occupied & range; + let reverse = forward.rotate_180(); + let forward = Bitboard(forward.0.wrapping_sub(1 << usize::from(sq))); + let reverse = Bitboard(reverse.0.wrapping_sub(1 << usize::from(sq.rotate_180()))); + (forward ^ reverse.rotate_180()) & range +} +pub fn bishop_attacks(sq: Square, occupied: Bitboard) -> Bitboard { + hyperbola(sq, DIAG_RANGE[usize::from(sq)], occupied) ^ hyperbola(sq, ANTI_DIAG_RANGE[usize::from(sq)], occupied) +} +pub fn rook_attacks(sq: Square, occupied: Bitboard) -> Bitboard { + file_attacks(sq, occupied) ^ rank_attacks(sq, occupied) +} + static ROOK_MAGICS: [Magic; 64] = magics::ROOK_MAGICS; /// Looks up attacks for a rook on `sq` with `occupied` squares. -#[inline] +/* #[inline] pub fn rook_attacks(sq: Square, occupied: Bitboard) -> Bitboard { let m = ROOK_MAGICS[usize::from(sq)]; @@ -69,29 +95,6 @@ pub fn rook_attacks(sq: Square, occupied: Bitboard) -> Bitboard { Bitboard(unsafe { *ATTACKS.get_unchecked(idx) }) } -/// Gets the set of potential blocking squares for a rook on `sq`. -/// -/// # Example -/// -/// ``` -/// use shakmaty::{attacks, Square}; -/// -/// let mask = attacks::rook_mask(Square::E8); -/// // 0 1 1 1 0 1 1 0 -/// // . . . . 1 . . . -/// // . . . . 1 . . . -/// // . . . . 1 . . . -/// // . . . . 1 . . . -/// // . . . . 1 . . . -/// // . . . . 1 . . . -/// // . . . . 0 . . . -/// -/// assert_eq!(mask.count(), 11); -#[inline] -pub fn rook_mask(sq: Square) -> Bitboard { - Bitboard(ROOK_MAGICS[usize::from(sq)].mask) -} - static BISHOP_MAGICS: [Magic; 64] = magics::BISHOP_MAGICS; /// Looks up attacks for a bishop on `sq` with `occupied` squares. @@ -105,31 +108,7 @@ pub fn bishop_attacks(sq: Square, occupied: Bitboard) -> Bitboard { let idx = (m.factor.wrapping_mul(occupied.0 & m.mask) >> (64 - 9)) as usize + m.offset; debug_assert!(idx < ATTACKS.len()); Bitboard(unsafe { *ATTACKS.get_unchecked(idx) }) -} - -/// Gets the set of potential blocking squares for a bishop on `sq`. -/// -/// # Example -/// -/// ``` -/// use shakmaty::{attacks, Square}; -/// -/// let mask = attacks::bishop_mask(Square::D5); -/// // 0 . . . . . 0 . -/// // . 1 . . . 1 . . -/// // . . 1 . 1 . . . -/// // . . . 0 . . . . -/// // . . 1 . 1 . . . -/// // . 1 . . . 1 . . -/// // 0 . . . . . 1 . -/// // . . . . . . . 0 -/// -/// assert_eq!(mask.count(), 9); -/// ``` -#[inline] -pub fn bishop_mask(sq: Square) -> Bitboard { - Bitboard(BISHOP_MAGICS[usize::from(sq)].mask) -} +} */ /// Looks up attacks for a queen on `sq` with `occupied` squares. #[inline] @@ -169,7 +148,20 @@ pub fn attacks(sq: Square, piece: Piece, occupied: Bitboard) -> Bitboard { /// ``` #[inline] pub fn ray(a: Square, b: Square) -> Bitboard { - Bitboard(RAYS[usize::from(a)][usize::from(b)]) + if a == b { + Bitboard::EMPTY + } else if a.rank() == b.rank() { + Bitboard::from_rank(a.rank()) + } else if a.file() == b.file() { + Bitboard::from_file(a.file()) + } else if Bitboard(DIAG_RANGE[usize::from(a)]).contains(b) { + Bitboard(DIAG_RANGE[usize::from(a)]).with(a) + } else if Bitboard(ANTI_DIAG_RANGE[usize::from(a)]).contains(b) { + Bitboard(ANTI_DIAG_RANGE[usize::from(a)]).with(a) + } else { + Bitboard::EMPTY + } + //Bitboard(RAYS[usize::from(a)][usize::from(b)]) } /// The squares between the two squares (bounds not included), or an empty diff --git a/src/bootstrap.rs b/src/bootstrap.rs index 28f90f0..89ac146 100644 --- a/src/bootstrap.rs +++ b/src/bootstrap.rs @@ -9,6 +9,11 @@ const KNIGHT_DELTAS: [i32; 8] = [17, 15, 10, 6, -17, -15, -10, -6]; const WHITE_PAWN_DELTAS: [i32; 2] = [7, 9]; const BLACK_PAWN_DELTAS: [i32; 2] = [-7, -9]; +const FILE_DELTAS: [i32; 2] = [8, -8]; +const RANK_DELTAS: [i32; 2] = [1, -1]; +const DIAG_DELTAS: [i32; 2] = [9, -9]; +const ANTI_DIAG_DELTAS: [i32; 2] = [7, -7]; + const fn sliding_attacks(square: i32, occupied: u64, deltas: &[i32]) -> u64 { let mut attack = 0; @@ -35,22 +40,31 @@ const fn sliding_attacks(square: i32, occupied: u64, deltas: &[i32]) -> u64 { attack } -const fn init_stepping_attacks(deltas: &[i32]) -> [u64; 64] { +const fn init_sliding_attacks(occupied: u64, deltas: &[i32]) -> [u64; 64] { let mut table = [0; 64]; let mut sq = 0; while sq < 64 { - table[sq] = sliding_attacks(sq as i32, !0, deltas); + table[sq] = sliding_attacks(sq as i32, occupied, deltas); sq += 1; } table } +const fn init_stepping_attacks(deltas: &[i32]) -> [u64; 64] { + init_sliding_attacks(!0, deltas) +} + pub static KNIGHT_ATTACKS: [u64; 64] = init_stepping_attacks(&KNIGHT_DELTAS); pub static KING_ATTACKS: [u64; 64] = init_stepping_attacks(&KING_DELTAS); pub static WHITE_PAWN_ATTACKS: [u64; 64] = init_stepping_attacks(&WHITE_PAWN_DELTAS); pub static BLACK_PAWN_ATTACKS: [u64; 64] = init_stepping_attacks(&BLACK_PAWN_DELTAS); -const fn init_rays() -> [[u64; 64]; 64] { +pub static FILE_RANGE: [u64; 64] = init_sliding_attacks(0, &FILE_DELTAS); +pub static RANK_RANGE: [u64; 64] = init_sliding_attacks(0, &RANK_DELTAS); +pub static DIAG_RANGE: [u64; 64] = init_sliding_attacks(0, &DIAG_DELTAS); +pub static ANTI_DIAG_RANGE: [u64; 64] = init_sliding_attacks(0, &ANTI_DIAG_DELTAS); + +pub static RAYS: [[u64; 64]; 64] = { let mut table = [[0; 64]; 64]; let mut a = 0; while a < 64 { @@ -86,11 +100,9 @@ const fn init_rays() -> [[u64; 64]; 64] { a += 1; } table -} - -pub static RAYS: [[u64; 64]; 64] = init_rays(); +}; -const fn init_magics() -> [u64; 88772] { +pub static ATTACKS: [u64; 88772] = { let mut table = [0; 88772]; let mut square = 0; while square < 64 { @@ -125,6 +137,4 @@ const fn init_magics() -> [u64; 88772] { square += 1; } table -} - -pub static ATTACKS: [u64; 88772] = init_magics(); +};