diff --git a/src/board.rs b/src/board.rs index 675f1f0..ecbd2fd 100644 --- a/src/board.rs +++ b/src/board.rs @@ -15,8 +15,10 @@ pub const BOARD_SIZE: usize = 8; #[allow(dead_code)] pub const BOARD_AREA: usize = BOARD_SIZE * BOARD_SIZE; +const BOARD_SIZE_N1: usize = BOARD_SIZE - 1; + /// 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....) type ChainCollection = ArrayVec; @@ -24,58 +26,64 @@ type ChainCollection = ArrayVec; /// Map of all points on the board against some type T /// Used to index like so: example[i][j] /// with each coordinate -type PosMap = ArrayVec, BOARD_SIZE>; +struct PosMap(ArrayVec); + +impl PosMap { + 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 fn gen_adj_lookup() -> PosMap { - (0..BOARD_SIZE) - .map(|i| { - (0..BOARD_SIZE) - .map(|j| { - let (i_chain, j_chain) = ( - split_from(0..=BOARD_SIZE - 1, i), - split_from(0..=BOARD_SIZE - 1, j), - ); + PosMap( + Board::all_positions() + .map(|(i, j)| { + let (i_chain, j_chain) = ( + split_from(0..=BOARD_SIZE - 1, i), + split_from(0..=BOARD_SIZE - 1, j), + ); - let mut chains: ChainCollection = ArrayVec::new_const(); + let mut chains: ChainCollection = ArrayVec::new_const(); - chains.extend( - i_chain - .clone() - .map(|range| range.map(move |i| (i, j))) - .map(Iterator::collect), - ); - chains.extend( - j_chain - .clone() - .map(|range| range.map(move |j| (i, j))) - .map(Iterator::collect), - ); + chains.extend( + i_chain + .clone() + .map(|range| range.map(move |i| (i, j))) + .map(Iterator::collect), + ); - // handle diagonals - chains.extend(diag_raw(i_chain, j_chain).map(Iterator::collect)); + chains.extend( + 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 - assert!( - 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" - ); + // handle diagonals + chains.extend(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 - }) - .collect() - }) - .collect() + .iter() + .flatten() + .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" + ); + + chains + }) + .collect(), + ) } #[derive(PartialEq, Eq, Copy, Clone, Debug)] @@ -87,7 +95,7 @@ pub enum Winner { lazy_static! { /// Precompute all possible chains for each position on the board - pub static ref ADJ_LOOKUP: PosMap = gen_adj_lookup(); + static ref ADJ_LOOKUP: PosMap = gen_adj_lookup(); } /// Repersents a Othello game board at a certain space @@ -254,8 +262,7 @@ impl Board { return Err("position is occupied"); } self.place_unchecked(i, j, piece); - let captured = self.propegate_from(i, j); - if captured > 0 { + if self.propegate_from(i, j) > 0 { Ok(()) } else { self.delete(i, j); @@ -273,6 +280,7 @@ impl Board { let iterator = unsafe { // SAFETY! `propegate_from_dry` should not have overlapping chains // 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) }; @@ -294,7 +302,8 @@ impl Board { j: usize, starting_color: Piece, ) -> impl Iterator + use<'_> { - ADJ_LOOKUP[i][j] + ADJ_LOOKUP + .get(i, j) .iter() .filter_map(move |chain| { let mut end_idx = None;