PosMap cleanup
This commit is contained in:
parent
8c5fea8359
commit
c2120dfcc4
105
src/board.rs
105
src/board.rs
@ -15,8 +15,10 @@ pub const BOARD_SIZE: usize = 8;
|
|||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub const BOARD_AREA: usize = BOARD_SIZE * BOARD_SIZE;
|
pub const BOARD_AREA: usize = BOARD_SIZE * BOARD_SIZE;
|
||||||
|
|
||||||
|
const BOARD_SIZE_N1: usize = BOARD_SIZE - 1;
|
||||||
|
|
||||||
/// A chain of positions across the board
|
/// A chain of positions across the board
|
||||||
type Chain = ArrayVec<(usize, usize), BOARD_SIZE>;
|
type Chain = ArrayVec<(usize, usize), BOARD_SIZE_N1>;
|
||||||
|
|
||||||
/// A collection of chains (up vert, down vert, left horiz, right horiz, diagonals....)
|
/// A collection of chains (up vert, down vert, left horiz, right horiz, diagonals....)
|
||||||
type ChainCollection = ArrayVec<Chain, 8>;
|
type ChainCollection = ArrayVec<Chain, 8>;
|
||||||
@ -24,58 +26,64 @@ type ChainCollection = ArrayVec<Chain, 8>;
|
|||||||
/// Map of all points on the board against some type T
|
/// Map of all points on the board against some type T
|
||||||
/// Used to index like so: example[i][j]
|
/// Used to index like so: example[i][j]
|
||||||
/// with each coordinate
|
/// with each coordinate
|
||||||
type PosMap<T> = ArrayVec<ArrayVec<T, BOARD_SIZE>, BOARD_SIZE>;
|
struct PosMap<T>(ArrayVec<T, BOARD_AREA>);
|
||||||
|
|
||||||
|
impl<T> PosMap<T> {
|
||||||
|
pub fn get(&self, row: usize, col: usize) -> &T {
|
||||||
|
&self.0[row * BOARD_SIZE + col]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Creates a lookup map for adjacencies and chains from each position on the board
|
/// Creates a lookup map for adjacencies and chains from each position on the board
|
||||||
fn gen_adj_lookup() -> PosMap<ChainCollection> {
|
fn gen_adj_lookup() -> PosMap<ChainCollection> {
|
||||||
(0..BOARD_SIZE)
|
PosMap(
|
||||||
.map(|i| {
|
Board::all_positions()
|
||||||
(0..BOARD_SIZE)
|
.map(|(i, j)| {
|
||||||
.map(|j| {
|
let (i_chain, j_chain) = (
|
||||||
let (i_chain, j_chain) = (
|
split_from(0..=BOARD_SIZE - 1, i),
|
||||||
split_from(0..=BOARD_SIZE - 1, i),
|
split_from(0..=BOARD_SIZE - 1, j),
|
||||||
split_from(0..=BOARD_SIZE - 1, j),
|
);
|
||||||
);
|
|
||||||
|
|
||||||
let mut chains: ChainCollection = ArrayVec::new_const();
|
let mut chains: ChainCollection = ArrayVec::new_const();
|
||||||
|
|
||||||
chains.extend(
|
chains.extend(
|
||||||
i_chain
|
i_chain
|
||||||
.clone()
|
.clone()
|
||||||
.map(|range| range.map(move |i| (i, j)))
|
.map(|range| range.map(move |i| (i, j)))
|
||||||
.map(Iterator::collect),
|
.map(Iterator::collect),
|
||||||
);
|
);
|
||||||
chains.extend(
|
|
||||||
j_chain
|
|
||||||
.clone()
|
|
||||||
.map(|range| range.map(move |j| (i, j)))
|
|
||||||
.map(Iterator::collect),
|
|
||||||
);
|
|
||||||
|
|
||||||
// handle diagonals
|
chains.extend(
|
||||||
chains.extend(diag_raw(i_chain, j_chain).map(Iterator::collect));
|
j_chain
|
||||||
|
.clone()
|
||||||
|
.map(|range| range.map(move |j| (i, j)))
|
||||||
|
.map(Iterator::collect),
|
||||||
|
);
|
||||||
|
|
||||||
// make sure all chains are in the proper range so we can ignore bounds checking later
|
// handle diagonals
|
||||||
assert!(
|
chains.extend(diag_raw(i_chain, j_chain).map(Iterator::collect));
|
||||||
chains.iter().all(|x| x.iter().all(
|
|
||||||
|(i, j)| (0..BOARD_SIZE).contains(i) && (0..BOARD_SIZE).contains(j)
|
|
||||||
)),
|
|
||||||
"chains go out-of-bounds"
|
|
||||||
);
|
|
||||||
|
|
||||||
// ensure all nodes in all chains are unique across chains, ensures beavior in
|
|
||||||
// [`Board::propegate_from`]
|
|
||||||
let mut uniq = HashSet::new();
|
|
||||||
assert!(
|
|
||||||
chains.iter().flatten().all(move |x| uniq.insert(x)),
|
|
||||||
"there are duplicate nodes in chain"
|
|
||||||
);
|
|
||||||
|
|
||||||
|
// make sure all chains are in the proper range so we can ignore bounds checking later
|
||||||
|
assert!(
|
||||||
chains
|
chains
|
||||||
})
|
.iter()
|
||||||
.collect()
|
.flatten()
|
||||||
})
|
.all(|(i, j)| (0..BOARD_SIZE).contains(i) && (0..BOARD_SIZE).contains(j)),
|
||||||
.collect()
|
"chains go out-of-bounds"
|
||||||
|
);
|
||||||
|
|
||||||
|
// ensure all nodes in all chains are unique across chains, ensures beavior in
|
||||||
|
// [`Board::propegate_from`]
|
||||||
|
let mut uniq = HashSet::new();
|
||||||
|
assert!(
|
||||||
|
chains.iter().flatten().all(move |x| uniq.insert(x)),
|
||||||
|
"there are duplicate nodes in chain"
|
||||||
|
);
|
||||||
|
|
||||||
|
chains
|
||||||
|
})
|
||||||
|
.collect(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
|
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
|
||||||
@ -87,7 +95,7 @@ pub enum Winner {
|
|||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
/// Precompute all possible chains for each position on the board
|
/// Precompute all possible chains for each position on the board
|
||||||
pub static ref ADJ_LOOKUP: PosMap<ChainCollection> = gen_adj_lookup();
|
static ref ADJ_LOOKUP: PosMap<ChainCollection> = gen_adj_lookup();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Repersents a Othello game board at a certain space
|
/// Repersents a Othello game board at a certain space
|
||||||
@ -254,8 +262,7 @@ impl Board {
|
|||||||
return Err("position is occupied");
|
return Err("position is occupied");
|
||||||
}
|
}
|
||||||
self.place_unchecked(i, j, piece);
|
self.place_unchecked(i, j, piece);
|
||||||
let captured = self.propegate_from(i, j);
|
if self.propegate_from(i, j) > 0 {
|
||||||
if captured > 0 {
|
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
self.delete(i, j);
|
self.delete(i, j);
|
||||||
@ -273,6 +280,7 @@ impl Board {
|
|||||||
let iterator = unsafe {
|
let iterator = unsafe {
|
||||||
// SAFETY! `propegate_from_dry` should not have overlapping chains
|
// SAFETY! `propegate_from_dry` should not have overlapping chains
|
||||||
// if overlapping chains were to exist, `self.place_unchecked` could collide with `self.get`
|
// if overlapping chains were to exist, `self.place_unchecked` could collide with `self.get`
|
||||||
|
// I now have a check in `ADJ_LOOKUP` on creation
|
||||||
(*(self as *const Self)).propegate_from_dry(i, j, starting_color)
|
(*(self as *const Self)).propegate_from_dry(i, j, starting_color)
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -294,7 +302,8 @@ impl Board {
|
|||||||
j: usize,
|
j: usize,
|
||||||
starting_color: Piece,
|
starting_color: Piece,
|
||||||
) -> impl Iterator<Item = &(usize, usize)> + use<'_> {
|
) -> impl Iterator<Item = &(usize, usize)> + use<'_> {
|
||||||
ADJ_LOOKUP[i][j]
|
ADJ_LOOKUP
|
||||||
|
.get(i, j)
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(move |chain| {
|
.filter_map(move |chain| {
|
||||||
let mut end_idx = None;
|
let mut end_idx = None;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user