1use crate::{Piece, Player, Role, board::Bitboard};
2
3use super::{Direction, Square};
4
5use Player::*;
6use Role::*;
7
8impl Square {
10 pub const fn attacks(self, piece: Piece, occupied: Bitboard) -> Bitboard {
11 match piece.role {
12 Pawn => self.pawn_attack_plays(piece.player),
13 Knight => self.knight_plays(),
14 Bishop => self.bishop_sight(occupied),
15 Rook => self.rook_sight(occupied),
16 Queen => self.queen_sight(occupied),
17 King => self.king_plays(),
18 }
19 }
20
21 pub const fn king_plays(self) -> Bitboard {
22 const KING_ATTACKS: [Direction; 8] = {
23 use Direction::*;
24 [North, NorthEast, East, SouthEast, South, SouthWest, West, NorthWest]
25 };
26
27 self.checked_add_vector_const(&KING_ATTACKS)
28 }
29
30 pub const fn knight_plays(self) -> Bitboard {
31 const KNIGHT_MOVES: [Direction; 8] = {
32 use Direction::*;
33 [
34 KnightNorthEast,
35 KnightEastNorth,
36 KnightEastSouth,
37 KnightSouthEast,
38 KnightSouthWest,
39 KnightWestSouth,
40 KnightWestNorth,
41 KnightNorthWest,
42 ]
43 };
44
45 self.checked_add_vector_const(&KNIGHT_MOVES)
46 }
47
48 pub const fn pawn_attack_plays(self, player: Player) -> Bitboard {
49 const WHITE_PAWN_ATTACKS: [Direction; 2] = {
50 use Direction::*;
51 [NorthWest, NorthEast]
52 };
53 const BLACK_PAWN_ATTACKS: [Direction; 2] = {
54 use Direction::*;
55 [SouthWest, SouthEast]
56 };
57
58 match player {
59 White => self.checked_add_vector_const(&WHITE_PAWN_ATTACKS),
60 Black => self.checked_add_vector_const(&BLACK_PAWN_ATTACKS),
61 }
62 }
63
64 pub const fn bishop_sight(self, occupied: Bitboard) -> Bitboard {
65 SliderSights::get().bishop_sight(self, occupied)
66 }
67
68 pub const fn rook_sight(self, occupied: Bitboard) -> Bitboard {
69 SliderSights::get().rook_sight(self, occupied)
70 }
71
72 pub const fn queen_sight(self, occupied: Bitboard) -> Bitboard {
73 self.bishop_sight(occupied).union(self.rook_sight(occupied))
74 }
75}
76
77mod bishop {
78 use super::*;
79
80 pub const DIRECTIONS: [Direction; 4] = {
81 use Direction::*;
82 [NorthEast, SouthEast, SouthWest, NorthWest]
83 };
84
85 pub const fn projector(square: Square) -> &'static Projector<9> {
86 &BISHOP_PROJECTOR[square as usize]
87 }
88
89 pub const fn blockers(square: Square) -> Bitboard {
90 const BLOCKERS: SliderBlockers = SliderBlockers::new(&DIRECTIONS);
91
92 BLOCKERS.get(square)
93 }
94}
95
96mod rook {
97 use super::*;
98
99 pub const DIRECTIONS: [Direction; 4] = {
100 use Direction::*;
101 [North, East, South, West]
102 };
103
104 pub const fn projector(square: Square) -> &'static Projector<12> {
105 &ROOK_PROJECTOR[square as usize]
106 }
107
108 pub const fn blockers(square: Square) -> Bitboard {
109 const BLOCKERS: SliderBlockers = SliderBlockers::new(&DIRECTIONS);
110
111 BLOCKERS.get(square)
112 }
113}
114
115struct Projector<const B: u32> {
116 pub factor: u64,
117 pub offset: usize,
118}
119
120impl<const B: u32> Projector<B> {
121 const fn new(factor: u64, offset: usize) -> Self {
122 Self { factor, offset }
123 }
124
125 const fn index(&self, bitboard: Bitboard) -> usize {
127 (self.factor.wrapping_mul(bitboard.0) >> (64 - B)) as usize + self.offset
128 }
129}
130
131pub struct SliderSights([Bitboard; 88772]);
132
133impl SliderSights {
134 pub const fn get() -> &'static Self {
135 #[cfg(rust_chess_compile_time_slider_sights)]
136 #[allow(long_running_const_eval)]
137 static SIGHTS: SliderSights = SliderSights::compute();
138 #[cfg(not(rust_chess_compile_time_slider_sights))]
139 static SIGHTS: SliderSights = include!("SLIDER-SIGHTS.rs");
140
141 &SIGHTS
142 }
143
144 pub const fn as_array(&self) -> &[Bitboard; 88772] {
145 &self.0
146 }
147
148 pub const fn bishop_sight(&self, square: Square, occupied: Bitboard) -> Bitboard {
151 let blockers = bishop::blockers(square);
152 let index = bishop::projector(square).index(occupied.intersection(blockers));
153 self.0[index]
154 }
155
156 pub const fn rook_sight(&self, square: Square, occupied: Bitboard) -> Bitboard {
157 let blockers = rook::blockers(square);
158 let index = rook::projector(square).index(occupied.intersection(blockers));
159 self.0[index]
160 }
161}
162
163#[cfg(any(rust_chess_compile_time_slider_sights, test))]
164impl SliderSights {
165 pub const fn compute() -> Self {
166 let mut this = Self([Bitboard::EMPTY; 88772]);
167 finite_for!(square in Square {
168 this.project_bishop_sights(square);
169 this.project_rook_sights(square);
170 });
171 this
172 }
173
174 const fn project_bishop_sights(&mut self, square: Square) {
175 self.project_slider_sights(
176 square,
177 &bishop::DIRECTIONS,
178 bishop::blockers(square),
179 bishop::projector(square),
180 );
181 }
182
183 const fn project_rook_sights(&mut self, square: Square) {
184 self.project_slider_sights(
185 square,
186 &rook::DIRECTIONS,
187 rook::blockers(square),
188 rook::projector(square),
189 );
190 }
191
192 const fn at(&self, index: usize) -> Bitboard {
193 self.0[index]
194 }
195
196 const fn set(&mut self, index: usize, attack: Bitboard) {
197 self.0[index] = attack;
198 }
199
200 const fn project_slider_sights<const B: u32>(
201 &mut self,
202 square: Square,
203 directions: &[Direction],
204 blockers: Bitboard,
205 projector: &Projector<B>,
206 ) {
207 let mut occupied = Bitboard::EMPTY;
208 loop {
209 let index = projector.index(occupied);
210 let sight = Self::sight(square, occupied, directions);
211 assert!(self.at(index).is_empty() || self.at(index).eq(sight));
214 self.set(index, sight);
215 occupied = blockers.next_subset(occupied);
216 if occupied.is_empty() {
217 break;
218 }
219 }
220 }
221
222 const fn sight(square: Square, occupied: Bitboard, directions: &[Direction]) -> Bitboard {
225 let mut sight = Bitboard::EMPTY;
226 let mut i = 0;
227 while i < directions.len() {
228 let direction = directions[i];
229 let mut square = square;
230 while let Some(target) = square.checked_add(direction) {
231 sight.append(Bitboard::from_square(target));
232 if occupied.contains(target) {
234 break;
235 }
236 square = target;
237 }
238 i += 1;
239 }
240 sight
241 }
242}
243
244#[allow(dead_code)]
245struct SliderBlockers([Bitboard; 64]);
246
247#[allow(dead_code)]
248impl SliderBlockers {
249 const fn new(directions: &[Direction]) -> Self {
250 let mut blockers = [Bitboard::EMPTY; 64];
251 finite_for!(square in Square {
252 blockers[square as usize] = Self::ray_blockers(square, directions);
253 });
254 Self(blockers)
255 }
256
257 const fn get(&self, square: Square) -> Bitboard {
258 self.0[square as usize]
259 }
260
261 const fn ray_blockers(square: Square, directions: &[Direction]) -> Bitboard {
262 let mut blockers = Bitboard::EMPTY;
263 let mut i = 0;
264 while i < directions.len() {
265 let direction = directions[i];
266 let mut target = square.checked_add(direction);
267 while let Some(square) = target {
268 target = square.checked_add(direction);
269 if target.is_some() {
270 blockers.append(Bitboard::from_square(square));
271 }
272 }
273 i += 1;
274 }
275 blockers
276 }
277}
278
279const BISHOP_PROJECTOR: [Projector<9>; 64] = [
283 Projector::new(0x007f_bfbf_bfbf_bfff, 5378),
284 Projector::new(0x0000_a060_4010_07fc, 4093),
285 Projector::new(0x0001_0040_0802_0000, 4314),
286 Projector::new(0x0000_8060_0400_0000, 6587),
287 Projector::new(0x0000_1004_0000_0000, 6491),
288 Projector::new(0x0000_21c1_00b2_0000, 6330),
289 Projector::new(0x0000_0400_4100_8000, 5609),
290 Projector::new(0x0000_0fb0_203f_ff80, 22236),
291 Projector::new(0x0000_0401_0040_1004, 6106),
292 Projector::new(0x0000_0200_8020_0802, 5625),
293 Projector::new(0x0000_0040_1020_2000, 16785),
294 Projector::new(0x0000_0080_6004_0000, 16817),
295 Projector::new(0x0000_0044_0200_0000, 6842),
296 Projector::new(0x0000_0008_0100_8000, 7003),
297 Projector::new(0x0000_07ef_e0bf_ff80, 4197),
298 Projector::new(0x0000_0008_2082_0020, 7356),
299 Projector::new(0x0000_4000_8080_8080, 4602),
300 Projector::new(0x0002_1f01_0040_0808, 4538),
301 Projector::new(0x0001_8000_c06f_3fff, 29531),
302 Projector::new(0x0000_2582_0080_1000, 45393),
303 Projector::new(0x0000_2400_8084_0000, 12420),
304 Projector::new(0x0000_1800_0c03_fff8, 15763),
305 Projector::new(0x0000_0a58_4020_8020, 5050),
306 Projector::new(0x0000_0200_0820_8020, 4346),
307 Projector::new(0x0000_8040_0081_0100, 6074),
308 Projector::new(0x0001_0119_0080_2008, 7866),
309 Projector::new(0x0000_8040_0081_0100, 32139),
310 Projector::new(0x0001_0040_3c04_03ff, 57673),
311 Projector::new(0x0007_8402_a880_2000, 55365),
312 Projector::new(0x0000_1010_0080_4400, 15818),
313 Projector::new(0x0000_0808_0010_4100, 5562),
314 Projector::new(0x0000_4004_c008_2008, 6390),
315 Projector::new(0x0001_0101_2000_8020, 7930),
316 Projector::new(0x0000_8080_9a00_4010, 13329),
317 Projector::new(0x0007_fefe_0881_0010, 7170),
318 Projector::new(0x0003_ff0f_833f_c080, 27267),
319 Projector::new(0x007f_e080_1900_3042, 53787),
320 Projector::new(0x003f_ffef_ea00_3000, 5097),
321 Projector::new(0x0000_1010_1000_2080, 6643),
322 Projector::new(0x0000_8020_0508_0804, 6138),
323 Projector::new(0x0000_8080_80a8_0040, 7418),
324 Projector::new(0x0000_1041_0020_0040, 7898),
325 Projector::new(0x0003_ffdf_7f83_3fc0, 42012),
326 Projector::new(0x0000_0088_4045_0020, 57350),
327 Projector::new(0x0000_7ffc_8018_0030, 22813),
328 Projector::new(0x007f_ffdd_8014_0028, 56693),
329 Projector::new(0x0002_0080_200a_0004, 5818),
330 Projector::new(0x0000_1010_1010_0020, 7098),
331 Projector::new(0x0007_ffdf_c180_5000, 4451),
332 Projector::new(0x0003_ffef_e0c0_2200, 4709),
333 Projector::new(0x0000_0008_2080_6000, 4794),
334 Projector::new(0x0000_0000_0840_3000, 13364),
335 Projector::new(0x0000_0001_0020_2000, 4570),
336 Projector::new(0x0000_0040_4080_2000, 4282),
337 Projector::new(0x0004_0100_4010_0400, 14964),
338 Projector::new(0x0000_6020_6018_03f4, 4026),
339 Projector::new(0x0003_ffdf_dfc2_8048, 4826),
340 Projector::new(0x0000_0008_2082_0020, 7354),
341 Projector::new(0x0000_0000_0820_8060, 4848),
342 Projector::new(0x0000_0000_0080_8020, 15946),
343 Projector::new(0x0000_0000_0100_2020, 14932),
344 Projector::new(0x0000_0004_0100_2008, 16588),
345 Projector::new(0x0000_0040_4040_4040, 6905),
346 Projector::new(0x007f_ff9f_df7f_f813, 16076),
347];
348
349const ROOK_PROJECTOR: [Projector<12>; 64] = [
350 Projector::new(0x0028_0077_ffeb_fffe, 26304),
351 Projector::new(0x2004_0102_0109_7fff, 35520),
352 Projector::new(0x0010_0200_1005_3fff, 38592),
353 Projector::new(0x0040_0400_0800_4002, 8026),
354 Projector::new(0x7fd0_0441_ffff_d003, 22196),
355 Projector::new(0x4020_0088_87df_fffe, 80870),
356 Projector::new(0x0040_0088_8847_ffff, 76747),
357 Projector::new(0x0068_00fb_ff75_fffd, 30400),
358 Projector::new(0x0000_2801_0113_ffff, 11115),
359 Projector::new(0x0020_0402_01fc_ffff, 18205),
360 Projector::new(0x007f_e800_42ff_ffe8, 53577),
361 Projector::new(0x0000_1800_217f_ffe8, 62724),
362 Projector::new(0x0000_1800_073f_ffe8, 34282),
363 Projector::new(0x0000_1800_e05f_ffe8, 29196),
364 Projector::new(0x0000_1800_602f_ffe8, 23806),
365 Projector::new(0x0000_3000_2fff_ffa0, 49481),
366 Projector::new(0x0030_0018_010b_ffff, 2410),
367 Projector::new(0x0003_000c_0085_fffb, 36498),
368 Projector::new(0x0004_0008_0201_0008, 24478),
369 Projector::new(0x0004_0020_2002_0004, 10074),
370 Projector::new(0x0001_0020_0200_2001, 79315),
371 Projector::new(0x0001_0010_0080_1040, 51779),
372 Projector::new(0x0000_0040_4000_8001, 13586),
373 Projector::new(0x0000_0068_00cd_fff4, 19323),
374 Projector::new(0x0040_2000_1008_0010, 70612),
375 Projector::new(0x0000_0800_1004_0010, 83652),
376 Projector::new(0x0004_0100_0802_0008, 63110),
377 Projector::new(0x0000_0400_2020_0200, 34496),
378 Projector::new(0x0002_0080_1010_0100, 84966),
379 Projector::new(0x0000_0080_2001_0020, 54341),
380 Projector::new(0x0000_0080_2020_0040, 60421),
381 Projector::new(0x0000_8200_2000_4020, 86402),
382 Projector::new(0x00ff_fd18_0030_0030, 50245),
383 Projector::new(0x007f_ff7f_bfd4_0020, 76622),
384 Projector::new(0x003f_ffbd_0018_0018, 84676),
385 Projector::new(0x001f_ffde_8018_0018, 78757),
386 Projector::new(0x000f_ffe0_bfe8_0018, 37346),
387 Projector::new(0x0001_0000_8020_2001, 370),
388 Projector::new(0x0003_fffb_ff98_0180, 42182),
389 Projector::new(0x0001_fffd_ff90_00e0, 45385),
390 Projector::new(0x00ff_fefe_ebff_d800, 61659),
391 Projector::new(0x007f_fff7_ffc0_1400, 12790),
392 Projector::new(0x003f_ffbf_e4ff_e800, 16762),
393 Projector::new(0x001f_fff0_1fc0_3000, 0),
394 Projector::new(0x000f_ffe7_f8bf_e800, 38380),
395 Projector::new(0x0007_ffdf_df3f_f808, 11098),
396 Projector::new(0x0003_fff8_5fff_a804, 21803),
397 Projector::new(0x0001_fffd_75ff_a802, 39189),
398 Projector::new(0x00ff_ffd7_ffeb_ffd8, 58628),
399 Projector::new(0x007f_ff75_ff7f_bfd8, 44116),
400 Projector::new(0x003f_ff86_3fbf_7fd8, 78357),
401 Projector::new(0x001f_ffbf_dfd7_ffd8, 44481),
402 Projector::new(0x000f_fff8_1028_0028, 64134),
403 Projector::new(0x0007_ffd7_f7fe_ffd8, 41759),
404 Projector::new(0x0003_fffc_0c48_0048, 1394),
405 Projector::new(0x0001_ffff_afd7_ffd8, 40910),
406 Projector::new(0x00ff_ffe4_ffdf_a3ba, 66516),
407 Projector::new(0x007f_ffef_7ff3_d3da, 3897),
408 Projector::new(0x003f_ffbf_dfef_f7fa, 3930),
409 Projector::new(0x001f_ffef_f7fb_fc22, 72934),
410 Projector::new(0x0000_0204_0800_1001, 72662),
411 Projector::new(0x0007_fffe_ffff_77fd, 56325),
412 Projector::new(0x0003_ffff_bf7d_feec, 66501),
413 Projector::new(0x0001_ffff_9dff_a333, 14826),
414];