chess/
magic.rs

1use crate::bitboard::{BitBoard, EMPTY};
2use crate::color::Color;
3use crate::file::File;
4use crate::rank::Rank;
5use crate::square::Square;
6#[cfg(target_feature = "bmi2")]
7use std::arch::x86_64::{_pdep_u64, _pext_u64};
8
9// Include the generated lookup tables
10include!(concat!(env!("OUT_DIR"), "/magic_gen.rs"));
11
12/// Get the rays for a bishop on a particular square.
13#[inline]
14pub fn get_bishop_rays(sq: Square) -> BitBoard {
15    unsafe { *RAYS.get_unchecked(BISHOP).get_unchecked(sq.to_index()) }
16}
17
18/// Get the rays for a rook on a particular square.
19#[inline]
20pub fn get_rook_rays(sq: Square) -> BitBoard {
21    unsafe { *RAYS.get_unchecked(ROOK).get_unchecked(sq.to_index()) }
22}
23
24/// Get the moves for a rook on a particular square, given blockers blocking my movement.
25#[inline]
26pub fn get_rook_moves(sq: Square, blockers: BitBoard) -> BitBoard {
27    unsafe {
28        let magic: Magic = *MAGIC_NUMBERS
29            .get_unchecked(ROOK)
30            .get_unchecked(sq.to_int() as usize);
31        *MOVES.get_unchecked(
32            (magic.offset as usize)
33                + (magic.magic_number * (blockers & magic.mask)).to_size(magic.rightshift),
34        ) & get_rook_rays(sq)
35    }
36}
37
38/// Get the moves for a rook on a particular square, given blockers blocking my movement.
39#[cfg(target_feature = "bmi2")]
40#[inline]
41pub fn get_rook_moves_bmi(sq: Square, blockers: BitBoard) -> BitBoard {
42    unsafe {
43        let bmi2_magic = *ROOK_BMI_MASK.get_unchecked(sq.to_int() as usize);
44        let index = (_pext_u64(blockers.0, bmi2_magic.blockers_mask.0) as usize)
45            + (bmi2_magic.offset as usize);
46        let result = _pdep_u64(
47            *BMI_MOVES.get_unchecked(index as usize) as u64,
48            get_rook_rays(sq).0,
49        );
50        return BitBoard(result);
51    }
52}
53
54/// Get the moves for a bishop on a particular square, given blockers blocking my movement.
55#[inline]
56pub fn get_bishop_moves(sq: Square, blockers: BitBoard) -> BitBoard {
57    unsafe {
58        let magic: Magic = *MAGIC_NUMBERS
59            .get_unchecked(BISHOP)
60            .get_unchecked(sq.to_int() as usize);
61        *MOVES.get_unchecked(
62            (magic.offset as usize)
63                + (magic.magic_number * (blockers & magic.mask)).to_size(magic.rightshift),
64        ) & get_bishop_rays(sq)
65    }
66}
67
68/// Get the moves for a bishop on a particular square, given blockers blocking my movement.
69#[inline]
70#[cfg(target_feature = "bmi2")]
71pub fn get_bishop_moves_bmi(sq: Square, blockers: BitBoard) -> BitBoard {
72    unsafe {
73        let bmi2_magic = *BISHOP_BMI_MASK.get_unchecked(sq.to_int() as usize);
74        let index = (_pext_u64(blockers.0, bmi2_magic.blockers_mask.0) as usize)
75            + (bmi2_magic.offset as usize);
76        let result = _pdep_u64(
77            *BMI_MOVES.get_unchecked(index as usize) as u64,
78            get_bishop_rays(sq).0,
79        );
80        return BitBoard(result);
81    }
82}
83
84/// Get the king moves for a particular square.
85#[inline]
86pub fn get_king_moves(sq: Square) -> BitBoard {
87    unsafe { *KING_MOVES.get_unchecked(sq.to_index()) }
88}
89
90/// Get the knight moves for a particular square.
91#[inline]
92pub fn get_knight_moves(sq: Square) -> BitBoard {
93    unsafe { *KNIGHT_MOVES.get_unchecked(sq.to_index()) }
94}
95
96/// Get the pawn capture move for a particular square, given the pawn's color and the potential
97/// victims
98#[inline]
99pub fn get_pawn_attacks(sq: Square, color: Color, blockers: BitBoard) -> BitBoard {
100    unsafe {
101        *PAWN_ATTACKS
102            .get_unchecked(color.to_index())
103            .get_unchecked(sq.to_index())
104            & blockers
105    }
106}
107/// Get the legal destination castle squares for both players
108#[inline]
109pub fn get_castle_moves() -> BitBoard {
110    CASTLE_MOVES
111}
112
113/// Get the quiet pawn moves (non-captures) for a particular square, given the pawn's color and
114/// the potential blocking pieces.
115#[inline]
116pub fn get_pawn_quiets(sq: Square, color: Color, blockers: BitBoard) -> BitBoard {
117    unsafe {
118        if (BitBoard::from_square(sq.uforward(color)) & blockers) != EMPTY {
119            EMPTY
120        } else {
121            *PAWN_MOVES
122                .get_unchecked(color.to_index())
123                .get_unchecked(sq.to_index())
124                & !blockers
125        }
126    }
127}
128
129/// Get all the pawn moves for a particular square, given the pawn's color and the potential
130/// blocking pieces and victims.
131#[inline]
132pub fn get_pawn_moves(sq: Square, color: Color, blockers: BitBoard) -> BitBoard {
133    get_pawn_attacks(sq, color, blockers) ^ get_pawn_quiets(sq, color, blockers)
134}
135
136/// Get a line (extending to infinity, which in chess is 8 squares), given two squares.
137/// This line does extend past the squares.
138#[inline]
139pub fn line(sq1: Square, sq2: Square) -> BitBoard {
140    unsafe {
141        *LINE
142            .get_unchecked(sq1.to_index())
143            .get_unchecked(sq2.to_index())
144    }
145}
146
147/// Get a line between these two squares, not including the squares themselves.
148#[inline]
149pub fn between(sq1: Square, sq2: Square) -> BitBoard {
150    unsafe {
151        *BETWEEN
152            .get_unchecked(sq1.to_index())
153            .get_unchecked(sq2.to_index())
154    }
155}
156
157/// Get a `BitBoard` that represents all the squares on a particular rank.
158#[inline]
159pub fn get_rank(rank: Rank) -> BitBoard {
160    unsafe { *RANKS.get_unchecked(rank.to_index()) }
161}
162
163/// Get a `BitBoard` that represents all the squares on a particular file.
164#[inline]
165pub fn get_file(file: File) -> BitBoard {
166    unsafe { *FILES.get_unchecked(file.to_index()) }
167}
168
169/// Get a `BitBoard` that represents the squares on the 1 or 2 files next to this file.
170#[inline]
171pub fn get_adjacent_files(file: File) -> BitBoard {
172    unsafe { *ADJACENT_FILES.get_unchecked(file.to_index()) }
173}
174
175#[inline]
176pub fn get_pawn_source_double_moves() -> BitBoard {
177    PAWN_SOURCE_DOUBLE_MOVES
178}
179
180#[inline]
181pub fn get_pawn_dest_double_moves() -> BitBoard {
182    PAWN_DEST_DOUBLE_MOVES
183}