Extract some grid functionality into trait
This commit is contained in:
parent
e668c96185
commit
8ccab04d6f
|
@ -4,7 +4,7 @@ use std::collections::HashSet;
|
||||||
|
|
||||||
use aoc2021::common::*;
|
use aoc2021::common::*;
|
||||||
|
|
||||||
const DAY: usize = 09;
|
const DAY: usize = 9;
|
||||||
type Parsed = Vec<Vec<u8>>;
|
type Parsed = Vec<Vec<u8>>;
|
||||||
|
|
||||||
fn parse_input(raw: &str) -> Parsed {
|
fn parse_input(raw: &str) -> Parsed {
|
||||||
|
|
|
@ -3,15 +3,15 @@
|
||||||
extern crate test;
|
extern crate test;
|
||||||
use aoc2021::{
|
use aoc2021::{
|
||||||
common::*,
|
common::*,
|
||||||
grid::{Grid, PositionND},
|
grid::{Grid, HashGrid, PositionND},
|
||||||
};
|
};
|
||||||
|
|
||||||
const DAY: usize = 11;
|
const DAY: usize = 11;
|
||||||
const ROUNDS: usize = 100;
|
const ROUNDS: usize = 100;
|
||||||
type Parsed = Grid<u8, 2>;
|
type Parsed = HashGrid<u8, 2>;
|
||||||
|
|
||||||
fn parse_input(raw: &str) -> Parsed {
|
fn parse_input(raw: &str) -> Parsed {
|
||||||
Grid::<u8, 2>::from_bytes_2d(raw, |b: u8| b - b'0')
|
HashGrid::<u8, 2>::from_bytes_2d(raw, |b: u8| b - b'0')
|
||||||
}
|
}
|
||||||
|
|
||||||
fn part1(parsed: &Parsed) -> usize {
|
fn part1(parsed: &Parsed) -> usize {
|
||||||
|
@ -80,5 +80,5 @@ mod tests {
|
||||||
test!(part2() == 195);
|
test!(part2() == 195);
|
||||||
bench!(part1() == 1741);
|
bench!(part1() == 1741);
|
||||||
bench!(part2() == 440);
|
bench!(part2() == 440);
|
||||||
bench_input!(Grid::len => 100);
|
bench_input!(HashGrid::len => 100);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,40 +2,50 @@ pub mod cell;
|
||||||
pub mod direction;
|
pub mod direction;
|
||||||
pub mod position;
|
pub mod position;
|
||||||
pub use direction::*;
|
pub use direction::*;
|
||||||
pub use position::*;
|
|
||||||
|
|
||||||
use itertools::join;
|
use itertools::join;
|
||||||
|
pub use position::*;
|
||||||
use std::{collections::HashMap, fmt::Display, hash::BuildHasher};
|
use std::{collections::HashMap, fmt::Display, hash::BuildHasher};
|
||||||
|
|
||||||
|
#[allow(clippy::len_without_is_empty)] // I mainly have this for assertions in benchmarks
|
||||||
|
pub trait Grid<T, const D: usize> {
|
||||||
|
fn get(&self, pos: &PositionND<D>) -> Option<&T>;
|
||||||
|
|
||||||
|
fn insert<Pos: Into<PositionND<D>>>(&mut self, pos: Pos, element: T);
|
||||||
|
|
||||||
|
fn len(&self) -> usize;
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct Grid<T: Default, const D: usize> {
|
pub struct HashGrid<T: Default, const D: usize> {
|
||||||
pub fields: HashMap<PositionND<D>, T>,
|
pub fields: HashMap<PositionND<D>, T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Default + Copy, const D: usize> Grid<T, D> {
|
impl<T: Default, const D: usize> Grid<T, D> for HashGrid<T, D> {
|
||||||
pub fn get(&self, pos: &PositionND<D>) -> T {
|
fn get(&self, pos: &PositionND<D>) -> Option<&T> {
|
||||||
self.fields.get(pos).copied().unwrap_or_else(T::default)
|
self.fields.get(pos)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert<Pos: Into<PositionND<D>>>(&mut self, pos: Pos, t: T) {
|
fn insert<Pos: Into<PositionND<D>>>(&mut self, pos: Pos, t: T) {
|
||||||
self.fields.insert(pos.into(), t);
|
self.fields.insert(pos.into(), t);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_bytes_2d<F: FnMut(u8) -> T + Copy>(raw: &str, mut f: F) -> Grid<T, 2> {
|
fn len(&self) -> usize {
|
||||||
|
self.fields.len()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Default + Copy, const D: usize> HashGrid<T, D> {
|
||||||
|
pub fn from_bytes_2d<F: FnMut(u8) -> T + Copy>(raw: &str, mut f: F) -> HashGrid<T, 2> {
|
||||||
raw.lines()
|
raw.lines()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.flat_map(move |(y, l)| l.bytes().enumerate().map(move |(x, c)| (PositionND { points: [x as i64, y as i64] }, f(c))))
|
.flat_map(move |(y, l)| l.bytes().enumerate().map(move |(x, c)| (PositionND { points: [x as i64, y as i64] }, f(c))))
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn len(&self) -> usize {
|
|
||||||
self.fields.len()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Default, const D: usize> std::iter::FromIterator<(PositionND<D>, T)> for Grid<T, D> {
|
impl<T: Default, const D: usize> std::iter::FromIterator<(PositionND<D>, T)> for HashGrid<T, D> {
|
||||||
fn from_iter<I: IntoIterator<Item = (PositionND<D>, T)>>(iter: I) -> Self {
|
fn from_iter<I: IntoIterator<Item = (PositionND<D>, T)>>(iter: I) -> Self {
|
||||||
Grid { fields: iter.into_iter().collect() }
|
HashGrid { fields: iter.into_iter().collect() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,7 +56,6 @@ struct Boundaries {
|
||||||
y_max: i64,
|
y_max: i64,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rustfmt::skip]
|
|
||||||
fn get_boundaries(input: &[&PositionND<2>]) -> Boundaries {
|
fn get_boundaries(input: &[&PositionND<2>]) -> Boundaries {
|
||||||
let x_min = input.iter().min_by_key(|k| k.points[0]).map(|p| p.points[0]).unwrap_or(0);
|
let x_min = input.iter().min_by_key(|k| k.points[0]).map(|p| p.points[0]).unwrap_or(0);
|
||||||
let x_max = input.iter().max_by_key(|k| k.points[0]).map(|p| p.points[0]).unwrap_or(0);
|
let x_max = input.iter().max_by_key(|k| k.points[0]).map(|p| p.points[0]).unwrap_or(0);
|
||||||
|
|
|
@ -49,6 +49,7 @@ impl<const DIMS: usize> PositionND<DIMS> {
|
||||||
|
|
||||||
pub fn from_padded(slice: &[i64]) -> PositionND<DIMS> {
|
pub fn from_padded(slice: &[i64]) -> PositionND<DIMS> {
|
||||||
let mut points = [0; DIMS];
|
let mut points = [0; DIMS];
|
||||||
|
#[allow(clippy::manual_memcpy)]
|
||||||
for i in 0..(DIMS.min(slice.len())) {
|
for i in 0..(DIMS.min(slice.len())) {
|
||||||
points[i] = slice[i];
|
points[i] = slice[i];
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user