board backing referencing improvements
This commit is contained in:
parent
54f7b8e472
commit
69dc686d0a
@ -5,7 +5,6 @@ use super::{
|
|||||||
};
|
};
|
||||||
use static_assertions::const_assert;
|
use static_assertions::const_assert;
|
||||||
|
|
||||||
#[cfg(not(feature = "bitvec"))]
|
|
||||||
pub type BitBoardInner = u64;
|
pub type BitBoardInner = u64;
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||||
@ -42,6 +41,10 @@ impl BitBoard {
|
|||||||
self.0.count_ones() as usize
|
self.0.count_ones() as usize
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const fn is_empty(&self) -> bool {
|
||||||
|
self.0 == 0
|
||||||
|
}
|
||||||
|
|
||||||
// Directional shifts with edge masking (prevents wrapping)
|
// Directional shifts with edge masking (prevents wrapping)
|
||||||
pub const fn east(&self) -> Self {
|
pub const fn east(&self) -> Self {
|
||||||
let mask = !Self::col_mask(Board::BOARD_SIZE - 1).0; // Mask to block column 7 bits
|
let mask = !Self::col_mask(Board::BOARD_SIZE - 1).0; // Mask to block column 7 bits
|
||||||
|
|||||||
@ -46,6 +46,40 @@ pub enum Winner {
|
|||||||
None,
|
None,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
macro_rules! get_board {
|
||||||
|
// Immutable static access
|
||||||
|
($self:expr, Piece::White) => {
|
||||||
|
$self.white_board
|
||||||
|
};
|
||||||
|
($self:expr, Piece::Black) => {
|
||||||
|
$self.black_board
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mutable static access
|
||||||
|
(mut $self:expr, Piece::White) => {
|
||||||
|
$self.white_board
|
||||||
|
};
|
||||||
|
(mut $self:expr, Piece::Black) => {
|
||||||
|
$self.black_board
|
||||||
|
};
|
||||||
|
|
||||||
|
// Immutable dynamic access
|
||||||
|
($self:expr, $piece:expr) => {{
|
||||||
|
match $piece {
|
||||||
|
Piece::White => &$self.white_board,
|
||||||
|
Piece::Black => &$self.black_board,
|
||||||
|
}
|
||||||
|
}};
|
||||||
|
|
||||||
|
// Mutable dynamic access
|
||||||
|
(mut $self:expr, $piece:expr) => {{
|
||||||
|
match $piece {
|
||||||
|
Piece::White => &mut $self.white_board,
|
||||||
|
Piece::Black => &mut $self.black_board,
|
||||||
|
}
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
/// Repersents a Othello game board at a certain space
|
/// Repersents a Othello game board at a certain space
|
||||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||||
pub struct Board {
|
pub struct Board {
|
||||||
@ -117,7 +151,7 @@ impl Board {
|
|||||||
pub const BOARD_SIZE: CoordAxis = 8;
|
pub const BOARD_SIZE: CoordAxis = 8;
|
||||||
|
|
||||||
/// Area of the board
|
/// Area of the board
|
||||||
pub const BOARD_AREA: CoordPair = CoordPair(CoordPair(Self::BOARD_SIZE).0.pow(2));
|
pub const BOARD_AREA: CoordPair = CoordPair::area(Self::BOARD_SIZE);
|
||||||
|
|
||||||
/// Create a new empty board
|
/// Create a new empty board
|
||||||
#[allow(clippy::new_without_default)]
|
#[allow(clippy::new_without_default)]
|
||||||
@ -164,24 +198,8 @@ impl Board {
|
|||||||
Self::all_positions().filter(move |&coord| self.would_prop(coord, color))
|
Self::all_positions().filter(move |&coord| self.would_prop(coord, color))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a reference to a backing [`BitBoard`]
|
|
||||||
const fn board(&self, color: Piece) -> &BitBoard {
|
|
||||||
match color {
|
|
||||||
Piece::Black => &self.black_board,
|
|
||||||
Piece::White => &self.white_board,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get a mutable reference to a backing [`BitBoard`]
|
|
||||||
const fn board_mut(&mut self, color: Piece) -> &mut BitBoard {
|
|
||||||
match color {
|
|
||||||
Piece::Black => &mut self.black_board,
|
|
||||||
Piece::White => &mut self.white_board,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const fn get_piece(&self, coord: CoordPair, color: Piece) -> bool {
|
pub const fn get_piece(&self, coord: CoordPair, color: Piece) -> bool {
|
||||||
self.board(color).get(coord)
|
get_board!(self, color).get(coord)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the color of a place on the [`Board`] at a position
|
/// Returns the color of a place on the [`Board`] at a position
|
||||||
@ -198,13 +216,14 @@ impl Board {
|
|||||||
/// Place a piece without checking for propegation of validity
|
/// Place a piece without checking for propegation of validity
|
||||||
/// only pub for setting up benchmark
|
/// only pub for setting up benchmark
|
||||||
pub const fn place_unchecked(&mut self, coord: CoordPair, piece: Piece) {
|
pub const fn place_unchecked(&mut self, coord: CoordPair, piece: Piece) {
|
||||||
self.board_mut(piece).set(coord, true);
|
let is_white = matches!(piece, Piece::White);
|
||||||
self.board_mut(piece.flip()).set(coord, false);
|
get_board!(self, Piece::White).set(coord, is_white);
|
||||||
|
get_board!(self, Piece::Black).set(coord, !is_white);
|
||||||
}
|
}
|
||||||
|
|
||||||
const fn delete(&mut self, coord: CoordPair) {
|
const fn delete(&mut self, coord: CoordPair) {
|
||||||
self.board_mut(Piece::White).set(coord, false);
|
get_board!(self, Piece::White).set(coord, false);
|
||||||
self.board_mut(Piece::Black).set(coord, false);
|
get_board!(self, Piece::Black).set(coord, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return a modified [`Board`] with the piece placed at a position
|
/// Return a modified [`Board`] with the piece placed at a position
|
||||||
@ -221,7 +240,7 @@ impl Board {
|
|||||||
|
|
||||||
/// Returns a bool which represents whether or not a move would propegate and be valid
|
/// 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 fn would_prop(&self, coord: CoordPair, piece: Piece) -> bool {
|
||||||
self.get(coord).is_none() && self.propegate_from_dry(coord, piece).count() > 0
|
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 fn place(&mut self, coord: CoordPair, piece: Piece) -> Result<(), &'static str> {
|
||||||
@ -230,7 +249,7 @@ impl Board {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.place_unchecked(coord, piece);
|
self.place_unchecked(coord, piece);
|
||||||
if self.propegate_from(coord) == 0 {
|
if !self.propegate_from(coord) {
|
||||||
self.delete(coord);
|
self.delete(coord);
|
||||||
Err("move would not propegate")
|
Err("move would not propegate")
|
||||||
} else {
|
} else {
|
||||||
@ -239,31 +258,32 @@ impl Board {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Propegate the board and captures starting from a specific position
|
/// Propegate the board and captures starting from a specific position
|
||||||
fn propegate_from(&mut self, coord: CoordPair) -> usize {
|
/// returns true if flips occurred
|
||||||
|
fn propegate_from(&mut self, coord: CoordPair) -> bool {
|
||||||
let Some(starting_color) = self.get(coord) else {
|
let Some(starting_color) = self.get(coord) else {
|
||||||
return 0;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
let flip_mask = self.propegate_from_dry(coord, starting_color);
|
let flip_mask = self.propegate_from_dry(coord, starting_color);
|
||||||
let count = flip_mask.count();
|
let did_flip = !flip_mask.is_empty();
|
||||||
|
|
||||||
// Apply the flips
|
// Apply the flips
|
||||||
self.apply_flip_mask(starting_color, flip_mask);
|
self.apply_flip_mask(starting_color, flip_mask);
|
||||||
|
|
||||||
count
|
did_flip
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_flip_mask(&mut self, color: Piece, flip_mask: BitBoard) {
|
fn apply_flip_mask(&mut self, color: Piece, flip_mask: BitBoard) {
|
||||||
*self.board_mut(color) |= flip_mask;
|
*get_board!(mut self, color) |= flip_mask;
|
||||||
*self.board_mut(color.flip()) &= !flip_mask;
|
*get_board!(mut self, color.flip()) &= !flip_mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Propegate piece captures originating from (i, j)
|
/// Propegate piece captures originating from (i, j)
|
||||||
/// DO NOT USE THIS ALONE, this should be called as a part of
|
/// DO NOT USE THIS ALONE, this should be called as a part of
|
||||||
/// [`Board::place`] or [`Board::place_and_prop_unchecked`]
|
/// [`Board::place`] or [`Board::place_and_prop_unchecked`]
|
||||||
fn propegate_from_dry(&self, coords: CoordPair, starting_color: Piece) -> BitBoard {
|
fn propegate_from_dry(&self, coords: CoordPair, starting_color: Piece) -> BitBoard {
|
||||||
let player_board = *self.board(starting_color);
|
let player_board = get_board!(self, starting_color);
|
||||||
let opponent_board = *self.board(starting_color.flip());
|
let opponent_board = get_board!(self, starting_color.flip());
|
||||||
|
|
||||||
let mut flip_mask = BitBoard::new();
|
let mut flip_mask = BitBoard::new();
|
||||||
let seed = BitBoard::from_coord(coords);
|
let seed = BitBoard::from_coord(coords);
|
||||||
@ -275,14 +295,14 @@ impl Board {
|
|||||||
// Expand in direction until edge or non-opponent piece
|
// Expand in direction until edge or non-opponent piece
|
||||||
loop {
|
loop {
|
||||||
current = dir(¤t);
|
current = dir(¤t);
|
||||||
if current.count() == 0 || !current.intersects(opponent_board) {
|
if current.is_empty() || !current.intersects(*opponent_board) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
temp_flips |= current;
|
temp_flips |= current;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If terminated on a player piece, keep the flips
|
// If terminated on a player piece, keep the flips
|
||||||
if current.intersects(player_board) {
|
if current.intersects(*player_board) {
|
||||||
flip_mask |= temp_flips;
|
flip_mask |= temp_flips;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -292,7 +312,7 @@ impl Board {
|
|||||||
|
|
||||||
/// Count the number of a type of [`Piece`] on the board
|
/// Count the number of a type of [`Piece`] on the board
|
||||||
pub const fn count(&self, piece: Piece) -> usize {
|
pub const fn count(&self, piece: Piece) -> usize {
|
||||||
self.board(piece).count()
|
get_board!(self, piece).count()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the "net score" of a player
|
/// Get the "net score" of a player
|
||||||
|
|||||||
@ -20,9 +20,13 @@ impl CoordPair {
|
|||||||
Self(row * Board::BOARD_SIZE + col)
|
Self(row * Board::BOARD_SIZE + col)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_index(&self) -> (CoordAxis, CoordAxis) {
|
fn into_indexes(&self) -> (CoordAxis, CoordAxis) {
|
||||||
self.0.div_mod_floor(&Board::BOARD_SIZE)
|
self.0.div_mod_floor(&Board::BOARD_SIZE)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const fn area(pos: CoordAxis) -> Self {
|
||||||
|
Self(pos.pow(2) as CoordPairInner)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Display for CoordPair {
|
impl std::fmt::Display for CoordPair {
|
||||||
@ -40,7 +44,7 @@ impl std::fmt::Debug for CoordPair {
|
|||||||
|
|
||||||
impl From<CoordPair> for (CoordAxis, CoordAxis) {
|
impl From<CoordPair> for (CoordAxis, CoordAxis) {
|
||||||
fn from(val: CoordPair) -> Self {
|
fn from(val: CoordPair) -> Self {
|
||||||
val.from_index()
|
val.into_indexes()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user