chess/
bitboard.rs

1use crate::file::File;
2use crate::rank::Rank;
3use crate::square::*;
4use std::fmt;
5use std::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Mul, Not};
6
7/// A good old-fashioned bitboard
8/// You *do* have access to the actual value, but you are probably better off
9/// using the implemented operators to work with this object.
10///
11/// ```
12/// use chess::{BitBoard, Square};
13///
14/// let bb = BitBoard(7); // lower-left 3 squares
15///
16/// let mut count = 0;
17///
18/// // Iterate over each square in the bitboard
19/// for _ in bb {
20///     count += 1;
21/// }
22///
23/// assert_eq!(count, 3);
24/// ```
25///
26#[derive(PartialEq, Eq, PartialOrd, Clone, Copy, Debug, Default, Hash)]
27pub struct BitBoard(pub u64);
28
29/// An empty bitboard.  It is sometimes useful to use !EMPTY to get the universe of squares.
30///
31/// ```
32///     use chess::EMPTY;
33///
34///     assert_eq!(EMPTY.count(), 0);
35///
36///     assert_eq!((!EMPTY).count(), 64);
37/// ```
38pub const EMPTY: BitBoard = BitBoard(0);
39
40// Impl BitAnd
41impl BitAnd for BitBoard {
42    type Output = BitBoard;
43
44    #[inline]
45    fn bitand(self, other: BitBoard) -> BitBoard {
46        BitBoard(self.0 & other.0)
47    }
48}
49
50impl BitAnd for &BitBoard {
51    type Output = BitBoard;
52
53    #[inline]
54    fn bitand(self, other: &BitBoard) -> BitBoard {
55        BitBoard(self.0 & other.0)
56    }
57}
58
59impl BitAnd<&BitBoard> for BitBoard {
60    type Output = BitBoard;
61
62    #[inline]
63    fn bitand(self, other: &BitBoard) -> BitBoard {
64        BitBoard(self.0 & other.0)
65    }
66}
67
68impl BitAnd<BitBoard> for &BitBoard {
69    type Output = BitBoard;
70
71    #[inline]
72    fn bitand(self, other: BitBoard) -> BitBoard {
73        BitBoard(self.0 & other.0)
74    }
75}
76
77// Impl BitOr
78impl BitOr for BitBoard {
79    type Output = BitBoard;
80
81    #[inline]
82    fn bitor(self, other: BitBoard) -> BitBoard {
83        BitBoard(self.0 | other.0)
84    }
85}
86
87impl BitOr for &BitBoard {
88    type Output = BitBoard;
89
90    #[inline]
91    fn bitor(self, other: &BitBoard) -> BitBoard {
92        BitBoard(self.0 | other.0)
93    }
94}
95
96impl BitOr<&BitBoard> for BitBoard {
97    type Output = BitBoard;
98
99    #[inline]
100    fn bitor(self, other: &BitBoard) -> BitBoard {
101        BitBoard(self.0 | other.0)
102    }
103}
104
105impl BitOr<BitBoard> for &BitBoard {
106    type Output = BitBoard;
107
108    #[inline]
109    fn bitor(self, other: BitBoard) -> BitBoard {
110        BitBoard(self.0 | other.0)
111    }
112}
113
114// Impl BitXor
115
116impl BitXor for BitBoard {
117    type Output = BitBoard;
118
119    #[inline]
120    fn bitxor(self, other: BitBoard) -> BitBoard {
121        BitBoard(self.0 ^ other.0)
122    }
123}
124
125impl BitXor for &BitBoard {
126    type Output = BitBoard;
127
128    #[inline]
129    fn bitxor(self, other: &BitBoard) -> BitBoard {
130        BitBoard(self.0 ^ other.0)
131    }
132}
133
134impl BitXor<&BitBoard> for BitBoard {
135    type Output = BitBoard;
136
137    #[inline]
138    fn bitxor(self, other: &BitBoard) -> BitBoard {
139        BitBoard(self.0 ^ other.0)
140    }
141}
142
143impl BitXor<BitBoard> for &BitBoard {
144    type Output = BitBoard;
145
146    #[inline]
147    fn bitxor(self, other: BitBoard) -> BitBoard {
148        BitBoard(self.0 ^ other.0)
149    }
150}
151
152// Impl BitAndAssign
153
154impl BitAndAssign for BitBoard {
155    #[inline]
156    fn bitand_assign(&mut self, other: BitBoard) {
157        self.0 &= other.0;
158    }
159}
160
161impl BitAndAssign<&BitBoard> for BitBoard {
162    #[inline]
163    fn bitand_assign(&mut self, other: &BitBoard) {
164        self.0 &= other.0;
165    }
166}
167
168// Impl BitOrAssign
169impl BitOrAssign for BitBoard {
170    #[inline]
171    fn bitor_assign(&mut self, other: BitBoard) {
172        self.0 |= other.0;
173    }
174}
175
176impl BitOrAssign<&BitBoard> for BitBoard {
177    #[inline]
178    fn bitor_assign(&mut self, other: &BitBoard) {
179        self.0 |= other.0;
180    }
181}
182
183// Impl BitXor Assign
184impl BitXorAssign for BitBoard {
185    #[inline]
186    fn bitxor_assign(&mut self, other: BitBoard) {
187        self.0 ^= other.0;
188    }
189}
190
191impl BitXorAssign<&BitBoard> for BitBoard {
192    #[inline]
193    fn bitxor_assign(&mut self, other: &BitBoard) {
194        self.0 ^= other.0;
195    }
196}
197
198// Impl Mul
199impl Mul for BitBoard {
200    type Output = BitBoard;
201
202    #[inline]
203    fn mul(self, other: BitBoard) -> BitBoard {
204        BitBoard(self.0.wrapping_mul(other.0))
205    }
206}
207
208impl Mul for &BitBoard {
209    type Output = BitBoard;
210
211    #[inline]
212    fn mul(self, other: &BitBoard) -> BitBoard {
213        BitBoard(self.0.wrapping_mul(other.0))
214    }
215}
216
217impl Mul<&BitBoard> for BitBoard {
218    type Output = BitBoard;
219
220    #[inline]
221    fn mul(self, other: &BitBoard) -> BitBoard {
222        BitBoard(self.0.wrapping_mul(other.0))
223    }
224}
225
226impl Mul<BitBoard> for &BitBoard {
227    type Output = BitBoard;
228
229    #[inline]
230    fn mul(self, other: BitBoard) -> BitBoard {
231        BitBoard(self.0.wrapping_mul(other.0))
232    }
233}
234
235// Impl Not
236impl Not for BitBoard {
237    type Output = BitBoard;
238
239    #[inline]
240    fn not(self) -> BitBoard {
241        BitBoard(!self.0)
242    }
243}
244
245impl Not for &BitBoard {
246    type Output = BitBoard;
247
248    #[inline]
249    fn not(self) -> BitBoard {
250        BitBoard(!self.0)
251    }
252}
253
254impl fmt::Display for BitBoard {
255    #[inline]
256    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
257        let mut s: String = "".to_owned();
258        for x in 0..64 {
259            if self.0 & (1u64 << x) == (1u64 << x) {
260                s.push_str("X ");
261            } else {
262                s.push_str(". ");
263            }
264            if x % 8 == 7 {
265                s.push_str("\n");
266            }
267        }
268        write!(f, "{}", s)
269    }
270}
271
272impl BitBoard {
273    /// Construct a new bitboard from a u64
274    #[inline]
275    pub fn new(b: u64) -> BitBoard {
276        BitBoard(b)
277    }
278
279    /// Construct a new `BitBoard` with a particular `Square` set
280    #[inline]
281    pub fn set(rank: Rank, file: File) -> BitBoard {
282        BitBoard::from_square(Square::make_square(rank, file))
283    }
284
285    /// Construct a new `BitBoard` with a particular `Square` set
286    #[inline]
287    pub fn from_square(sq: Square) -> BitBoard {
288        BitBoard(1u64 << sq.to_int())
289    }
290
291    /// Convert an `Option<Square>` to an `Option<BitBoard>`
292    #[inline]
293    pub fn from_maybe_square(sq: Option<Square>) -> Option<BitBoard> {
294        sq.map(|s| BitBoard::from_square(s))
295    }
296
297    /// Convert a `BitBoard` to a `Square`.  This grabs the least-significant `Square`
298    #[inline]
299    pub fn to_square(&self) -> Square {
300        unsafe { Square::new(self.0.trailing_zeros() as u8) }
301    }
302
303    /// Count the number of `Squares` set in this `BitBoard`
304    #[inline]
305    pub fn popcnt(&self) -> u32 {
306        self.0.count_ones()
307    }
308
309    /// Reverse this `BitBoard`.  Look at it from the opponents perspective.
310    #[inline]
311    pub fn reverse_colors(&self) -> BitBoard {
312        BitBoard(self.0.swap_bytes())
313    }
314
315    /// Convert this `BitBoard` to a `usize` (for table lookups)
316    #[inline]
317    pub fn to_size(&self, rightshift: u8) -> usize {
318        (self.0 >> rightshift) as usize
319    }
320}
321
322/// For the `BitBoard`, iterate over every `Square` set.
323impl Iterator for BitBoard {
324    type Item = Square;
325
326    #[inline]
327    fn next(&mut self) -> Option<Square> {
328        if self.0 == 0 {
329            None
330        } else {
331            let result = self.to_square();
332            *self ^= BitBoard::from_square(result);
333            Some(result)
334        }
335    }
336}