//! Grid of lines and sands use super::*; use std::{ collections::BTreeMap, borrow::Cow, fmt, }; #[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Default, Copy)] #[repr(u8)] pub enum Cell { #[default] Air = b'.', Wall = b'#', Settled = b'O', Falling = b'~', Source = b'+', } impl From for u8 { #[inline(always)] fn from(from: Cell) -> Self { from as u8 } } impl fmt::Display for Cell { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", u8::from(*self) as char) } } #[derive(Debug, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct Grid { map: BTreeMap, } impl Grid { #[inline] pub const fn new() -> Self { Self { map: BTreeMap::new(), } } #[inline(always)] pub fn insert_single(&mut self, point: Point, cell: Cell) -> Option { self.map.insert(point, cell) } #[inline] pub fn draw_line_with(&mut self, line: Line, mut with: F) where F: for<'a> FnMut(&'a Point) -> Cell { for point in line.unroll() { let cell = with(&point); self.map.insert(point, cell); } } #[inline] pub fn draw_line(&mut self, line: Line, cell: Cell) { self.draw_line_with(line, move |_| cell) } #[inline] pub fn draw_lines_with(&mut self, line: I, mut with: F) where F: for<'a> FnMut(&'a Point) -> Cell, I: IntoIterator { for point in line.into_iter().map(|x| x.normalised().unroll()).flatten() { let cell = with(&point); self.map.insert(point, cell); } } /// Draw these lines with this cell #[inline] pub fn draw_lines(&mut self, lines: impl IntoIterator, cell: Cell) { self.draw_lines_with(lines, move |_| cell) } /// Add the source to the grid #[inline(always)] pub fn draw_source(&mut self, source: Point) { self.map.insert(source, Cell::Source); } } /// Create a new sparse grid, returns the point. /// /// A sparse grid does not draw air, only the specified `walls`. #[inline] pub fn sparse_grid(walls: Lines) -> (grid::Grid, Point) { let mut grid = grid::Grid::new(); // Add source grid.draw_source(ORIGIN_POINT); // Draw walls grid.draw_lines(walls, Cell::Wall); (grid, ORIGIN_POINT) } // Non-drawing grid functions impl Grid { /// Number of points in the grid #[inline] pub fn len(&self) -> usize { self.map.len() } /// Find the highest point in the collection #[inline(always)] pub fn find_high_bound(&self) -> Point { let x = self.map.keys().max_by(|a, b| u64::cmp(&a.x, &b.x)).map(|x| x.x).unwrap_or(0); let y = self.map.keys().max_by(|a, b| u64::cmp(&a.y, &b.y)).map(|y| y.y).unwrap_or(0); Point{ x, y } } /// Find the lowest point in the collection #[inline(always)] pub fn find_low_bound(&self) -> Point { let x = self.map.keys().min_by(|a, b| u64::cmp(&a.x, &b.x)).map(|x| x.x).unwrap_or(0); let y = self.map.keys().min_by(|a, b| u64::cmp(&a.y, &b.y)).map(|y| y.y).unwrap_or(0); Point{ x, y } } /// Find the low and high bound as a flattened line #[inline] pub fn find_bound(&self) -> Line { let start = self.find_low_bound(); let end = self.find_high_bound(); Line{ start, end } } /// Iterate over a sparse grid, bounded by `bound`, any not set cells will be drawn with air. #[inline] pub fn iterate_sparse<'g>(&'g self, bound: Line) -> impl Iterator + 'g { const AIR: Cell = Cell::Air; //let mut grid = start.map.iter().fuse().peekable(); bound.normalised().unroll().into_iter() .map(move |point| { if let Some(cell) = self.map.get(&point) { // Contains the point, return that reference return cell; } /* if let Some(&(next_wall, cell)) = grid.peek() { if next_wall == &point { // Take this point off the iterator if it matches return grid.next().unwrap().1; } }*/ &AIR }) } }