use super::{ misc::{diag_raw, split_from}, Board, CoordPair, }; use arrayvec::ArrayVec; use std::collections::HashSet; /// A chain of positions across the board type Chain = ArrayVec; /// A collection of chains (up vert, down vert, left horiz, right horiz, diagonals....) pub type ChainCollection = ArrayVec; /// Creates a lookup map for adjacencies and chains from each position on the board pub fn gen_adj_lookup() -> PosMap { PosMap( Board::all_positions() .map(|coord| { let (i, j) = coord.into(); 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)) .filter(|x: &Vec<(u8, u8)>| !x.is_empty()) // PERF! filter out empty chains +~5% perf boost (in [`Board::place`]) .map(|x: Vec<(u8, u8)>| x.into_iter().map(|x| x.into()).collect()), ); // make sure all chains are in the proper range so we can ignore bounds checking later assert!( chains .iter() .flatten() .map(|&x| x.into()) .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(), ) }