diff options
author | eug-vs <eugene@eug-vs.xyz> | 2023-01-21 04:34:32 +0300 |
---|---|---|
committer | eug-vs <eugene@eug-vs.xyz> | 2023-01-21 04:42:44 +0300 |
commit | 56f80a81852ef9fa6c1654c8548751fb898f2fb3 (patch) | |
tree | 2eb1fc091237f1eef2909a3802cf1728e41e9dd0 /src/attacks.rs | |
parent | d788e73ea5240f72d3ca64a5ce2bad5026643ebd (diff) | |
download | chessnost-56f80a81852ef9fa6c1654c8548751fb898f2fb3.tar.gz |
feat: precompute knight and king attacks
Diffstat (limited to 'src/attacks.rs')
-rw-r--r-- | src/attacks.rs | 99 |
1 files changed, 99 insertions, 0 deletions
diff --git a/src/attacks.rs b/src/attacks.rs new file mode 100644 index 0000000..ece87b6 --- /dev/null +++ b/src/attacks.rs @@ -0,0 +1,99 @@ +use crate::bitboard::Bitboard; + +static NOT_A_FILE: Bitboard = 0xFEFEFEFEFEFEFEFE; +static NOT_B_FILE: Bitboard = 0xFDFDFDFDFDFDFDFD; +static NOT_G_FILE: Bitboard = 0xBFBFBFBFBFBFBFBF; +static NOT_H_FILE: Bitboard = 0x7F7F7F7F7F7F7F7F; + +type AttackTable = [Bitboard; 64]; + +#[derive(Debug)] +pub struct Attacks { + pub knight: AttackTable, + pub king: AttackTable, +} + +impl Attacks { + pub fn new() -> Self { + let mut knight = [0; 64]; + let mut king = [0; 64]; + Self::precompute_knight_attacks(&mut knight); + Self::precompute_king_attacks(&mut king); + Self { knight, king } + } + + fn precompute_knight_attacks(attacks: &mut AttackTable) { + for index in 0..64 { + let position = 1u64 << index; + attacks[index] = + ((position & NOT_A_FILE & NOT_B_FILE) << 6) | + ((position & NOT_G_FILE & NOT_H_FILE) << 10) | + ((position & NOT_A_FILE) << 15) | + ((position & NOT_H_FILE) << 17) | + ((position & NOT_G_FILE & NOT_H_FILE) >> 6) | + ((position & NOT_A_FILE & NOT_B_FILE) >> 10) | + ((position & NOT_H_FILE) >> 15) | + ((position & NOT_A_FILE) >> 17); + } + } + + fn precompute_king_attacks(attacks: &mut AttackTable) { + for index in 0..64 { + let position = 1u64 << index; + attacks[index] = + ((position & NOT_A_FILE) >> 1) | + ((position & NOT_A_FILE) << 7) | + ((position & NOT_A_FILE) >> 9) | + ((position & NOT_H_FILE) << 1) | + ((position & NOT_H_FILE) >> 7) | + ((position & NOT_H_FILE) << 9) | + (position << 8) | + (position >> 8); + } + } +} + +#[cfg(test)] +mod tests { + use crate::{bitboard::pop_count, board::Square}; + + use super::*; + + #[test] + fn test_knight_attacks() { + let attacks = Attacks::new(); + let e4_attacks = attacks.knight[Square::E4 as usize]; + + assert_ne!(e4_attacks & 1 << Square::G5 as usize, 0); + assert_ne!(e4_attacks & 1 << Square::G3 as usize, 0); + assert_ne!(e4_attacks & 1 << Square::C5 as usize, 0); + assert_ne!(e4_attacks & 1 << Square::C3 as usize, 0); + assert_ne!(e4_attacks & 1 << Square::D2 as usize, 0); + assert_ne!(e4_attacks & 1 << Square::F2 as usize, 0); + assert_ne!(e4_attacks & 1 << Square::D6 as usize, 0); + assert_ne!(e4_attacks & 1 << Square::F6 as usize, 0); + + assert_eq!(e4_attacks & 1 << Square::E5 as usize, 0); + assert_eq!(e4_attacks & 1 << Square::D4 as usize, 0); + assert_eq!(e4_attacks & 1 << Square::A1 as usize, 0); + + assert_eq!(pop_count(attacks.knight[Square::G1 as usize]), 3); + assert_eq!(pop_count(attacks.knight[Square::H8 as usize]), 2); + } + + #[test] + fn test_king_attacks() { + let attacks = Attacks::new(); + assert_eq!(pop_count(attacks.king[Square::E4 as usize]), 8); + + assert_eq!(pop_count(attacks.king[Square::A1 as usize]), 3); + assert_eq!(pop_count(attacks.king[Square::A8 as usize]), 3); + assert_eq!(pop_count(attacks.king[Square::H1 as usize]), 3); + assert_eq!(pop_count(attacks.king[Square::H8 as usize]), 3); + + assert_eq!(pop_count(attacks.king[Square::E1 as usize]), 5); + assert_eq!(pop_count(attacks.king[Square::E8 as usize]), 5); + assert_eq!(pop_count(attacks.king[Square::A4 as usize]), 5); + assert_eq!(pop_count(attacks.king[Square::H4 as usize]), 5); + } +} |