Migrate day 11 to PositionND

This commit is contained in:
kageru 2021-07-08 19:21:07 +02:00
parent eee3183dc0
commit 98b8a9c81c
Signed by: kageru
GPG Key ID: 8282A2BEA4ADA3D2
3 changed files with 40 additions and 22 deletions

View File

@ -40,7 +40,7 @@ impl Default for Tile {
} }
} }
type Parsed = HashMap<Position2D, Tile>; type Parsed = HashMap<PositionND<2>, Tile>;
fn read_input() -> String { fn read_input() -> String {
read_file(11) read_file(11)
@ -50,15 +50,20 @@ fn parse_input(raw: &str) -> Parsed {
raw.lines() raw.lines()
.enumerate() .enumerate()
.flat_map(move |(y, l)| { .flat_map(move |(y, l)| {
l.chars() l.chars().enumerate().map(move |(x, c)| {
.enumerate() (
.map(move |(x, c)| (Position2D { x: x as i64, y: y as i64 }, Tile::from(c))) PositionND {
points: [x as i64, y as i64],
},
Tile::from(c),
)
})
}) })
.collect() .collect()
} }
#[inline] #[inline]
fn occupied_neighbors(pos: &Position2D, grid: &Parsed) -> usize { fn occupied_neighbors(pos: &PositionND<2>, grid: &Parsed) -> usize {
pos.neighbors() pos.neighbors()
.iter() .iter()
.filter(|p| grid.get(&p).unwrap_or(&Tile::Floor) == &Tile::Occupied) .filter(|p| grid.get(&p).unwrap_or(&Tile::Floor) == &Tile::Occupied)
@ -68,10 +73,9 @@ fn occupied_neighbors(pos: &Position2D, grid: &Parsed) -> usize {
const DIRECTIONS: [(i64, i64); 8] = [(0, 1), (1, 0), (1, 1), (0, -1), (-1, 0), (-1, -1), (-1, 1), (1, -1)]; const DIRECTIONS: [(i64, i64); 8] = [(0, 1), (1, 0), (1, 1), (0, -1), (-1, 0), (-1, -1), (-1, 1), (1, -1)];
#[inline] #[inline]
fn neighbors_in_vision(pos: &Position2D, grid: &Parsed) -> usize { fn neighbors_in_vision(pos: &PositionND<2>, grid: &Parsed) -> usize {
DIRECTIONS IntoIterator::into_iter(DIRECTIONS)
.iter() .map(|(x, y)| PositionND { points: [x, y] })
.map(|t| Position2D::from(*t))
.map(|p| { .map(|p| {
(1..) (1..)
.find_map(|n| match grid.get(&(*pos + (p * n))) { .find_map(|n| match grid.get(&(*pos + (p * n))) {
@ -85,7 +89,7 @@ fn neighbors_in_vision(pos: &Position2D, grid: &Parsed) -> usize {
.count() .count()
} }
fn make_step<F: Fn(&Position2D, &Parsed) -> usize>(previous: &mut Parsed, count_neighbors: F, limit: usize) -> bool { fn make_step<F: Fn(&PositionND<2>, &Parsed) -> usize>(previous: &mut Parsed, count_neighbors: F, limit: usize) -> bool {
let readonly = previous.to_owned(); let readonly = previous.to_owned();
let mut changed = false; let mut changed = false;
for (pos, tile) in previous.iter_mut() { for (pos, tile) in previous.iter_mut() {
@ -108,7 +112,7 @@ fn make_step<F: Fn(&Position2D, &Parsed) -> usize>(previous: &mut Parsed, count_
changed changed
} }
fn move_until_equilibrium<F: Fn(&Position2D, &Parsed) -> usize>(mut parsed: Parsed, count_neighbors: F, limit: usize) -> usize { fn move_until_equilibrium<F: Fn(&PositionND<2>, &Parsed) -> usize>(mut parsed: Parsed, count_neighbors: F, limit: usize) -> usize {
while make_step(&mut parsed, &count_neighbors, limit) {} while make_step(&mut parsed, &count_neighbors, limit) {}
parsed.iter().filter(|(_, t)| t == &&Tile::Occupied).count() parsed.iter().filter(|(_, t)| t == &&Tile::Occupied).count()
} }
@ -219,7 +223,7 @@ LLL####LL#
assert_eq!(draw_ascii(&grid), draw_ascii(&after_1)); assert_eq!(draw_ascii(&grid), draw_ascii(&after_1));
assert_eq!(&grid, &after_1); assert_eq!(&grid, &after_1);
assert!( make_step(&mut grid, neighbors_in_vision, 5)); assert!(make_step(&mut grid, neighbors_in_vision, 5));
let after_2 = parse_input(P2_AFTER_2); let after_2 = parse_input(P2_AFTER_2);
assert_eq!(draw_ascii(&grid), draw_ascii(&after_2)); assert_eq!(draw_ascii(&grid), draw_ascii(&after_2));
assert_eq!(&grid, &after_2); assert_eq!(&grid, &after_2);

View File

@ -38,20 +38,20 @@ struct Boundaries {
} }
#[rustfmt::skip] #[rustfmt::skip]
fn get_boundaries(input: &[&Position2D]) -> Boundaries { fn get_boundaries(input: &[&PositionND<2>]) -> Boundaries {
let x_min = input.iter().min_by_key(|k| k.x).map(|p| p.x).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.x).map(|p| p.x).unwrap_or(0); let x_max = input.iter().max_by_key(|k| k.points[0]).map(|p| p.points[0]).unwrap_or(0);
let y_min = input.iter().min_by_key(|k| k.y).map(|p| p.y).unwrap_or(0); let y_min = input.iter().min_by_key(|k| k.points[1]).map(|p| p.points[1]).unwrap_or(0);
let y_max = input.iter().max_by_key(|k| k.y).map(|p| p.y).unwrap_or(0); let y_max = input.iter().max_by_key(|k| k.points[1]).map(|p| p.points[1]).unwrap_or(0);
Boundaries { x_min, x_max, y_min, y_max } Boundaries { x_min, x_max, y_min, y_max }
} }
pub fn draw_ascii<T: Display + Default, S: BuildHasher>(coordinates: &HashMap<Position2D, T, S>) -> String { pub fn draw_ascii<T: Display + Default, S: BuildHasher>(coordinates: &HashMap<PositionND<2>, T, S>) -> String {
let b = get_boundaries(&coordinates.keys().collect::<Vec<_>>()); let b = get_boundaries(&coordinates.keys().collect::<Vec<_>>());
join( join(
(b.y_min..=b.y_max).rev().map(|y| { (b.y_min..=b.y_max).rev().map(|y| {
(b.x_min..=b.x_max) (b.x_min..=b.x_max)
.map(|x| coordinates.get(&(x, y).into()).unwrap_or(&T::default()).to_string()) .map(|x| coordinates.get(&PositionND { points: [x, y] }).unwrap_or(&T::default()).to_string())
.collect::<String>() .collect::<String>()
}), }),
"\n", "\n",

View File

@ -3,7 +3,7 @@ use super::direction::*;
use impl_ops::*; use impl_ops::*;
use itertools::iproduct; use itertools::iproduct;
use std::{ use std::{
convert::TryInto, hash::Hash, ops, ops::{Add, AddAssign} convert::TryInto, hash::Hash, ops::{self, Add, AddAssign, Mul}
}; };
pub trait Position pub trait Position
@ -87,7 +87,7 @@ impl<const DIMS: usize> PositionND<DIMS> {
3 => { 3 => {
for (i, n) in iproduct!((-1..=1), (-1..=1), (-1..=1)) for (i, n) in iproduct!((-1..=1), (-1..=1), (-1..=1))
.filter(|t| t != &(0, 0, 0)) .filter(|t| t != &(0, 0, 0))
.map(|(x, y, z)| PositionND::<DIMS>::from_padded(&[self.points[0]+x, self.points[1]+y, self.points[2]+z])) .map(|(x, y, z)| PositionND::<DIMS>::from_padded(&[self.points[0] + x, self.points[1] + y, self.points[2] + z]))
.enumerate() .enumerate()
{ {
out[i] = n; out[i] = n;
@ -96,7 +96,9 @@ impl<const DIMS: usize> PositionND<DIMS> {
4 => { 4 => {
for (i, n) in iproduct!((-1..=1), (-1..=1), (-1..=1), (-1..=1)) for (i, n) in iproduct!((-1..=1), (-1..=1), (-1..=1), (-1..=1))
.filter(|t| t != &(0, 0, 0, 0)) .filter(|t| t != &(0, 0, 0, 0))
.map(|(x, y, z, w)| PositionND::<DIMS>::from_padded(&[self.points[0]+x, self.points[1]+y, self.points[2]+z, self.points[3]+w])) .map(|(x, y, z, w)| {
PositionND::<DIMS>::from_padded(&[self.points[0] + x, self.points[1] + y, self.points[2] + z, self.points[3] + w])
})
.enumerate() .enumerate()
{ {
out[i] = n; out[i] = n;
@ -125,6 +127,18 @@ impl<const DIMS: usize> PositionND<DIMS> {
*/ */
} }
impl<const D: usize> Mul<i64> for PositionND<D> {
type Output = PositionND<D>;
fn mul(self, rhs: i64) -> Self::Output {
let mut points = [0; D];
for i in 0..D {
points[i] = self.points[i] * rhs;
}
PositionND { points }
}
}
impl<const D: usize> Add<PositionND<D>> for PositionND<D> { impl<const D: usize> Add<PositionND<D>> for PositionND<D> {
type Output = PositionND<D>; type Output = PositionND<D>;