board optimizations

This commit is contained in:
2025-03-12 10:28:32 -04:00
parent 7863e0324f
commit 16eb6a1259
2 changed files with 47 additions and 51 deletions

View File

@@ -227,22 +227,26 @@ impl Board {
/// Return a modified [`Board`] with the piece placed at a position
/// Returns None if the move was invalid
pub fn what_if(&self, coord: CoordPair, piece: Piece) -> Result<Self, &'static str> {
pub const fn what_if(&self, coord: CoordPair, piece: Piece) -> Option<Self> {
// extract check here to avoid copy
if self.get(coord).is_some() {
return Err("position is occupied");
return None;
}
let mut self_copy = *self;
self_copy.place(coord, piece).map(|_| self_copy)
if let Ok(_) = self_copy.place(coord, piece) {
Some(self_copy)
} else {
None
}
}
/// Returns a bool which represents whether or not a move would propegate and be valid
pub fn would_prop(&self, coord: CoordPair, piece: Piece) -> bool {
pub const fn would_prop(&self, coord: CoordPair, piece: Piece) -> bool {
self.get(coord).is_none() && !self.propegate_from_dry(coord, piece).is_empty()
}
pub fn place(&mut self, coord: CoordPair, piece: Piece) -> Result<(), &'static str> {
pub const fn place(&mut self, coord: CoordPair, piece: Piece) -> Result<(), &'static str> {
if self.get(coord).is_some() {
return Err("position is occupied");
}
@@ -257,7 +261,7 @@ impl Board {
/// Propegate the board and captures starting from a specific position
/// returns true if flips occurred
fn propegate_from(&mut self, coord: CoordPair, starting_color: Piece) -> bool {
const fn propegate_from(&mut self, coord: CoordPair, starting_color: Piece) -> bool {
let flip_mask = self.propegate_from_dry(coord, starting_color);
let did_flip = !flip_mask.is_empty();
@@ -267,40 +271,52 @@ impl Board {
did_flip
}
fn apply_flip_mask(&mut self, color: Piece, flip_mask: BitBoard) {
const fn apply_flip_mask(&mut self, color: Piece, flip_mask: BitBoard) {
// did some investigation, seems using xor actually decreases
// performance over the branchfull impl? 3.2-3.5% slower
get_board!(mut self, color).bitor_assign(flip_mask);
get_board!(mut self, color.flip()).bitand_assign(!flip_mask);
get_board!(mut self, color.flip()).bitand_assign(flip_mask.not());
}
/// Propegate piece captures originating from (i, j)
/// DO NOT USE THIS ALONE, this should be called as a part of
/// [`Board::place`] or [`Board::place_and_prop_unchecked`]
fn propegate_from_dry(&self, coords: CoordPair, starting_color: Piece) -> BitBoard {
const fn propegate_from_dry(&self, coords: CoordPair, starting_color: Piece) -> BitBoard {
let player_board = get_board!(self, starting_color);
let opponent_board = get_board!(self, starting_color.flip());
let mut flip_mask = BitBoard::new();
let seed = BitBoard::from_coord(coords);
for dir in BitBoard::DIRECTIONS {
let mut current = seed;
let mut temp_flips = BitBoard::new();
macro_rules! apply_dir {
($base:expr, $sum_mask:expr, $dir:expr) => {
let mut current = $base;
let mut temp_flips = BitBoard::new();
// Expand in direction until edge or non-opponent piece
loop {
current = dir(&current, 1);
if current.is_empty() || !current.intersects(*opponent_board) {
break;
// Expand in direction until edge or non-opponent piece
loop {
current = $dir(&current, 1);
if current.is_empty() || !current.intersects(*opponent_board) {
break;
}
temp_flips.bitor_assign(current);
}
temp_flips |= current;
}
// If terminated on a player piece, keep the flips
if current.intersects(*player_board) {
flip_mask |= temp_flips;
}
// If terminated on a player piece, keep the flips
if current.intersects(*player_board) {
$sum_mask.bitor_assign(temp_flips);
}
};
}
apply_dir!(seed, flip_mask, BitBoard::east);
apply_dir!(seed, flip_mask, BitBoard::west);
apply_dir!(seed, flip_mask, BitBoard::north);
apply_dir!(seed, flip_mask, BitBoard::south);
apply_dir!(seed, flip_mask, BitBoard::northeast);
apply_dir!(seed, flip_mask, BitBoard::northwest);
apply_dir!(seed, flip_mask, BitBoard::southeast);
apply_dir!(seed, flip_mask, BitBoard::southwest);
flip_mask
}