|
use std::fmt::Write; |
|
|
|
use pyo3::prelude::*; |
|
|
|
#[pyclass] |
|
#[derive(Clone)] |
|
pub struct BitBoard(pub u64, pub u64); |
|
|
|
impl core::fmt::Debug for BitBoard { |
|
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { |
|
f.write_str(&self.to_string(('B', 'W')))?; |
|
Ok(()) |
|
} |
|
} |
|
|
|
#[pymethods] |
|
impl BitBoard { |
|
#[new] |
|
pub fn default() -> Self { |
|
Self(0x0000_0008_1000_0000, 0x0000_0010_0800_0000) |
|
} |
|
|
|
fn __repr__(&self) -> String { |
|
self.to_string(('B', 'W')) |
|
} |
|
|
|
pub fn to_string(&self, players: (char, char)) -> String { |
|
let mut s = String::with_capacity(64 + 8); |
|
for i in (0..64).rev() { |
|
s.write_char(match (self.0 >> i & 1, self.1 >> i & 1) { |
|
(0, 0) => '.', |
|
(1, 0) => players.0, |
|
(0, 1) => players.1, |
|
(_, _) => unreachable!(), |
|
}) |
|
.unwrap(); |
|
if i % 8 == 0 { |
|
s.write_char('\n').unwrap(); |
|
} |
|
} |
|
s |
|
} |
|
|
|
|
|
#[must_use] |
|
pub const fn get(&self) -> [u64; 2] { |
|
[self.0, self.1] |
|
} |
|
|
|
|
|
pub fn pass_move(&self) -> Self { |
|
Self(self.1, self.0) |
|
} |
|
|
|
|
|
|
|
#[must_use] |
|
pub fn make_move(&self, place: usize) -> Option<Self> { |
|
let diff = (0..4) |
|
.map(|i| unsafe { |
|
use crate::consts::*; |
|
use bitintr::*; |
|
|
|
|
|
|
|
|
|
u64::from(*RESULT.get_unchecked( |
|
|
|
INDEX[place][i] as usize * 32 |
|
+ self.0.pext(MASK[place][i][0]) as usize * 64 |
|
+ self.1.pext(MASK[place][i][1]) as usize, |
|
)) |
|
.pdep(MASK[place][i][1]) |
|
}) |
|
.fold(0, core::ops::BitOr::bitor); |
|
|
|
|
|
|
|
|
|
if diff == 0 || ((self.0 | self.1) & 1 << place != 0) { |
|
None |
|
} else { |
|
Some(Self(self.1 ^ diff, self.0 ^ diff ^ 1 << place)) |
|
} |
|
} |
|
|
|
|
|
#[must_use] |
|
pub fn available_moves(&self) -> u64 { |
|
|
|
[-9, -8, -7, -1, 1, 7, 8, 9] |
|
|
|
.iter_mut() |
|
.map(|i| self.gen(*i)) |
|
.fold(0, core::ops::BitOr::bitor) |
|
& !self.0 |
|
& !self.1 |
|
} |
|
|
|
pub fn available_moves_list(&self) -> Vec<usize> { |
|
let mask = self.available_moves(); |
|
(0..64).filter(|i| mask >> i & 1 == 1).collect() |
|
} |
|
|
|
#[must_use] |
|
fn gen(&self, dir: isize) -> u64 { |
|
|
|
fn shift(x: u64, y: isize) -> u64 { |
|
if y > 0 { |
|
x >> y |
|
} else { |
|
x << -y |
|
} |
|
} |
|
let x = self.0; |
|
|
|
let y = self.1 |
|
& match dir.rem_euclid(8) { |
|
0 => !0, |
|
1 | 7 => 0x7E7E_7E7E_7E7E_7E7E, |
|
_ => unreachable!(), |
|
}; |
|
let d = dir; |
|
let x = x | y & shift(x, d); |
|
let y = y & shift(y, d); |
|
let d = d * 2; |
|
let x = x | y & shift(x, d); |
|
let y = y & shift(y, d); |
|
let d = d * 2; |
|
let x = x | y & shift(x, d); |
|
shift(x ^ self.0, dir) |
|
} |
|
|
|
pub fn count(&self) -> (i32, i32) { |
|
(self.0.count_ones() as i32, self.1.count_ones() as i32) |
|
} |
|
} |
|
|
|
#[cfg(test)] |
|
mod tests { |
|
use super::BitBoard; |
|
|
|
#[test] |
|
fn default_test() { |
|
let x = BitBoard::default(); |
|
assert_eq!(x.available_moves(), 0x0000_1020_0408_0000); |
|
|
|
let x = x.make_move(44).unwrap(); |
|
assert_eq!(x.get(), [0x0000_0000_0800_0000, 0x0000_1018_1000_0000]); |
|
assert_eq!(x.count(), (1, 4)); |
|
} |
|
} |
|
|