Fortune for day14's current commit: Small curse − 小凶master
parent
6a2aefc1d9
commit
774c71d5d4
@ -1,3 +1,180 @@
|
||||
//! 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<Cell> 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<Point, Cell>,
|
||||
}
|
||||
|
||||
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<Cell>
|
||||
{
|
||||
self.map.insert(point, cell)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn draw_line_with<F>(&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<I,F>(&mut self, line: I, mut with: F)
|
||||
where F: for<'a> FnMut(&'a Point) -> Cell,
|
||||
I: IntoIterator<Item = Line>
|
||||
{
|
||||
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<Item = Line>, 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<Item = &'g Cell> + '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
|
||||
})
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in new issue