monster_chess/bitboard/
util.rs1#[derive(Debug, Clone, Copy, PartialEq, Eq, Ord)]
7pub struct BitBoard<const T: usize> {
8 pub bits: [u128; T],
9}
10
11impl<const T: usize> BitBoard<T> {
12 pub fn from_data(data: [u128; T]) -> BitBoard<T> {
14 BitBoard { bits: data }
15 }
16
17 pub fn from_element(el: u128) -> BitBoard<T> {
19 let mut arr = [0; T];
20 arr[T - 1] = el;
21 BitBoard { bits: arr }
22 }
23
24 pub fn from_lsb(bit: u16) -> BitBoard<T> {
26 BitBoard::<T>::from_element(1) << bit
27 }
28
29 pub fn from_msb(bit: u16) -> BitBoard<T> {
31 !(BitBoard::<T>::max() >> 1) >> bit
32 }
33
34 pub fn starting_at_lsb(bit: u16, length: u16) -> BitBoard<T> {
36 (BitBoard::<T>::from_lsb(length) - BitBoard::<T>::from_element(1)) << bit
37 }
38
39 pub fn has_bit(self, bit: u16) -> bool {
41 (self & (BitBoard::<T>::from_element(1) << bit)).is_set()
42 }
43
44 pub fn is_empty(&self) -> bool {
46 if T == 1 {
47 return self.bits[0] == 0;
48 }
49
50 self.bits.iter().all(|el| *el == 0)
51 }
52
53 pub fn is_set(&self) -> bool {
55 if T == 1 {
56 return self.bits[0] != 0;
57 }
58
59 self.bits.iter().any(|el| *el != 0)
60 }
61
62 pub fn max() -> BitBoard<T> {
64 BitBoard::<T>::from_data([u128::MAX; T])
65 }
66
67 pub fn new() -> BitBoard<T> {
69 BitBoard::<T>::from_data([0; T])
70 }
71
72 #[inline(always)]
76 pub fn apply(self, rhs: BitBoard<T>, apply: impl Fn((&u128, u128)) -> u128) -> Self {
77 if T == 1 {
78 return BitBoard {
79 bits: [apply((&self.bits[0], rhs.bits[0])); T],
80 };
81 }
82
83 BitBoard {
84 bits: self
85 .bits
86 .iter()
87 .zip(rhs.bits)
88 .map(apply)
89 .collect::<Vec<_>>()
90 .try_into()
91 .expect(&format!("Could not convert BitBoard data vector into an array when applying operation with `apply`."))
92 }
93 }
94
95 #[inline(always)]
99 pub fn effect(&mut self, rhs: BitBoard<T>, apply: impl Fn((&u128, u128)) -> u128) {
100 if T == 1 {
101 self.bits = [apply((&self.bits[0], rhs.bits[0])); T];
102 return;
103 }
104
105 self.bits = self
106 .bits
107 .iter()
108 .zip(rhs.bits)
109 .map(apply)
110 .collect::<Vec<_>>()
111 .try_into()
112 .expect(&format!("Could not convert BitBoard data vector into an array when applying operation with `effect`."));
113 }
114
115 pub fn count_zeros(&self) -> u32 {
117 if T == 1 {
118 self.bits[0].count_zeros()
119 } else {
120 self.bits.iter().map(|el| el.count_zeros()).sum()
121 }
122 }
123
124 pub fn count_ones(&self) -> u32 {
126 if T == 1 {
127 self.bits[0].count_ones()
128 } else {
129 self.bits.iter().map(|el| el.count_ones()).sum()
130 }
131 }
132
133 pub fn get_bits(&self) -> Vec<u128> {
136 let mut bits: Vec<u128> = Vec::with_capacity(128 * T);
137 for container in self.bits.iter().rev() {
138 for i in 0..128 {
139 bits.push((container >> i) & 1); }
141 }
142 bits
143 }
144
145 pub fn iter_set_bits(self, end: u16) -> BitIterator<T> {
147 BitIterator(self, end)
148 }
149
150 pub fn display(&self, rows: usize, cols: usize) -> String {
153 let mut chunks = Vec::<String>::with_capacity(rows);
154 for (ind, row) in self.get_bits().chunks(cols).enumerate() {
155 if ind == rows {
156 break;
157 }
158
159 let chunk = row
160 .iter()
161 .map(|i| if i == &0 { "⬛" } else { "⬜" })
162 .collect::<Vec<_>>()
163 .join("");
164 chunks.push(chunk);
165 }
166
167 chunks.join("\n")
168 }
169}
170
171pub struct BitIterator<const T: usize>(pub BitBoard<T>, u16);
173
174impl<const T: usize> Iterator for BitIterator<T> {
175 type Item = u16;
176
177 fn next(&mut self) -> Option<Self::Item> {
178 if self.0.is_set() {
179 let bit = self.0.bitscan_forward();
180 if bit >= self.1 {
181 return None;
182 }
183 self.0 &= self.0 - BitBoard::from_element(1);
184 Some(bit)
185 } else {
186 None
187 }
188 }
189}