Skip to main content

hermes_simd_intrinsics/bitboard/
hyperbola.rs

1//! Hyperbola Quintessence (o-protect) bitboard sliding attack generation.
2
3use hermes_simd_core::bitboard::BitBoardKernel;
4
5/// ZST marker for Hyperbola Quintessence backend.
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
7pub struct Hyperbola;
8
9const FILE_RAYS: [u64; 64] = {
10    let mut rays = [0u64; 64];
11    let mut sq = 0;
12    while sq < 64 {
13        rays[sq] = 0x0101010101010101u64 << (sq & 7);
14        sq += 1;
15    }
16    rays
17};
18
19const RANK_RAYS: [u64; 64] = {
20    let mut rays = [0u64; 64];
21    let mut sq = 0;
22    while sq < 64 {
23        rays[sq] = 0xFFu64 << (sq & 56);
24        sq += 1;
25    }
26    rays
27};
28
29const DIAGONAL_RAYS: [u64; 64] = {
30    let mut rays = [0u64; 64];
31    let mut sq = 0;
32    while sq < 64 {
33        let s_file = (sq & 7) as i32;
34        let s_rank = (sq >> 3) as i32;
35        let mut mask = 0u64;
36        let mut f = 0;
37        while f < 8 {
38            let r = s_rank + (f - s_file);
39            if r >= 0 && r < 8 {
40                mask |= 1u64 << (r * 8 + f);
41            }
42            f += 1;
43        }
44        rays[sq] = mask;
45        sq += 1;
46    }
47    rays
48};
49
50const ANTIDIAGONAL_RAYS: [u64; 64] = {
51    let mut rays = [0u64; 64];
52    let mut sq = 0;
53    while sq < 64 {
54        let s_file = (sq & 7) as i32;
55        let s_rank = (sq >> 3) as i32;
56        let mut mask = 0u64;
57        let mut f = 0;
58        while f < 8 {
59            let r = s_rank - (f - s_file);
60            if r >= 0 && r < 8 {
61                mask |= 1u64 << (r * 8 + f);
62            }
63            f += 1;
64        }
65        rays[sq] = mask;
66        sq += 1;
67    }
68    rays
69};
70
71#[inline(always)]
72fn file_ray(square: u8) -> u64 {
73    FILE_RAYS[square as usize]
74}
75
76#[inline(always)]
77fn rank_ray(square: u8) -> u64 {
78    RANK_RAYS[square as usize]
79}
80
81#[inline(always)]
82fn diagonal_ray(square: u8) -> u64 {
83    DIAGONAL_RAYS[square as usize]
84}
85
86#[inline(always)]
87fn antidiagonal_ray(square: u8) -> u64 {
88    ANTIDIAGONAL_RAYS[square as usize]
89}
90
91/// Generates sliding attacks along a ray mask using Hyperbola Quintessence.
92#[inline(always)]
93pub fn hyperbola_quintessence(square: u8, occupancy: u64, ray_mask: u64) -> u64 {
94    let slider = 1u64 << square;
95    let o = occupancy & ray_mask;
96
97    // Forward attacks
98    let forward = o.wrapping_sub(slider.wrapping_mul(2)) ^ o;
99
100    // Backward attacks (requires bit-reversal)
101    let o_rev = o.reverse_bits();
102    let slider_rev = slider.reverse_bits();
103    let backward = o_rev.wrapping_sub(slider_rev.wrapping_mul(2)) ^ o_rev;
104
105    // Combine and mask to the ray (excluding the slider itself)
106    ((forward & ray_mask) | (backward.reverse_bits() & ray_mask)) & !slider
107}
108
109impl BitBoardKernel for Hyperbola {
110    #[inline]
111    fn rook_attacks(square: u8, occupancy: u64) -> u64 {
112        hyperbola_quintessence(square, occupancy, file_ray(square))
113            | hyperbola_quintessence(square, occupancy, rank_ray(square))
114    }
115
116    #[inline]
117    fn bishop_attacks(square: u8, occupancy: u64) -> u64 {
118        hyperbola_quintessence(square, occupancy, diagonal_ray(square))
119            | hyperbola_quintessence(square, occupancy, antidiagonal_ray(square))
120    }
121}