aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/attacks.rs92
1 files changed, 73 insertions, 19 deletions
diff --git a/src/attacks.rs b/src/attacks.rs
index 787f200..4d826f6 100644
--- a/src/attacks.rs
+++ b/src/attacks.rs
@@ -1,4 +1,4 @@
-use crate::bitboard::{Bitboard, ls1b};
+use crate::bitboard::Bitboard;
static NOT_A_FILE: Bitboard = 0xFEFEFEFEFEFEFEFE;
static NOT_B_FILE: Bitboard = 0xFDFDFDFDFDFDFDFD;
@@ -15,12 +15,13 @@ type AttackTable = [Bitboard; 64];
pub type Byte = u8;
/// First index is *occupancy* of the first rank (all possible states)
-/// and the second index is position of the piece on the first rank
+/// and the second index is the file of the piece on the first rank
/// ```
/// rank_attacks = first_rank_attacks[occupancy][piece_file];
/// ```
type FirstRankAttacks = [[Byte; 8]; 256];
+#[allow(dead_code)]
enum Direction {
Nort,
NoEa,
@@ -92,6 +93,8 @@ impl Attacks {
}
+ // Compute rook-like attacks on the first rank based on
+ // occupancy and rook file.
fn precompute_first_rank_attacks() -> FirstRankAttacks {
let mut attacks = [[0; 8]; 256];
@@ -101,21 +104,20 @@ impl Attacks {
}
for occupancy in 0..256 {
- let right_most_piece = log_base_2(occupancy);
- let left_most_piece = log_base_2(ls1b(occupancy));
-
for file in 0..8 {
- let left_bound = if left_most_piece == file {
- 0
- } else {
- left_most_piece
- };
-
- let right_bound = if right_most_piece == file {
- 7
- } else {
- right_most_piece
- };
+ let mut left_bound = 0;
+ let mut right_bound = 7;
+
+ for bit in 0..8 {
+ if (occupancy & (1 << bit)) > 0 {
+ if (bit > left_bound) && (bit < file) {
+ left_bound = bit
+ }
+ if (bit < right_bound) && (bit > file) {
+ right_bound = bit
+ }
+ }
+ }
for index in left_bound..right_bound+1 {
if index != file {
@@ -208,6 +210,32 @@ impl Attacks {
}
[nort, noea, east, soea, sout, sowe, west, nowe]
}
+
+ /// https://www.chessprogramming.org/Kindergarten_Bitboards
+ ///
+ /// Given a square and occupancy masked for rank, diagonal or anti-diagonal (note: not a file!)
+ /// return an attack bitboard that considers blocking pieces
+ fn kingergarten_attacks_base(&self, occupancy: Bitboard, mask: Bitboard, square: u8) -> Bitboard {
+ let file = square % 8;
+ let masked_occupancy = occupancy & mask;
+ let occupancy_rank = ((masked_occupancy as u128 * B_FILE as u128) >> 58 & 0b111111) << 1;
+ let rank_attacks = self.first_rank_attacks[occupancy_rank as usize][file as usize] as Bitboard;
+
+ let mut filled_up_attacks = 0;
+ for rank in 0..8 {
+ filled_up_attacks |= rank_attacks << (rank * 8);
+ }
+ filled_up_attacks & mask
+ }
+
+ fn bishop(&self, occupancy: Bitboard, square: u8) -> Bitboard {
+ let diagonal_mask = self.ray_attacks[Direction::NoEa as usize][square as usize] |
+ self.ray_attacks[Direction::SoWe as usize][square as usize];
+ let anti_diagonal_mask = self.ray_attacks[Direction::NoWe as usize][square as usize] |
+ self.ray_attacks[Direction::SoEa as usize][square as usize];
+
+ self.kingergarten_attacks_base(occupancy, diagonal_mask, square) | self.kingergarten_attacks_base(occupancy, anti_diagonal_mask, square)
+ }
}
#[cfg(test)]
@@ -236,7 +264,7 @@ mod tests {
assert_eq!(pop_count(attacks[Square::G1 as usize]), 3);
assert_eq!(pop_count(attacks[Square::H8 as usize]), 2);
- print(attacks[Square::E4 as usize]);
+ print(e4_attacks);
}
#[test]
@@ -259,14 +287,18 @@ mod tests {
#[test]
fn test_first_rank_attacks() {
let attacks = Attacks::precompute_first_rank_attacks();
- // HGFEDCBA HGFEDCBA
- assert_eq!(attacks[0b00010000][4], 0b11101111, "If rook is the only one on the file, it should be able to attack all rank");
+ // HGFEDCBA HGFEDCBA
+ assert_eq!(attacks[0b00010000][4], 0b11101111, "If rook is the only piece on a rank, it should be able to attack all rank");
+ assert_eq!(attacks[0b00000000][4], 0b11101111, "Even with 0 occupancy rook should be able to attack all rank");
+ assert_eq!(attacks[0b00000000][0], 0b11111110, "Even with 0 occupancy rook should be able to attack all rank");
assert_eq!(attacks[0b00010001][4], 0b11101111, "If only other piece is on A rank, rook should be able to attack all rank");
assert_eq!(attacks[0b10010000][4], 0b11101111, "If only other piece is on H rank, rook should be able to attack all rank");
assert_eq!(attacks[0b10010001][4], 0b11101111, "If only other pieces are on A and H ranks, rook should be able to attack all rank");
assert_eq!(attacks[0b00010100][4], 0b11101100);
assert_eq!(attacks[0b01010100][4], 0b01101100);
assert_eq!(attacks[0b01010010][4], 0b01101110);
+ assert_eq!(attacks[0b00000010][4], 0b11101110);
+ assert_eq!(attacks[0b01011000][5], 0b01010000);
}
#[test]
@@ -284,4 +316,26 @@ mod tests {
attacks[7][square];
print(bitboard);
}
+
+ #[test]
+ fn test_diagonal_attacks() {
+ let attacks = Attacks::new();
+ let square = Square::E4 as u8;
+ let occupancy =
+ 1 << Square::B7 as usize |
+ 1 << Square::B1 as usize |
+ 1 << Square::C2 as usize |
+ 1 << Square::F3 as usize;
+ let bb = attacks.bishop(occupancy, square);
+
+ assert_ne!(bb & 1 << Square::C2 as u8, 0);
+ assert_eq!(bb & 1 << Square::B1 as u8, 0);
+ assert_ne!(bb & 1 << Square::F3 as u8, 0);
+ assert_eq!(bb & 1 << Square::G2 as u8, 0);
+ assert_ne!(bb & 1 << Square::H7 as u8, 0);
+ assert_ne!(bb & 1 << Square::B7 as u8, 0);
+ assert_eq!(bb & 1 << Square::A8 as u8, 0);
+
+ print(bb);
+ }
}