Skip to main content

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('\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(BitBoard::from_square)
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		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}