refactor chains file

This commit is contained in:
Simon Gardling 2025-02-22 19:48:47 -05:00
parent c8ac4ce84b
commit 52cf81ec58
Signed by: titaniumtown
GPG Key ID: 9AB28AC10ECE533D
3 changed files with 104 additions and 98 deletions

View File

@ -1,106 +1,11 @@
use super::{
bitboard::BitBoard,
misc::get_index,
misc::{diag_raw, split_from},
chains::{gen_adj_lookup, ChainCollection, PosMap},
piece::Piece,
};
use arrayvec::ArrayVec;
use const_fn::const_fn;
use lazy_static::lazy_static;
use std::{cmp::Ordering, collections::HashSet, fmt};
/// A chain of positions across the board
type Chain = ArrayVec<(usize, usize), { Board::BOARD_SIZE - 1 }>;
/// A collection of chains (up vert, down vert, left horiz, right horiz, diagonals....)
type ChainCollection = ArrayVec<Chain, 8>;
/// Map of all points on the board against some type T
/// Used to index like so: example[i][j]
/// with each coordinate
pub struct PosMap<T: Default>(ArrayVec<T, { Board::BOARD_AREA }>);
impl<T: Default> PosMap<T> {
#[allow(clippy::new_without_default)]
pub fn new() -> Self {
Self(ArrayVec::from_iter(
(0..Board::BOARD_AREA).map(|_| Default::default()),
))
}
pub fn get(&self, row: usize, col: usize) -> &T {
let index = get_index(row, col);
debug_assert!(
Board::BOARD_AREA + 1 >= index,
"index out of range, was: {}",
index
);
unsafe { self.0.get_unchecked(index) }
}
pub fn set(&mut self, row: usize, col: usize, value: T) {
let index = get_index(row, col);
debug_assert!(
Board::BOARD_AREA + 1 >= index,
"index out of range, was: {}",
index
);
self.0[index] = value;
}
}
/// Creates a lookup map for adjacencies and chains from each position on the board
fn gen_adj_lookup() -> PosMap<ChainCollection> {
PosMap(
Board::all_positions()
.map(|(i, j)| {
let (i_chain, j_chain) = (
split_from(0..=Board::BOARD_SIZE - 1, i),
split_from(0..=Board::BOARD_SIZE - 1, j),
);
let chains: ChainCollection = ArrayVec::from_iter(
i_chain
.clone()
.into_iter()
.map(|range| range.map(move |i| (i, j)))
.map(Iterator::collect)
.chain(
j_chain
.clone()
.into_iter()
.map(|range| range.map(move |j| (i, j)))
.map(Iterator::collect),
)
.chain(diag_raw(i_chain, j_chain).map(Iterator::collect)),
);
// make sure all chains are in the proper range so we can ignore bounds checking later
assert!(
chains
.iter()
.flatten()
.flat_map(|(i, j)| [i, j]) // flatten to just numbers
.all(|x| (0..Board::BOARD_SIZE).contains(x)),
"chains go out-of-bounds"
);
// SAFETY! 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(),
)
}
use std::{cmp::Ordering, fmt};
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
pub enum Winner {

99
src/repr/chains.rs Normal file
View File

@ -0,0 +1,99 @@
use super::{
misc::{diag_raw, get_index, split_from},
Board,
};
use arrayvec::ArrayVec;
use std::collections::HashSet;
/// A chain of positions across the board
type Chain = ArrayVec<(usize, usize), { Board::BOARD_SIZE - 1 }>;
/// A collection of chains (up vert, down vert, left horiz, right horiz, diagonals....)
pub type ChainCollection = ArrayVec<Chain, 8>;
/// Map of all points on the board against some type T
/// Used to index like so: example[i][j]
/// with each coordinate
pub struct PosMap<T: Default>(ArrayVec<T, { Board::BOARD_AREA }>);
impl<T: Default> PosMap<T> {
#[allow(clippy::new_without_default)]
pub fn new() -> Self {
Self(ArrayVec::from_iter(
(0..Board::BOARD_AREA).map(|_| Default::default()),
))
}
pub fn get(&self, row: usize, col: usize) -> &T {
let index = get_index(row, col);
debug_assert!(
Board::BOARD_AREA + 1 >= index,
"index out of range, was: {}",
index
);
unsafe { self.0.get_unchecked(index) }
}
pub fn set(&mut self, row: usize, col: usize, value: T) {
let index = get_index(row, col);
debug_assert!(
Board::BOARD_AREA + 1 >= index,
"index out of range, was: {}",
index
);
self.0[index] = value;
}
}
/// Creates a lookup map for adjacencies and chains from each position on the board
pub fn gen_adj_lookup() -> PosMap<ChainCollection> {
PosMap(
Board::all_positions()
.map(|(i, j)| {
let (i_chain, j_chain) = (
split_from(0..=Board::BOARD_SIZE - 1, i),
split_from(0..=Board::BOARD_SIZE - 1, j),
);
let chains: ChainCollection = ArrayVec::from_iter(
i_chain
.clone()
.into_iter()
.map(|range| range.map(move |i| (i, j)))
.map(Iterator::collect)
.chain(
j_chain
.clone()
.into_iter()
.map(|range| range.map(move |j| (i, j)))
.map(Iterator::collect),
)
.chain(diag_raw(i_chain, j_chain).map(Iterator::collect)),
);
// make sure all chains are in the proper range so we can ignore bounds checking later
assert!(
chains
.iter()
.flatten()
.flat_map(|(i, j)| [i, j]) // flatten to just numbers
.all(|x| (0..Board::BOARD_SIZE).contains(x)),
"chains go out-of-bounds"
);
// SAFETY! 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(),
)
}

View File

@ -1,7 +1,9 @@
mod bitboard;
mod board;
mod chains;
mod misc;
mod piece;
pub use board::{Board, PosMap, Winner};
pub use board::{Board, Winner};
pub use chains::PosMap;
pub use piece::Piece;