1use std::fmt;
2
3use bitvec::prelude::*;
4
5use crate::{DimensionMismatch, bitboard::BitBoard};
6
7#[derive(Debug, Clone, PartialEq, Eq)]
11pub struct BitBoardDyn {
12 pub board: BitVec,
14
15 pub n_rows: usize,
17
18 pub n_cols: usize,
20}
21
22impl fmt::Display for BitBoardDyn {
23 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
24 write!(f, " ")?; for col in 0..self.n_cols {
27 write!(f, "{}", col % 10)?; }
29 writeln!(f)?;
30
31 for row in 0..self.n_rows {
32 write!(f, "{:>2} ", row)?;
34 for col in 0..self.n_cols {
35 let idx = row * self.n_cols + col;
36 let bit = self.board[idx];
37 let c = if bit { 'X' } else { '.' };
38 write!(f, "{}", c)?;
39 }
40 writeln!(f)?;
41 }
42 Ok(())
43 }
44}
45
46impl BitBoard for BitBoardDyn {
47 fn n_rows(&self) -> usize {
48 self.n_rows
49 }
50
51 fn n_cols(&self) -> usize {
52 self.n_cols
53 }
54
55 fn board_mut(&mut self) -> &mut BitSlice {
56 &mut self.board
57 }
58
59 fn board(&self) -> &BitSlice {
60 &self.board
61 }
62
63 fn or(&self, other: &impl BitBoard) -> Result<Self, DimensionMismatch> {
64 if (self.n_rows != other.n_rows()) || (self.n_cols != other.n_cols()) {
65 return Err(DimensionMismatch);
66 }
67 let mut new_board = BitBoardDyn::new(self.n_rows, self.n_cols);
68 new_board.board = self.board.clone() | other.board().to_bitvec();
69 Ok(new_board)
70 }
71
72 fn and(&self, other: &impl BitBoard) -> Result<Self, DimensionMismatch> {
73 if (self.n_rows != other.n_rows()) || (self.n_cols != other.n_cols()) {
74 return Err(DimensionMismatch);
75 }
76 let mut new_board = BitBoardDyn::new(self.n_rows, self.n_cols);
77 new_board.board = self.board.clone() & other.board().to_bitvec();
78 Ok(new_board)
79 }
80}
81
82impl BitBoardDyn {
83 pub fn new(n_rows: usize, n_cols: usize) -> Self {
85 BitBoardDyn {
86 board: bitvec![0; n_rows * n_cols],
87 n_rows,
88 n_cols,
89 }
90 }
91}
92
93#[cfg(test)]
94mod tests {
95 use super::*;
96 use rstest::rstest;
97
98 #[test]
99 fn can_construct() {
100 let bb = BitBoardDyn::new(2, 2);
101 println!("{:?}", bb);
102 }
103
104 #[test]
105 #[should_panic(expected = "row cannot be greater than n_rows")]
106 fn row_too_big() {
107 let bb = BitBoardDyn::new(2, 2);
108 bb.index_of(10, 0);
109 }
110
111 #[test]
112 #[should_panic(expected = "col cannot be greater than n_col")]
113 fn col_too_big() {
114 let bb = BitBoardDyn::new(2, 2);
115 bb.index_of(0, 10);
116 }
117
118 #[rstest]
119 #[case(0, 0, 0)]
120 #[case(0, 1, 1)]
121 #[case(1, 0, 2)]
122 #[case(1, 1, 3)]
123 fn index_of(#[case] row: usize, #[case] col: usize, #[case] expected: usize) {
124 let bb = BitBoardDyn::new(2, 2);
125 assert_eq!(expected, bb.index_of(row, col))
126 }
127
128 #[rstest]
129 #[case(0, 0, 0)]
130 #[case(1, 0, 1)]
131 #[case(2, 0, 2)]
132 #[case(3, 0, 3)]
133 #[case(4, 0, 4)]
134 fn col_vec_index_of(#[case] row: usize, #[case] col: usize, #[case] expected: usize) {
135 let bb = BitBoardDyn::new(5, 1);
136 assert_eq!(expected, bb.index_of(row, col))
137 }
138
139 #[rstest]
140 #[case(0, 0, 0)]
141 #[case(0, 1, 1)]
142 #[case(0, 2, 2)]
143 #[case(0, 3, 3)]
144 #[case(0, 4, 4)]
145 fn row_vec_index_of(#[case] row: usize, #[case] col: usize, #[case] expected: usize) {
146 let bb = BitBoardDyn::new(1, 5);
147 assert_eq!(expected, bb.index_of(row, col))
148 }
149
150 #[rstest]
151 #[case(0)]
152 #[case(1)]
153 #[case(2)]
154 #[case(3)]
155 #[case(4)]
156 fn set_col(#[case] col: usize) {
157 let mut bb = BitBoardDyn::new(5, 5);
158 bb.set_col(col, true);
159 for ridx in 0..bb.n_rows {
160 for cidx in 0..bb.n_cols {
161 if cidx == col {
162 assert!(bb.board[bb.index_of(ridx, cidx)])
163 } else {
164 assert!(!bb.board[bb.index_of(ridx, cidx)])
165 }
166 }
167 }
168 }
169
170 #[rstest]
171 #[case(0)]
172 #[case(1)]
173 #[case(2)]
174 #[case(3)]
175 #[case(4)]
176 fn set_row(#[case] row: usize) {
177 let mut bb = BitBoardDyn::new(5, 5);
178 bb.set_row(row, true);
179 for ridx in 0..bb.n_rows {
180 for cidx in 0..bb.n_cols {
181 if ridx == row {
182 assert!(bb.board[bb.index_of(ridx, cidx)])
183 } else {
184 assert!(!bb.board[bb.index_of(ridx, cidx)])
185 }
186 }
187 }
188 }
189
190 #[test]
191 fn can_set_all_bits() {
192 let nr = 3;
194 let nc = 3;
195 let mut bb = BitBoardDyn::new(nr, nc);
196
197 bb.set(0, 0, true);
198
199 for ridx in 0..nr {
201 for cidx in 0..nc {
202 bb.set(ridx, cidx, true);
203 }
204 }
205 assert!(bb.board.all());
206
207 for ridx in 0..nr {
209 for cidx in 0..nc {
210 bb.set(ridx, cidx, false);
211 }
212 }
213 assert!(bb.board.not_any());
214 }
215
216 #[rstest]
217 #[case(0, 0, BitBoardDyn { board: bitvec![0, 1, 1, 0], n_rows: 2, n_cols: 2 })]
218 #[case(0, 1, BitBoardDyn { board: bitvec![1, 0, 0, 1], n_rows: 2, n_cols: 2 })]
219 #[case(1, 0, BitBoardDyn { board: bitvec![1, 0, 0, 1], n_rows: 2, n_cols: 2 })]
220 #[case(1, 1, BitBoardDyn { board: bitvec![0, 1, 1, 0], n_rows: 2, n_cols: 2 })]
221 fn set_caridnal_neighbors_2x2(
222 #[case] row: usize,
223 #[case] col: usize,
224 #[case] expect: BitBoardDyn,
225 ) {
226 let mut bb = BitBoardDyn::new(2, 2);
227 bb.set_cardinal_neighbors(row, col, true);
228 assert_eq!(expect, bb);
229 }
230
231 #[rstest]
232 #[case(0, 0, BitBoardDyn { board: bitvec![0, 1, 0, 1, 0, 0, 0, 0, 0], n_rows: 3, n_cols: 3 })]
233 #[case(0, 1, BitBoardDyn { board: bitvec![1, 0, 1, 0, 1, 0, 0, 0, 0], n_rows: 3, n_cols: 3 })]
234 #[case(0, 2, BitBoardDyn { board: bitvec![0, 1, 0, 0, 0, 1, 0, 0, 0], n_rows: 3, n_cols: 3 })]
235 #[case(1, 0, BitBoardDyn { board: bitvec![1, 0, 0, 0, 1, 0, 1, 0, 0], n_rows: 3, n_cols: 3 })]
236 #[case(1, 1, BitBoardDyn { board: bitvec![0, 1, 0, 1, 0, 1, 0, 1, 0], n_rows: 3, n_cols: 3 })]
237 #[case(1, 2, BitBoardDyn { board: bitvec![0, 0, 1, 0, 1, 0, 0, 0, 1], n_rows: 3, n_cols: 3 })]
238 #[case(2, 0, BitBoardDyn { board: bitvec![0, 0, 0, 1, 0, 0, 0, 1, 0], n_rows: 3, n_cols: 3 })]
239 #[case(2, 1, BitBoardDyn { board: bitvec![0, 0, 0, 0, 1, 0, 1, 0, 1], n_rows: 3, n_cols: 3 })]
240 #[case(2, 2, BitBoardDyn { board: bitvec![0, 0, 0, 0, 0, 1, 0, 1, 0], n_rows: 3, n_cols: 3 })]
241 fn set_caridnal_neighbors_3x3(
242 #[case] row: usize,
243 #[case] col: usize,
244 #[case] expect: BitBoardDyn,
245 ) {
246 let mut bb = BitBoardDyn::new(3, 3);
247 bb.set_cardinal_neighbors(row, col, true);
248 assert_eq!(expect, bb);
249 }
250
251 #[rstest]
252 #[case(0, 0, BitBoardDyn { board: bitvec![0, 1, 1, 1], n_rows: 2, n_cols: 2 })]
253 #[case(0, 1, BitBoardDyn { board: bitvec![1, 0, 1, 1], n_rows: 2, n_cols: 2 })]
254 #[case(1, 0, BitBoardDyn { board: bitvec![1, 1, 0, 1], n_rows: 2, n_cols: 2 })]
255 #[case(1, 1, BitBoardDyn { board: bitvec![1, 1, 1, 0], n_rows: 2, n_cols: 2 })]
256 fn set_all_neighbors_2x2(#[case] row: usize, #[case] col: usize, #[case] expect: BitBoardDyn) {
257 let mut bb = BitBoardDyn::new(2, 2);
258 bb.set_all_neighbors(row, col, true);
259 assert_eq!(expect, bb);
260 }
261
262 #[rstest]
263 #[case(0, 0, BitBoardDyn { board: bitvec![0, 1, 0, 1, 1, 0, 0, 0, 0], n_rows: 3, n_cols: 3 })]
264 #[case(0, 1, BitBoardDyn { board: bitvec![1, 0, 1, 1, 1, 1, 0, 0, 0], n_rows: 3, n_cols: 3 })]
265 #[case(0, 2, BitBoardDyn { board: bitvec![0, 1, 0, 0, 1, 1, 0, 0, 0], n_rows: 3, n_cols: 3 })]
266 #[case(1, 0, BitBoardDyn { board: bitvec![1, 1, 0, 0, 1, 0, 1, 1, 0], n_rows: 3, n_cols: 3 })]
267 #[case(1, 1, BitBoardDyn { board: bitvec![1, 1, 1, 1, 0, 1, 1, 1, 1], n_rows: 3, n_cols: 3 })]
268 #[case(1, 2, BitBoardDyn { board: bitvec![0, 1, 1, 0, 1, 0, 0, 1, 1], n_rows: 3, n_cols: 3 })]
269 #[case(2, 0, BitBoardDyn { board: bitvec![0, 0, 0, 1, 1, 0, 0, 1, 0], n_rows: 3, n_cols: 3 })]
270 #[case(2, 1, BitBoardDyn { board: bitvec![0, 0, 0, 1, 1, 1, 1, 0, 1], n_rows: 3, n_cols: 3 })]
271 #[case(2, 2, BitBoardDyn { board: bitvec![0, 0, 0, 0, 1, 1, 0, 1, 0], n_rows: 3, n_cols: 3 })]
272 fn set_all_neighbors_3x3(#[case] row: usize, #[case] col: usize, #[case] expect: BitBoardDyn) {
273 let mut bb = BitBoardDyn::new(3, 3);
274 bb.set_all_neighbors(row, col, true);
275 assert_eq!(expect, bb);
276 }
277
278 #[rstest]
279 #[case(1, 1, 1, 2)]
280 #[case(2, 1, 1, 2)]
281 #[case(2, 1, 2, 7)]
282 fn and_dimension_mismatch(
283 #[case] b1r: usize,
284 #[case] b1c: usize,
285 #[case] b2r: usize,
286 #[case] b2c: usize,
287 ) {
288 let bb1 = BitBoardDyn::new(b1r, b1c);
289 let bb8 = BitBoardDyn::new(b2r, b2c);
290 assert!(bb1.and(&bb8).is_err());
291 }
292
293 #[rstest]
294 #[case(1, 1, 1, 2)]
295 #[case(2, 1, 1, 2)]
296 #[case(2, 1, 2, 7)]
297 fn or_dimension_mismatch(
298 #[case] b1r: usize,
299 #[case] b1c: usize,
300 #[case] b2r: usize,
301 #[case] b2c: usize,
302 ) {
303 let bb1 = BitBoardDyn::new(b1r, b1c);
304 let bb8 = BitBoardDyn::new(b2r, b2c);
305 assert!(bb1.or(&bb8).is_err());
306 }
307
308 #[rstest]
309 #[case(bitvec![0, 0, 0, 0], bitvec![0, 0, 0, 0], bitvec![0, 0, 0, 0])] #[case(bitvec![1, 1, 1, 1], bitvec![1, 1, 1, 1], bitvec![1, 1, 1, 1])] #[case(bitvec![0, 0, 0, 0], bitvec![1, 1, 1, 1], bitvec![0, 0, 0, 0])] #[case(bitvec![1, 1, 1, 1], bitvec![1, 0, 0, 1], bitvec![1, 0, 0, 1])] #[case(bitvec![1, 0, 1, 0], bitvec![0, 1, 0, 1], bitvec![0, 0, 0, 0])] #[case(bitvec![1, 1, 0, 0], bitvec![1, 0, 1, 0], bitvec![1, 0, 0, 0])] fn and_operations(#[case] board1: BitVec, #[case] board2: BitVec, #[case] expected: BitVec) {
316 let bb1 = BitBoardDyn {
317 board: board1,
318 n_rows: 2,
319 n_cols: 2,
320 };
321 let bb2 = BitBoardDyn {
322 board: board2,
323 n_rows: 2,
324 n_cols: 2,
325 };
326
327 let result = bb1.and(&bb2).unwrap();
328 assert_eq!(result.board().to_bitvec(), expected);
329 assert_eq!(result.n_rows(), 2);
330 assert_eq!(result.n_cols(), 2);
331 }
332
333 #[rstest]
334 #[case(bitvec![0, 0, 0, 0], bitvec![0, 0, 0, 0], bitvec![0, 0, 0, 0])] #[case(bitvec![1, 1, 1, 1], bitvec![1, 1, 1, 1], bitvec![1, 1, 1, 1])] #[case(bitvec![0, 0, 0, 0], bitvec![1, 1, 1, 1], bitvec![1, 1, 1, 1])] #[case(bitvec![0, 0, 0, 0], bitvec![1, 0, 0, 1], bitvec![1, 0, 0, 1])] #[case(bitvec![1, 0, 1, 0], bitvec![0, 1, 0, 1], bitvec![1, 1, 1, 1])] #[case(bitvec![1, 1, 0, 0], bitvec![0, 0, 1, 1], bitvec![1, 1, 1, 1])] #[case(bitvec![1, 0, 0, 1], bitvec![0, 1, 1, 0], bitvec![1, 1, 1, 1])] fn or_operations(#[case] board1: BitVec, #[case] board2: BitVec, #[case] expected: BitVec) {
342 let bb1 = BitBoardDyn {
343 board: board1,
344 n_rows: 2,
345 n_cols: 2,
346 };
347 let bb2 = BitBoardDyn {
348 board: board2,
349 n_rows: 2,
350 n_cols: 2,
351 };
352
353 let result = bb1.or(&bb2).unwrap();
354 assert_eq!(result.board().to_bitvec(), expected);
355 assert_eq!(result.n_rows(), 2);
356 assert_eq!(result.n_cols(), 2);
357 }
358
359 #[test]
360 fn and_or_larger_boards() {
361 let mut bb1 = BitBoardDyn::new(3, 3);
362 bb1.set_row(0, true); bb1.set(2, 2, true); let mut bb2 = BitBoardDyn::new(3, 3);
366 bb2.set_col(0, true); bb2.set(1, 1, true); let and_result = bb1.and(&bb2).unwrap();
371 assert!(and_result.board()[0]); assert!(!and_result.board()[1]); assert!(!and_result.board()[2]); assert!(!and_result.board()[3]); assert!(!and_result.board()[4]); assert!(!and_result.board()[6]); let or_result = bb1.or(&bb2).unwrap();
380 assert!(or_result.board()[0]); assert!(or_result.board()[1]); assert!(or_result.board()[2]); assert!(or_result.board()[3]); assert!(or_result.board()[4]); assert!(!or_result.board()[5]); assert!(or_result.board()[6]); assert!(!or_result.board()[7]); assert!(or_result.board()[8]); }
390
391 #[test]
392 fn and_or_preserve_original_boards() {
393 let mut bb1 = BitBoardDyn::new(2, 2);
394 bb1.set(0, 0, true);
395 let bb1_original = bb1.clone();
396
397 let mut bb2 = BitBoardDyn::new(2, 2);
398 bb2.set(1, 1, true);
399 let bb2_original = bb2.clone();
400
401 let _and_result = bb1.and(&bb2).unwrap();
403 let _or_result = bb1.or(&bb2).unwrap();
404
405 assert_eq!(bb1, bb1_original);
407 assert_eq!(bb2, bb2_original);
408 }
409}