shogiutil/board/
bitboard.rs

1use crate::Square;
2use std::ops::{BitAnd, BitOr, BitXor};
3
4const BIT_BOARD_FULL: u128 =
5    0b_111111111_111111111_111111111_111111111_111111111_111111111_111111111_111111111_111111111;
6
7#[derive(Clone, Copy)]
8pub struct Bitboard(pub u128);
9
10impl BitAnd for Bitboard {
11    type Output = Bitboard;
12
13    fn bitand(self, rhs: Self) -> Self::Output {
14        Self(self.0 & rhs.0)
15    }
16}
17
18impl BitOr for Bitboard {
19    type Output = Bitboard;
20
21    fn bitor(self, rhs: Self) -> Self::Output {
22        Self(self.0 | rhs.0)
23    }
24}
25
26impl BitXor for Bitboard {
27    type Output = Bitboard;
28
29    fn bitxor(self, rhs: Self) -> Self::Output {
30        Self(self.0 ^ rhs.0)
31    }
32}
33
34impl Bitboard {
35    pub const fn empty() -> Self {
36        Self(0)
37    }
38    pub const fn full() -> Self {
39        Self(BIT_BOARD_FULL)
40    }
41
42    pub fn is_filled(&self, sq: &Square) -> bool {
43        let pos = sq_to_pos(sq);
44        self.0 & (1 << pos) != 0
45    }
46    pub fn fill(&mut self, sq: &Square) {
47        let pos = sq_to_pos(sq);
48        assert_eq!(self.0 & (1 << pos), 0);
49        self.0 ^= 1 << pos;
50    }
51    pub fn remove(&mut self, sq: &Square) {
52        let pos = sq_to_pos(sq);
53        assert_ne!(self.0 & (1 << pos), 0);
54        self.0 ^= 1 << pos;
55    }
56
57    pub fn rotate180(&self) -> Self {
58        let reversed = self.0.reverse_bits();
59        Bitboard(reversed >> 47)
60    }
61
62    pub fn iter(&self) -> impl Iterator<Item = u32> {
63        BitIterator(self.0)
64    }
65
66    pub fn file_count_ones(&self, file: u8) -> u32 {
67        let file_only = super::bit_file(file) & self.0;
68        file_only.count_ones()
69    }
70}
71
72struct BitIterator(u128);
73
74impl Iterator for BitIterator {
75    type Item = u32;
76
77    fn next(&mut self) -> Option<Self::Item> {
78        if self.0 == 0 {
79            None
80        } else {
81            let pos = self.0.trailing_zeros();
82            self.0 ^= 1 << pos;
83            Some(pos)
84        }
85    }
86}
87
88fn sq_to_pos(sq: &Square) -> u8 {
89    (sq.rank - 1) * 9 + 9 - sq.file
90}
91
92#[cfg(test)]
93mod tests {
94    use super::*;
95
96    #[test]
97    fn test_rotate180() {
98        let input: u128 =
99            0b_101001000100001000001000000100000001000000001000000000100000000001000000000001000;
100        let expected: u128 =
101            0b_000100000000000100000000001000000000100000000100000001000000100000100001000100101;
102        assert_eq!(expected, Bitboard(input).rotate180().0);
103        assert_eq!(input, Bitboard(input).rotate180().rotate180().0);
104    }
105
106    #[test]
107    fn test_bit_iterator() {
108        let v = Bitboard(0b1000100101).iter().collect::<Vec<_>>();
109        assert_eq!(v, [0, 2, 5, 9]);
110    }
111
112    #[test]
113    fn test_full_bit() {
114        let full = Bitboard::full();
115        assert_eq!(81, full.0.count_ones());
116    }
117}