aboutsummaryrefslogtreecommitdiff
path: root/src/attacks.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/attacks.rs')
-rw-r--r--src/attacks.rs67
1 files changed, 65 insertions, 2 deletions
diff --git a/src/attacks.rs b/src/attacks.rs
index ece87b6..141ba44 100644
--- a/src/attacks.rs
+++ b/src/attacks.rs
@@ -1,25 +1,42 @@
-use crate::bitboard::Bitboard;
+use crate::bitboard::{Bitboard, ls1b, pop_count};
static NOT_A_FILE: Bitboard = 0xFEFEFEFEFEFEFEFE;
static NOT_B_FILE: Bitboard = 0xFDFDFDFDFDFDFDFD;
static NOT_G_FILE: Bitboard = 0xBFBFBFBFBFBFBFBF;
static NOT_H_FILE: Bitboard = 0x7F7F7F7F7F7F7F7F;
+/// An array where N-th item is an attack bitboard
+/// of a piece on N-th square
type AttackTable = [Bitboard; 64];
+/// One byte stores exactly 256 states which is every
+/// possible state of the occupancy on a rank
+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
+/// ```
+/// rank_attacks = first_rank_attacks[occupancy][piece_file];
+/// ```
+type FirstRankAttacks = [[Byte; 8]; 256];
+
+
#[derive(Debug)]
pub struct Attacks {
pub knight: AttackTable,
pub king: AttackTable,
+ pub first_rank_attacks: FirstRankAttacks,
}
impl Attacks {
pub fn new() -> Self {
let mut knight = [0; 64];
let mut king = [0; 64];
+ let mut first_rank_attacks = [[0; 8]; 256];
Self::precompute_knight_attacks(&mut knight);
Self::precompute_king_attacks(&mut king);
- Self { knight, king }
+ Self::precompute_first_rank_attacks(&mut first_rank_attacks);
+ Self { knight, king, first_rank_attacks }
}
fn precompute_knight_attacks(attacks: &mut AttackTable) {
@@ -51,6 +68,38 @@ impl Attacks {
(position >> 8);
}
}
+
+ fn precompute_first_rank_attacks(attacks: &mut FirstRankAttacks) {
+ /// Really slow implementation of Most Significant One Bit which is fine to use when pre-computing
+ fn log_base_2(bb: Bitboard) -> u64 {
+ (bb as f64).log2() as u64
+ }
+
+ 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
+ };
+
+ for index in left_bound..right_bound+1 {
+ if index != file {
+ attacks[occupancy as usize][file as usize] |= 1 << index;
+ }
+ }
+ }
+ }
+ }
}
#[cfg(test)]
@@ -96,4 +145,18 @@ mod tests {
assert_eq!(pop_count(attacks.king[Square::A4 as usize]), 5);
assert_eq!(pop_count(attacks.king[Square::H4 as usize]), 5);
}
+
+ #[test]
+ fn test_first_rank_attacks() {
+ let attacks = Attacks::new();
+ // HGFEDCBA HGFEDCBA
+ assert_eq!(attacks.first_rank_attacks[0b00010000][4], 0b11101111, "If rook is the only one on the file, it should be able to attack all rank");
+ assert_eq!(attacks.first_rank_attacks[0b00010001][4], 0b11101111, "If only other piece is on A rank, rook should be able to attack all rank");
+ assert_eq!(attacks.first_rank_attacks[0b10010000][4], 0b11101111, "If only other piece is on H rank, rook should be able to attack all rank");
+ assert_eq!(attacks.first_rank_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.first_rank_attacks[0b00010100][4], 0b11101100);
+ assert_eq!(attacks.first_rank_attacks[0b01010100][4], 0b01101100);
+ assert_eq!(attacks.first_rank_attacks[0b01010010][4], 0b01101110);
+
+ }
}