diff --git a/src/day10.rs b/src/day10.rs index 50ac2fb..c52214d 100644 --- a/src/day10.rs +++ b/src/day10.rs @@ -1,19 +1,19 @@ use aoc_runner_derive::{aoc, aoc_generator}; use grid::Grid; use itertools::Itertools; -use std::io::{BufRead, Lines}; +use std::io::BufRead; #[aoc_generator(day10)] pub fn get_input(input: &[u8]) -> TrailMap { - TrailMap::from(input.lines()) + TrailMap::from(input) } pub struct TrailMap { map: Grid, } -impl From> for TrailMap { - fn from(input: Lines) -> Self { +impl From for TrailMap { + fn from(input: T) -> Self { Self { map: input.into() } } } @@ -29,13 +29,13 @@ impl TrailMap { .collect_vec() } fn count_reachable_from(&self, pos: &(i64, i64), needle: u8, visited: &mut Grid) -> u64 { - if visited.get(pos) == Some(true) { + if visited.get(pos) == Some(&true) { return 0; } else { visited.set(pos, true); } let our_val = self.map.get(pos).unwrap(); - if our_val == needle { + if *our_val == needle { return 1; } // adjacents that are +1 @@ -43,7 +43,7 @@ impl TrailMap { .iter() .map(|(x_ofs, y_ofs)| (pos.0 + x_ofs, pos.1 + y_ofs)) // get target position .map(|target_pos| (target_pos, self.map.get(&target_pos))) // get value at that position - .filter(|(_, val)| *val == Some(our_val + 1)) // only interested if it's our value + 1 + .filter(|(_, val)| *val == Some(&(our_val + 1))) // only interested if it's our value + 1 .map(|(pos, _)| pos) // discard the value .map(|pos| self.count_reachable_from(&pos, needle, visited)) .sum() @@ -51,14 +51,14 @@ impl TrailMap { fn count_paths_to(&self, pos: &(i64, i64), needle: u8) -> u64 { let our_val = self.map.get(pos).unwrap(); - if our_val == needle { + if *our_val == needle { return 1; } [(-1, 0), (1, 0), (0, -1), (0, 1)] // left, right, up, down .iter() .map(|(x_ofs, y_ofs)| (pos.0 + x_ofs, pos.1 + y_ofs)) // get target position .map(|target_pos| (target_pos, self.map.get(&target_pos))) // get value at that position - .filter(|(_, val)| *val == Some(our_val + 1)) // only interested if it's our value + 1 + .filter(|(_, val)| *val == Some(&(our_val + 1))) // only interested if it's our value + 1 .map(|(pos, _)| pos) // discard the value .map(|mov| self.count_paths_to(&mov, needle)) .sum::() diff --git a/src/day12.rs b/src/day12.rs index 61fa4ed..ef15b47 100644 --- a/src/day12.rs +++ b/src/day12.rs @@ -1,5 +1,3 @@ -use std::io::BufRead; - use aoc_runner_derive::{aoc, aoc_generator}; use grid::{Coord2d, Grid}; @@ -10,7 +8,7 @@ pub struct Farm { impl From<&[u8]> for Farm { fn from(input: &[u8]) -> Self { Self { - map: Grid::from(input.lines()), + map: Grid::from(input), } } } @@ -27,9 +25,9 @@ impl Farm { .fold((1, 0), |(area, perimeter), adj| { match self.map.get(adj) { Some(plant) if plant == our_plant => { - if visited.get(adj) == Some(false) { + if visited.get(adj) == Some(&false) { // add the perimeter of the growth from there if not visited yet - let (add_area, add_perimeter) = self.compute_region(&adj, visited); + let (add_area, add_perimeter) = self.compute_region(adj, visited); (area + add_area, perimeter + add_perimeter) } else { (area, perimeter) @@ -99,9 +97,9 @@ impl Farm { .fold((1, self.count_corners(pos)), |(area, corners), adj| { match self.map.get(adj) { Some(plant) if plant == our_plant => { - if visited.get(adj) == Some(false) { + if visited.get(adj) == Some(&false) { // add the perimeter of the growth from there if not visited yet - let (n_area, n_corners) = self.region_corners(&adj, visited); + let (n_area, n_corners) = self.region_corners(adj, visited); (area+n_area, corners+n_corners) } else { (area, corners) } } @@ -110,7 +108,7 @@ impl Farm { }) } fn regions_discount_cost(&self) -> u64 { - let mut visited = Grid::with_shape(self.map.width(), self.map.height(), false); + let mut visited = self.map.same_shape(false); let mut cost = 0; for y in 0..self.map.height() { for x in 0..self.map.width() { diff --git a/src/day6.rs b/src/day6.rs index af4d3d1..741701f 100644 --- a/src/day6.rs +++ b/src/day6.rs @@ -3,14 +3,14 @@ use bitflags::bitflags; use rayon::iter::ParallelIterator; use rayon::slice::ParallelSlice; use std::fmt; -use std::io::{BufRead, Lines}; +use std::io::BufRead; use std::ops::BitAnd; use grid::Grid; #[aoc_generator(day6)] pub fn get_input(input: &[u8]) -> Map { - Map::from(input.lines()) + Map::from(input) } #[repr(u8)] @@ -96,8 +96,8 @@ pub struct Map { path: Vec<((i64, i64), FacingDirection)>, } -impl From> for Map { - fn from(input: Lines) -> Self { +impl From for Map { + fn from(input: T) -> Self { let grid = Grid::from(input); let mut visited_from: Grid = Grid::new(grid.width() as i64); visited_from.data.resize(grid.data.len(), DirectionSet::empty()); @@ -114,7 +114,7 @@ impl From> for Map { } impl Map { - fn look(&self, dir: &FacingDirection) -> Option { + fn look(&self, dir: &FacingDirection) -> Option<&u8> { self.grid.get(&dir.pos_ofs(self.guard_pos)) } /// Move one step in the facing direction, return if we are still inside the bounds @@ -132,7 +132,7 @@ impl Map { } self.visited_from.set( &new_pos, - self.visited_from.get(&new_pos).unwrap() | self.guard_facing.into(), + *self.visited_from.get(&new_pos).unwrap() | self.guard_facing.into(), ); self.guard_pos = new_pos; StepOutcome::Continue diff --git a/src/day8.rs b/src/day8.rs index 73fe09d..d98dc53 100644 --- a/src/day8.rs +++ b/src/day8.rs @@ -2,19 +2,19 @@ use aoc_runner_derive::{aoc, aoc_generator}; use grid::Grid; use itertools::Itertools; use std::collections::HashSet; -use std::io::{BufRead, Lines}; +use std::io::BufRead; #[aoc_generator(day8)] pub fn get_input(input: &[u8]) -> AntennaMap { - AntennaMap::from(input.lines()) + AntennaMap::from(input) } pub struct AntennaMap { map: Grid, } -impl From> for AntennaMap { - fn from(input: Lines) -> Self { +impl From for AntennaMap { + fn from(input: T) -> Self { Self { map: Grid::from(input) } } } diff --git a/utils/grid/lib.rs b/utils/grid/lib.rs index 33d2a62..d09e769 100644 --- a/utils/grid/lib.rs +++ b/utils/grid/lib.rs @@ -1,7 +1,8 @@ use std::{ fmt::{Debug, Display, Formatter, Write}, - io::{BufRead, Lines}, + io::BufRead, iter::repeat, + mem::swap, ops::{Add, Sub}, }; @@ -49,6 +50,21 @@ impl AsCoord2d for Coord2d { } } +impl AsCoord2d for (i32, i32) { + fn to_coord(self) -> Coord2d { + Coord2d { + x: self.0.into(), + y: self.1.into(), + } + } + fn x(&self) -> i64 { + self.0.into() + } + fn y(&self) -> i64 { + self.1.into() + } +} + impl AsCoord2d for (i64, i64) { fn to_coord(self) -> Coord2d { Coord2d { x: self.0, y: self.1 } @@ -76,19 +92,41 @@ impl AsCoord2d for (usize, usize) { } } +impl AsCoord2d for (u64, u64) { + fn to_coord(self) -> Coord2d { + Coord2d { + x: self.0 as i64, + y: self.1 as i64, + } + } + fn x(&self) -> i64 { + self.0 as i64 + } + fn y(&self) -> i64 { + self.1 as i64 + } +} + #[derive(Clone)] pub struct Grid { pub data: Vec, width: i64, } -impl Grid { +impl Grid { pub fn new(width: i64) -> Self { Self { data: Vec::new(), width, } } + /// Returns a new [Grid] with the same shape (width x height) as `self`, filled with `fill` + pub fn same_shape(&self, fill: NT) -> Grid { + Grid { + data: Vec::from_iter(repeat(fill).take(self.width() * self.height())), + width: self.width, + } + } pub fn with_shape(width: usize, height: usize, fill: T) -> Self { Self { data: Vec::from_iter(repeat(fill).take(width * height)), @@ -96,10 +134,10 @@ impl Grid { } } pub fn width(&self) -> usize { - return self.width as usize; + self.width as usize } pub fn height(&self) -> usize { - return self.data.len() / self.width(); + self.data.len() / self.width() } fn pos(&self, c: &C) -> i64 { c.y() * self.width + c.x() @@ -124,18 +162,17 @@ impl Grid { } self.pos(c).try_into().ok() } - pub fn get(&self, c: &C) -> Option { + pub fn get(&self, c: &C) -> Option<&T> { match self.valid_pos(c) { - Some(pos) => Some(self.data[pos]), + Some(pos) => Some(&self.data[pos]), None => None, } } - pub fn set(&mut self, c: &C, val: T) -> Option { + pub fn set(&mut self, c: &C, mut val: T) -> Option { match self.valid_pos(c) { Some(pos) => { - let res = Some(self.data[pos]); - self.data[pos] = val; - res + swap(&mut self.data[pos], &mut val); + Some(val) } None => None, } @@ -192,17 +229,17 @@ impl Grid { // } } -impl From> for Grid { - fn from(input: Lines) -> Grid { +impl From for Grid { + fn from(input: T) -> Grid { let mut data = Vec::new(); let mut width = 0; - for line in input.map(|i| i.unwrap()) { + for line in input.split(b'\n').map(|i| i.unwrap()) { if width == 0 { width = line.len() as i64 } else if line.len() as i64 != width { panic!("Grids must have fixed length rows") } - data.extend_from_slice(line.as_bytes()); + data.extend_from_slice(&line); } Grid { data, width } } @@ -224,7 +261,7 @@ impl Display for Grid { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { for y in 0..self.height() { for x in 0..self.width() { - f.write_fmt(format_args!("{}", self.get(&(x as i64, y as i64)).unwrap() as char))?; + f.write_fmt(format_args!("{}", *self.get(&(x as i64, y as i64)).unwrap() as char))?; } f.write_char('\n')?; } @@ -236,13 +273,13 @@ impl Display for Grid { mod tests { use super::*; - static TEST_VECTOR: &str = &"ABCD + static TEST_VECTOR: &[u8] = b"ABCD EFGH IJKL FBCG"; fn unchecked_load() -> Grid { - Grid::from(Cursor::new(TEST_VECTOR).lines()) + Grid::from(TEST_VECTOR) } #[test] @@ -254,8 +291,8 @@ FBCG"; #[test] fn indexing() { let grid = unchecked_load(); - assert_eq!(grid.get(&(0, 0)), Some(b'A')); - assert_eq!(grid.get(&(3, 3)), Some(b'G')); + assert_eq!(grid.get(&(0, 0)), Some(b'A').as_ref()); + assert_eq!(grid.get(&(3, 3)), Some(b'G').as_ref()); assert_eq!(grid.get(&(-1, 0)), None); assert_eq!(grid.get(&(0, -1)), None); assert_eq!(grid.get(&(5, 0)), None); @@ -271,11 +308,11 @@ FBCG"; assert_eq!(grid.forward_slice(&(0, 2), 4), Some(b"IJKL".as_slice())); } - #[test] - fn window_compare() { - let grid = unchecked_load(); - assert_eq!(grid.window_compare(b"IJKL"), &[(0, 2)]); - assert_eq!(grid.window_compare(b"BC"), &[(1, 0), (1, 3)]); - assert_eq!(grid.window_compare(b"LF").len(), 0); - } + // #[test] + // fn window_compare() { + // let grid = unchecked_load(); + // assert_eq!(grid.window_compare(b"IJKL"), &[(0, 2)]); + // assert_eq!(grid.window_compare(b"BC"), &[(1, 0), (1, 3)]); + // assert_eq!(grid.window_compare(b"LF").len(), 0); + // } }