aboutsummaryrefslogtreecommitdiff
path: root/src/attacks.rs
blob: ece87b607674f07766396797076f732b4e9f630d (plain)
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);
    }
}