From a2bee8300b6f507e5c20f5b4cdfab3372b6cc08d Mon Sep 17 00:00:00 2001 From: kageru Date: Thu, 17 Dec 2020 14:51:05 +0100 Subject: [PATCH] Refactor grid stuff into modules --- 2020/src/bin/day11.rs | 2 +- 2020/src/bin/day15.rs | 1 + 2020/src/bin/day17.rs | 4 +- 2020/src/grid.rs | 231 ++----------------------------------- 2020/src/grid/cell.rs | 34 ++++++ 2020/src/grid/direction.rs | 49 ++++++++ 2020/src/grid/position.rs | 141 ++++++++++++++++++++++ 7 files changed, 238 insertions(+), 224 deletions(-) create mode 100644 2020/src/grid/cell.rs create mode 100644 2020/src/grid/direction.rs create mode 100644 2020/src/grid/position.rs diff --git a/2020/src/bin/day11.rs b/2020/src/bin/day11.rs index f1de31c..b3fc805 100644 --- a/2020/src/bin/day11.rs +++ b/2020/src/bin/day11.rs @@ -59,7 +59,7 @@ fn parse_input(raw: &str) -> Parsed { #[inline] fn occupied_neighbors(pos: &Position2D, grid: &Parsed) -> usize { - pos.moore() + pos.neighbors() .iter() .filter(|p| grid.get(&p).unwrap_or(&Tile::Floor) == &Tile::Occupied) .count() diff --git a/2020/src/bin/day15.rs b/2020/src/bin/day15.rs index f1265c4..d9a15c6 100644 --- a/2020/src/bin/day15.rs +++ b/2020/src/bin/day15.rs @@ -27,6 +27,7 @@ fn part1(initial: &Parsed, limit: usize) -> usize { } // only here so the test/bench macro works +#[allow(unused)] #[inline] fn part2(parsed: &Parsed, limit: usize) -> usize { part1(parsed, limit) diff --git a/2020/src/bin/day17.rs b/2020/src/bin/day17.rs index c9945d3..a091e5b 100644 --- a/2020/src/bin/day17.rs +++ b/2020/src/bin/day17.rs @@ -1,6 +1,8 @@ #![feature(test)] extern crate test; -use aoc2020::{common::*, grid::*}; +use aoc2020::{ + common::*, grid::{cell::Cell, *} +}; type Parsed = Grid; diff --git a/2020/src/grid.rs b/2020/src/grid.rs index d28a1a4..fadac61 100644 --- a/2020/src/grid.rs +++ b/2020/src/grid.rs @@ -1,80 +1,18 @@ -use impl_ops::*; -use itertools::{iproduct, join, Itertools}; -use std::{ - collections::HashMap, convert::TryInto, fmt::{self, Display, Formatter}, hash::{BuildHasher, Hash}, ops, ops::AddAssign -}; +pub mod cell; +pub mod direction; +pub mod position; +pub use direction::*; +pub use position::*; -#[derive(Hash, PartialEq, Eq, Debug, Clone, Copy)] -pub struct Position2D { - pub x: i64, - pub y: i64, -} - -#[derive(Hash, PartialEq, Eq, Debug, Clone, Copy)] -pub struct Position3D { - pub x: i64, - pub y: i64, - pub z: i64, -} - -impl Position3D { - pub fn neighbors(&self) -> Vec { - iproduct!((-1..=1), (-1..=1), (-1..=1)) - .filter(|t| t != &(0, 0, 0)) - .map(|(x, y, z)| *self + Position3D::from((x, y, z))) - .collect() - } -} - -#[derive(Clone, Copy, Debug)] -pub enum Direction { - Up, - Down, - Left, - Right, -} - -#[derive(Hash, PartialEq, Eq, Debug, Clone, Copy)] -pub enum Cell { - Alive, - Dead, -} - -impl From for Cell { - fn from(b: u8) -> Self { - match b { - b'.' => Cell::Dead, - b'#' => Cell::Alive, - _ => unreachable!(), - } - } -} - -impl Display for Cell { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - f.write_str(match self { - Cell::Alive => ".", - Cell::Dead => "#", - }) - } -} - -impl Default for Cell { - fn default() -> Self { - Cell::Dead - } -} - -pub trait Position {} -impl Position for Position2D {} -impl Position for Position3D {} +use itertools::join; +use std::{collections::HashMap, fmt::Display, hash::BuildHasher}; #[derive(Debug, Clone)] pub struct Grid { pub fields: HashMap, } -impl Grid { +impl Grid { pub fn get>(&self, pos: Pos) -> T { self.fields.get(&pos.into()).copied().unwrap_or_else(|| T::default()) } @@ -84,7 +22,7 @@ impl Grid { } } -impl std::iter::FromIterator<(P, T)> for Grid { +impl std::iter::FromIterator<(P, T)> for Grid { fn from_iter>(iter: I) -> Self { Grid { fields: iter.into_iter().collect(), @@ -98,8 +36,6 @@ impl Grid { } } -pub const ALL_DIRECTIONS: [Direction; 4] = [Direction::Up, Direction::Down, Direction::Left, Direction::Right]; - struct Boundaries { x_min: i64, x_max: i64, @@ -128,155 +64,6 @@ pub fn draw_ascii(coordinates: &HashMap [(Direction, Position2D); 4] { - [ - (Direction::Up, *self + Direction::Up), - (Direction::Down, *self + Direction::Down), - (Direction::Right, *self + Direction::Right), - (Direction::Left, *self + Direction::Left), - ] - } - - pub fn moore(&self) -> [Position2D; 8] { - [ - *self + Direction::Up + Direction::Left, - *self + Direction::Up, - *self + Direction::Up + Direction::Right, - *self + Direction::Left, - *self + Direction::Right, - *self + Direction::Down + Direction::Left, - *self + Direction::Down, - *self + Direction::Down + Direction::Right, - ] - } -} - -impl Direction { - pub fn turn(&mut self, turn_value: i64) { - *self += turn_value as i8; - } -} - -impl From for Position2D { - fn from(d: Direction) -> Self { - match d { - Direction::Up => Position2D::from((0, 1)), - Direction::Right => Position2D::from((1, 0)), - Direction::Left => Position2D::from((-1, 0)), - Direction::Down => Position2D::from((0, -1)), - } - } -} - -impl_op!(+ |a: Direction, b: i8| -> Direction { - match b { - -1 | 3 => match a { - Direction::Up => Direction::Left, - Direction::Right => Direction::Up, - Direction::Down => Direction::Right, - Direction::Left => Direction::Down, - }, - 1 | -3 => match a { - Direction::Up => Direction::Right, - Direction::Right => Direction::Down, - Direction::Down => Direction::Left, - Direction::Left => Direction::Up, - }, - 0 | 4 | -4 => a, - 2 | -2 => match a { - Direction::Up => Direction::Down, - Direction::Right => Direction::Left, - Direction::Down => Direction::Up, - Direction::Left => Direction::Right, - }, - n => unreachable!(format!("Illegal turn value: {}", n)), - } -}); - -impl_op!(+|a: Position2D, b: Position2D| -> Position2D { - Position2D { - x: a.x + b.x, - y: a.y + b.y - } -}); - -impl_op!(-|a: Position2D, b: Position2D| -> Position2D { - Position2D { - x: a.x - b.x, - y: a.y - b.y, - } -}); - -impl_op!(-|a: Position3D, b: Position3D| -> Position3D { - Position3D { - x: a.x - b.x, - y: a.y - b.y, - z: a.z - b.z, - } -}); - -impl_op!(+|a: Position3D, b: Position3D| -> Position3D { - Position3D { - x: a.x + b.x, - y: a.y + b.y, - z: a.z + b.z, - } -}); - -impl_op!(+|a: Position2D, b: Direction| -> Position2D { - a + Position2D::from(b) -}); - -impl_op!(-|a: Position2D, b: Direction| -> Position2D { a - Position2D::from(b) }); - -impl_op!(*|a: Position2D, b: i64| -> Position2D { Position2D { x: a.x * b, y: a.y * b } }); - -impl AddAssign for Direction { - fn add_assign(&mut self, rhs: i8) { - *self = *self + rhs; - } -} - -impl AddAssign for Position2D { - fn add_assign(&mut self, rhs: Direction) { - *self = *self + rhs; - } -} - -impl AddAssign for Position2D { - fn add_assign(&mut self, rhs: Position2D) { - *self = *self + rhs; - } -} - -impl From<(I, I, I)> for Position3D -where I: TryInto -{ - fn from((x, y, z): (I, I, I)) -> Position3D { - Position3D { - x: unwrap_number_result(x), - y: unwrap_number_result(y), - z: unwrap_number_result(z), - } - } -} - -// because calling .unwrap() on a TryInto result isn’t possible without trait bounds on the -// associated Error type. -fn unwrap_number_result>(i: I) -> i64 { - match i.try_into() { - Ok(i) => return i, - _ => panic!("Bad coordinate"), - } -} - -impl> From<(I, I)> for Position2D { - fn from((x, y): (I, I)) -> Position2D { - Position2D { x: x.into(), y: y.into() } - } -} - #[cfg(test)] mod tests { use super::*; diff --git a/2020/src/grid/cell.rs b/2020/src/grid/cell.rs new file mode 100644 index 0000000..e10a6d3 --- /dev/null +++ b/2020/src/grid/cell.rs @@ -0,0 +1,34 @@ +use std::{ + fmt::{self, Display, Formatter}, hash::Hash +}; + +#[derive(Hash, PartialEq, Eq, Debug, Clone, Copy)] +pub enum Cell { + Alive, + Dead, +} + +impl From for Cell { + fn from(b: u8) -> Self { + match b { + b'.' => Cell::Dead, + b'#' => Cell::Alive, + _ => unreachable!(), + } + } +} + +impl Display for Cell { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.write_str(match self { + Cell::Alive => ".", + Cell::Dead => "#", + }) + } +} + +impl Default for Cell { + fn default() -> Self { + Cell::Dead + } +} diff --git a/2020/src/grid/direction.rs b/2020/src/grid/direction.rs new file mode 100644 index 0000000..db9ced8 --- /dev/null +++ b/2020/src/grid/direction.rs @@ -0,0 +1,49 @@ +use impl_ops::*; +use std::{ops, ops::AddAssign}; + +pub const ALL_DIRECTIONS: [Direction; 4] = [Direction::Up, Direction::Down, Direction::Left, Direction::Right]; + +#[derive(Clone, Copy, Debug)] +pub enum Direction { + Up, + Down, + Left, + Right, +} + +impl AddAssign for Direction { + fn add_assign(&mut self, rhs: i8) { + *self = *self + rhs; + } +} + +impl_op!(+ |a: Direction, b: i8| -> Direction { + match b { + -1 | 3 => match a { + Direction::Up => Direction::Left, + Direction::Right => Direction::Up, + Direction::Down => Direction::Right, + Direction::Left => Direction::Down, + }, + 1 | -3 => match a { + Direction::Up => Direction::Right, + Direction::Right => Direction::Down, + Direction::Down => Direction::Left, + Direction::Left => Direction::Up, + }, + 0 | 4 | -4 => a, + 2 | -2 => match a { + Direction::Up => Direction::Down, + Direction::Right => Direction::Left, + Direction::Down => Direction::Up, + Direction::Left => Direction::Right, + }, + n => unreachable!(format!("Illegal turn value: {}", n)), + } +}); + +impl Direction { + pub fn turn(&mut self, turn_value: i64) { + *self += turn_value as i8; + } +} diff --git a/2020/src/grid/position.rs b/2020/src/grid/position.rs new file mode 100644 index 0000000..83b27e4 --- /dev/null +++ b/2020/src/grid/position.rs @@ -0,0 +1,141 @@ +use super::direction::*; +use impl_ops::*; +use itertools::iproduct; +use std::{convert::TryInto, hash::Hash, ops, ops::AddAssign}; + +pub trait Position +where Self: Sized + Hash + Eq +{ + fn neighbors(&self) -> Vec; +} + +#[derive(Hash, PartialEq, Eq, Debug, Clone, Copy)] +pub struct Position2D { + pub x: i64, + pub y: i64, +} + +#[derive(Hash, PartialEq, Eq, Debug, Clone, Copy)] +pub struct Position3D { + pub x: i64, + pub y: i64, + pub z: i64, +} + +mod p2d { + use super::*; + + impl From for Position2D { + fn from(d: Direction) -> Self { + match d { + Direction::Up => Position2D::from((0, 1)), + Direction::Right => Position2D::from((1, 0)), + Direction::Left => Position2D::from((-1, 0)), + Direction::Down => Position2D::from((0, -1)), + } + } + } + + impl Position for Position2D { + fn neighbors(&self) -> Vec { + vec![ + *self + Direction::Up + Direction::Left, + *self + Direction::Up, + *self + Direction::Up + Direction::Right, + *self + Direction::Left, + *self + Direction::Right, + *self + Direction::Down + Direction::Left, + *self + Direction::Down, + *self + Direction::Down + Direction::Right, + ] + } + } + + impl> From<(I, I)> for Position2D { + fn from((x, y): (I, I)) -> Position2D { + Position2D { x: x.into(), y: y.into() } + } + } + + impl_op!(+|a: Position2D, b: Direction| -> Position2D { a + Position2D::from(b) }); + + impl_op!(-|a: Position2D, b: Direction| -> Position2D { a - Position2D::from(b) }); + + impl_op!(*|a: Position2D, b: i64| -> Position2D { Position2D { x: a.x * b, y: a.y * b } }); + + impl_op!(+|a: Position2D, b: Position2D| -> Position2D { + Position2D { + x: a.x + b.x, + y: a.y + b.y + } + }); + + impl_op!(-|a: Position2D, b: Position2D| -> Position2D { + Position2D { + x: a.x - b.x, + y: a.y - b.y, + } + }); + + impl AddAssign for Position2D { + fn add_assign(&mut self, rhs: Direction) { + *self = *self + rhs; + } + } + + impl AddAssign for Position2D { + fn add_assign(&mut self, rhs: Position2D) { + *self = *self + rhs; + } + } +} + +mod p3d { + use super::*; + + impl Position for Position3D { + fn neighbors(&self) -> Vec { + iproduct!((-1..=1), (-1..=1), (-1..=1)) + .filter(|t| t != &(0, 0, 0)) + .map(|(x, y, z)| *self + Position3D::from((x, y, z))) + .collect() + } + } + + impl From<(I, I, I)> for Position3D + where I: TryInto + { + fn from((x, y, z): (I, I, I)) -> Position3D { + Position3D { + x: unwrap_number_result(x), + y: unwrap_number_result(y), + z: unwrap_number_result(z), + } + } + } + + impl_op!(-|a: Position3D, b: Position3D| -> Position3D { + Position3D { + x: a.x - b.x, + y: a.y - b.y, + z: a.z - b.z, + } + }); + + impl_op!(+|a: Position3D, b: Position3D| -> Position3D { + Position3D { + x: a.x + b.x, + y: a.y + b.y, + z: a.z + b.z, + } + }); +} + +// because calling .unwrap() on a TryInto result isn’t possible without trait bounds on the +// associated Error type. +fn unwrap_number_result>(i: I) -> i64 { + match i.try_into() { + Ok(i) => return i, + _ => panic!("Bad coordinate"), + } +}