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