1use super::*;
2
3#[repr(transparent)]
4#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5#[derive(Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Debug, Hash)]
6pub struct BitBoard(u64);
7
8macro_rules! generate_shift_functions {
9 ($func: ident, $operator: tt, $empty_side: ident) => {
10 #[inline]
11 pub fn $func(self, n: u8) -> Self {
12 if n > 7 {
13 BitBoard::EMPTY
14 } else {
15 (self $operator n)
16 & get_item_unchecked!(
17 const {
18 let mut array = [BitBoard::ALL; 8];
19 let mut i = 1;
20 while i < 8 {
21 array[i].0 = array[i - 1].0 & !($empty_side.0 $operator (i - 1));
22 i += 1;
23 }
24 array
25 },
26 n as usize,
27 )
28 }
29 }
30 };
31}
32
33impl BitBoard {
34 pub const EMPTY: Self = Self(0);
35 pub const ALL: Self = Self::new(0xFFFFFFFFFFFFFFFF);
36
37 #[inline]
38 pub const fn new(bb: u64) -> Self {
39 unsafe { std::mem::transmute(bb) }
40 }
41
42 #[inline]
43 pub const fn set_mask(&mut self, mask: u64) {
44 self.0 = mask;
45 }
46
47 #[inline]
49 pub const fn from_rank_and_file(rank: Rank, file: File) -> Self {
50 Self::new(1 << ((rank.to_int() << 3) ^ file.to_int()))
51 }
52
53 #[inline]
54 pub const fn popcnt(self) -> u32 {
55 self.0.count_ones()
56 }
57
58 #[inline]
59 pub const fn reverse_colors(self) -> Self {
60 Self::new(self.0.swap_bytes())
61 }
62
63 #[inline]
64 pub const unsafe fn to_square_index_unchecked(self) -> usize {
65 self.0.trailing_zeros() as usize
66 }
67
68 #[inline]
69 pub const unsafe fn to_square_unchecked(self) -> Square {
70 Square::from_index(self.to_square_index_unchecked())
71 }
72
73 #[inline]
74 pub const fn to_square_index(self) -> Option<usize> {
75 if self.is_empty() {
76 None
77 } else {
78 Some(unsafe { self.to_square_index_unchecked() })
79 }
80 }
81
82 #[inline]
83 pub const fn to_square(self) -> Option<Square> {
84 if self.is_empty() {
85 None
86 } else {
87 Some(unsafe { self.to_square_unchecked() })
88 }
89 }
90
91 #[inline]
92 pub const fn xor_square(&mut self, square: Square) {
93 self.0 ^= square.to_bitboard().0;
94 }
95
96 #[inline]
97 pub const fn remove_square(&mut self, square: Square) {
98 self.0 &= !square.to_bitboard().0;
99 }
100
101 pub const unsafe fn pop_square_unchecked(&mut self) -> Square {
102 let square = self.to_square_unchecked();
103 self.xor_square(square);
104 square
105 }
106
107 #[inline]
108 pub const fn pop_square(&mut self) -> Option<Square> {
109 if self.is_empty() {
110 None
111 } else {
112 Some(unsafe { self.pop_square_unchecked() })
113 }
114 }
115
116 #[inline]
117 pub const fn wrapping_mul(self, rhs: Self) -> Self {
118 Self::new(self.0.wrapping_mul(rhs.0))
119 }
120
121 #[inline]
122 pub const fn is_empty(self) -> bool {
123 self.0 == const { Self::EMPTY.0 }
124 }
125
126 pub const fn flip_vertical(self) -> Self {
128 let mut bb = self.0;
129 bb = ((bb >> 8) & 0x00FF_00FF_00FF_00FF) | ((bb & 0x00FF_00FF_00FF_00FF) << 8);
130 bb = ((bb >> 16) & 0x0000_FFFF_0000_FFFF) | ((bb & 0x0000_FFFF_0000_FFFF) << 16);
131 bb = (bb >> 32) | ((bb & 0x0000_0000_FFFF_FFFF) << 32);
132 Self::new(bb)
133 }
134
135 pub const fn flip_horizontal(self) -> Self {
137 let mut bb = self.0;
138 bb = ((bb >> 1) & 0x5555_5555_5555_5555) | ((bb & 0x5555_5555_5555_5555) << 1);
139 bb = ((bb >> 2) & 0x3333_3333_3333_3333) | ((bb & 0x3333_3333_3333_3333) << 2);
140 bb = ((bb >> 4) & 0x0F0F_0F0F_0F0F_0F0F) | ((bb & 0x0F0F_0F0F_0F0F_0F0F) << 4);
141 Self::new(bb)
142 }
143
144 pub const fn flip_diagonal(self) -> Self {
146 let mut bb = self.0;
147 let mut t = (bb ^ (bb << 28)) & 0x0F0F_0F0F_0000_0000;
148 bb = bb ^ t ^ (t >> 28);
149 t = (bb ^ (bb << 14)) & 0x3333_0000_3333_0000;
150 bb = bb ^ t ^ (t >> 14);
151 t = (bb ^ (bb << 7)) & 0x5500_5500_5500_5500;
152 bb = bb ^ t ^ (t >> 7);
153 Self::new(bb)
154 }
155
156 pub const fn flip_anti_diagonal(self) -> Self {
158 let mut bb = self.0;
159 let mut t = bb ^ (bb << 36);
160 bb = bb ^ ((t ^ (bb >> 36)) & 0xF0F0_F0F0_0F0F_0F0F);
161 t = (bb ^ (bb << 18)) & 0xCCCC_0000_CCCC_0000;
162 bb = bb ^ t ^ (t >> 18);
163 t = (bb ^ (bb << 9)) & 0xAA00_AA00_AA00_AA00;
164 bb = bb ^ t ^ (t >> 9);
165 Self::new(bb)
166 }
167
168 #[inline]
169 pub const fn shift_up_n_times(self, n: u8) -> Self {
170 if n > 7 {
171 Self::EMPTY
172 } else {
173 Self::new(self.0 << (n << 3))
174 }
175 }
176
177 #[inline]
178 pub const fn shift_down_n_times(self, n: u8) -> Self {
179 if n > 7 {
180 Self::EMPTY
181 } else {
182 Self::new(self.0 >> (n << 3))
183 }
184 }
185
186 generate_shift_functions!(shift_left_n_times, >>, BB_FILE_H);
187 generate_shift_functions!(shift_right_n_times, <<, BB_FILE_A);
188
189 #[inline]
190 pub const fn shift_up(self) -> Self {
191 self.shift_up_n_times(1)
192 }
193
194 #[inline]
195 pub const fn shift_down(self) -> Self {
196 self.shift_down_n_times(1)
197 }
198
199 #[inline]
200 pub const fn shift_left(self) -> Self {
201 Self::new((self.0 & const { !BB_FILE_A.0 }) >> 1)
202 }
203
204 #[inline]
205 pub const fn shift_right(self) -> Self {
206 Self::new((self.0 & const { !BB_FILE_H.0 }) << 1)
207 }
208
209 #[inline]
210 pub const fn shift_forward_n_times(self, color: Color, n: u8) -> Self {
211 match color {
212 White => self.shift_up_n_times(n),
213 Black => self.shift_down_n_times(n),
214 }
215 }
216
217 #[inline]
218 pub const fn shift_backward_n_times(self, color: Color, n: u8) -> Self {
219 match color {
220 White => self.shift_down_n_times(n),
221 Black => self.shift_up_n_times(n),
222 }
223 }
224
225 #[inline]
226 pub const fn shift_forward(self, color: Color) -> Self {
227 self.shift_forward_n_times(color, 1)
228 }
229
230 #[inline]
231 pub const fn shift_backward(self, color: Color) -> Self {
232 self.shift_backward_n_times(color, 1)
233 }
234
235 #[inline]
236 pub const fn contains(self, square: Square) -> bool {
237 !Self::new(self.0 & square.to_bitboard().0).is_empty()
238 }
239
240 #[inline]
241 pub const fn into_inner(self) -> u64 {
242 self.0
243 }
244
245 #[inline]
246 pub const fn to_usize(self) -> usize {
247 self.0 as usize
248 }
249}
250
251impl From<&BitBoard> for u64 {
252 #[inline]
253 fn from(value: &BitBoard) -> Self {
254 value.0
255 }
256}
257
258impl From<BitBoard> for u64 {
259 #[inline]
260 fn from(value: BitBoard) -> Self {
261 (&value).into()
262 }
263}
264
265impl From<u64> for BitBoard {
266 #[inline]
267 fn from(value: u64) -> Self {
268 Self::new(value)
269 }
270}
271
272impl From<&u64> for BitBoard {
273 #[inline]
274 fn from(value: &u64) -> Self {
275 (*value).into()
276 }
277}
278
279macro_rules! implement_u64_methods {
280 ($($visibility:vis const fn $function:ident(self $(, $argument:ident: $argument_type:ty)* $(,)?) -> $return_type:ty),* $(,)?) => {
281 impl BitBoard {
282 $(
283 #[inline]
284 $visibility const fn $function(&self, $($argument: $argument_type),*) -> $return_type {
285 Self::new(self.0.$function($($argument),*))
286 }
287 )*
288 }
289 };
290}
291
292implement_u64_methods!(
293 pub const fn wrapping_shl(self, rhs: u32) -> Self,
294 pub const fn wrapping_shr(self, rhs: u32) -> Self,
295);
296
297macro_rules! implement_bitwise_operations {
298 (@bit_shifting $direct_trait: ident, $assign_trait: ident, $direct_func: ident, $assign_func: ident) => {
299 impl<T> $assign_trait<T> for BitBoard where u64: $assign_trait<T> {
300
301 #[inline]
302 fn $assign_func(&mut self, rhs: T) {
303 self.0.$assign_func(rhs)
304 }
305 }
306
307 impl<T> $direct_trait<T> for BitBoard where Self: $assign_trait<T> {
308 type Output = Self;
309
310 #[inline]
311 fn $direct_func(mut self, rhs: T) -> Self::Output {
312 self.$assign_func(rhs);
313 self
314 }
315 }
316
317 impl<T> $direct_trait<T> for &BitBoard where BitBoard: $direct_trait<T> {
318 type Output = <BitBoard as $direct_trait<T>>::Output;
319
320 #[inline]
321 fn $direct_func(self, rhs: T) -> Self::Output {
322 (*self).$direct_func(rhs)
323 }
324 }
325 };
326
327 ($direct_trait: ident, $assign_trait: ident, $direct_func: ident, $assign_func: ident) => {
328 implement_bitwise_operations!(@bigger_integer_implementation $direct_trait, $assign_trait, $direct_func, $assign_func, u128);
329 implement_bitwise_operations!(@bigger_integer_implementation $direct_trait, $assign_trait, $direct_func, $assign_func, u64);
330 implement_bitwise_operations!(@bigger_integer_implementation $direct_trait, $assign_trait, $direct_func, $assign_func, i128);
331
332 impl<T> $assign_trait<T> for BitBoard where u64: From<T> {
333
334 #[inline]
335 fn $assign_func(&mut self, rhs: T) {
336 self.0.$assign_func(u64::from(rhs))
337 }
338 }
339
340 impl<T> $direct_trait<T> for BitBoard where u64: From<T> {
341 type Output = Self;
342
343 #[inline]
344 fn $direct_func(mut self, rhs: T) -> Self::Output {
345 self.$assign_func(rhs);
346 self
347 }
348 }
349
350 impl<T> $direct_trait<T> for &BitBoard where u64: From<T> {
351 type Output = BitBoard;
352
353 #[inline]
354 fn $direct_func(self, rhs: T) -> Self::Output {
355 (*self).$direct_func(rhs)
356 }
357 }
358 };
359
360 (@bigger_integer_implementation $direct_trait: ident, $assign_trait: ident, $direct_func: ident, $assign_func: ident, $int_type: ident) => {
361 impl $assign_trait<&BitBoard> for $int_type {
362 #[inline]
363 fn $assign_func(&mut self, rhs: &BitBoard) {
364 self.$assign_func(rhs.0 as $int_type)
365 }
366 }
367
368 impl $assign_trait<BitBoard> for $int_type {
369 #[inline]
370 fn $assign_func(&mut self, rhs: BitBoard) {
371 self.$assign_func(&rhs)
372 }
373 }
374
375 impl $direct_trait<&BitBoard> for $int_type {
376 type Output = $int_type;
377
378 #[inline]
379 fn $direct_func(mut self, rhs: &BitBoard) -> Self::Output {
380 self.$assign_func(rhs);
381 self
382 }
383 }
384
385 impl $direct_trait<BitBoard> for $int_type {
386 type Output = $int_type;
387
388 #[inline]
389 fn $direct_func(self, rhs: BitBoard) -> Self::Output {
390 self.$direct_func(&rhs)
391 }
392 }
393
394 impl $direct_trait<&BitBoard> for &$int_type {
395 type Output = $int_type;
396
397 #[inline]
398 fn $direct_func(self, rhs: &BitBoard) -> Self::Output {
399 (*self).$direct_func(rhs)
400 }
401 }
402
403 impl $direct_trait<BitBoard> for &$int_type {
404 type Output = $int_type;
405
406 #[inline]
407 fn $direct_func(self, rhs: BitBoard) -> Self::Output {
408 self.$direct_func(&rhs)
409 }
410 }
411 };
412}
413
414implement_bitwise_operations!(BitAnd, BitAndAssign, bitand, bitand_assign);
415implement_bitwise_operations!(BitOr, BitOrAssign, bitor, bitor_assign);
416implement_bitwise_operations!(BitXor, BitXorAssign, bitxor, bitxor_assign);
417implement_bitwise_operations!(Mul, MulAssign, mul, mul_assign);
418implement_bitwise_operations!(@bit_shifting Shl, ShlAssign, shl, shl_assign);
419implement_bitwise_operations!(@bit_shifting Shr, ShrAssign, shr, shr_assign);
420
421impl Not for &BitBoard {
422 type Output = BitBoard;
423
424 #[inline]
425 fn not(self) -> BitBoard {
426 BitBoard::new(!self.0)
427 }
428}
429
430impl Not for BitBoard {
431 type Output = Self;
432
433 #[inline]
434 fn not(self) -> Self {
435 !&self
436 }
437}
438
439impl Iterator for BitBoard {
440 type Item = Square;
441
442 #[inline]
443 fn next(&mut self) -> Option<Square> {
444 self.pop_square()
445 }
446}
447
448impl fmt::Display for BitBoard {
449 #[inline]
450 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
451 let occupied_symbol = "X".colorize(BITBOARD_OCCUPIED_SQUARE_STYLE);
452 write!(
453 f,
454 "{}",
455 get_board_string(true, |square| if self.contains(square) {
456 occupied_symbol.as_str().into()
457 } else {
458 Cow::Borrowed(" ")
459 })
460 )
461 }
462}
463
464#[cfg(feature = "pyo3")]
465impl<'source> FromPyObject<'source> for BitBoard {
466 fn extract_bound(ob: &Bound<'source, PyAny>) -> PyResult<Self> {
467 if let Ok(int) = ob.extract::<u64>() {
468 return Ok(Self::new(int));
469 }
470 Err(Pyo3Error::Pyo3TypeConversionError {
471 from: ob.to_string().into(),
472 to: std::any::type_name::<Self>().into(),
473 }
474 .into())
475 }
476}