1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
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);
}
}
|