From dfc41a1167cfa3109b67a5bdc6478493b9e0e3f4 Mon Sep 17 00:00:00 2001 From: Gabe Venberg Date: Mon, 20 Nov 2023 14:40:03 -0600 Subject: [PATCH] that *should* be day 9, and the example passes, but the real input is off!!! --- Cargo.lock | 7 + Cargo.toml | 4 +- aoc_libs/Cargo.toml | 6 + aoc_libs/src/lib.rs | 1 + aoc_libs/src/points.rs | 211 ++++ days/day09/Cargo.toml | 4 + days/day09/src/input.txt | 2000 ++++++++++++++++++++++++++++++++++++++ days/day09/src/main.rs | 6 +- days/day09/src/part1.rs | 47 +- days/day09/src/part2.rs | 18 +- days/day09/src/rope.rs | 166 +++- template/Cargo.toml | 1 + 12 files changed, 2422 insertions(+), 49 deletions(-) create mode 100644 aoc_libs/Cargo.toml create mode 100644 aoc_libs/src/lib.rs create mode 100644 aoc_libs/src/points.rs diff --git a/Cargo.lock b/Cargo.lock index d8e5af5..451aeb5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11,6 +11,10 @@ dependencies = [ "memchr", ] +[[package]] +name = "aoc_libs" +version = "0.1.0" + [[package]] name = "day01" version = "0.1.0" @@ -59,6 +63,9 @@ version = "0.1.0" [[package]] name = "day09" version = "0.1.0" +dependencies = [ + "aoc_libs", +] [[package]] name = "memchr" diff --git a/Cargo.toml b/Cargo.toml index 9063675..47faac1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,9 +1,10 @@ [workspace] members = [ "template", + "aoc_libs", "days/*", ] -default-members = [ "days/*" ] +default-members = [ "days/*", "aoc_libs" ] resolver = "2" [workspace.package] @@ -13,6 +14,7 @@ edition = "2021" description = "advent of code 2022 in rust" [workspace.dependencies] +aoc_libs = {path = "./aoc_libs"} regex = "1" once_cell = "1.16" thiserror = "1.0" diff --git a/aoc_libs/Cargo.toml b/aoc_libs/Cargo.toml new file mode 100644 index 0000000..63d082f --- /dev/null +++ b/aoc_libs/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "aoc_libs" +version.workspace = true +authors.workspace = true +edition.workspace = true +description.workspace = true diff --git a/aoc_libs/src/lib.rs b/aoc_libs/src/lib.rs new file mode 100644 index 0000000..2111939 --- /dev/null +++ b/aoc_libs/src/lib.rs @@ -0,0 +1 @@ +pub mod points; diff --git a/aoc_libs/src/points.rs b/aoc_libs/src/points.rs new file mode 100644 index 0000000..74a92c6 --- /dev/null +++ b/aoc_libs/src/points.rs @@ -0,0 +1,211 @@ +#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Hash)] +pub struct Point { + pub x: isize, + pub y: isize, +} + +impl Point { + /// converts a point (representing a point on a 4 quadrant grid with positive xy in the + /// top-right) into a upoint (representing a point on a 1 quadrant grid with the origin in the + /// top-left corner). Returns none if the resulting point would have either number negative. + pub fn to_upoint(self, zero_coord: &UPoint) -> Option { + Some(UPoint { + x: zero_coord.x.checked_add_signed(self.x)?, + y: zero_coord.y.checked_add_signed(-self.y)?, + }) + } +} + +impl std::ops::Add for Point { + type Output = Point; + + fn add(self, rhs: Self) -> Self::Output { + Self { + x: self.x + rhs.x, + y: self.y + rhs.y, + } + } +} + +impl std::ops::AddAssign for Point { + fn add_assign(&mut self, rhs: Self) { + *self = *self + rhs + } +} + +impl std::ops::Sub for Point { + type Output = Point; + + fn sub(self, rhs: Self) -> Self::Output { + Self { + x: self.x - rhs.x, + y: self.y - rhs.y, + } + } +} + +impl std::ops::SubAssign for Point { + fn sub_assign(&mut self, rhs: Self) { + *self = *self - rhs + } +} + +impl std::ops::Neg for Point { + type Output = Point; + + fn neg(self) -> Self::Output { + Point { + x: -self.x, + y: -self.y, + } + } +} + +/// an unsigned point in 2d space +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct UPoint { + pub x: usize, + pub y: usize, +} + +impl UPoint { + /// converts a upoint (representing a point on a 1 quadrant grid with the origin in the + /// top-left corner) into a point( representing a point on a 4 quadrant grid with positive xy + /// in the top-right) + pub fn to_point(self, zero_coord: &UPoint) -> Point { + Point { + x: -(zero_coord.x as isize - self.x as isize), + y: zero_coord.y as isize - self.y as isize, + } + } +} + +impl std::ops::Add for UPoint { + type Output = UPoint; + + fn add(self, rhs: Self) -> Self::Output { + Self { + x: self.x + rhs.x, + y: self.y + rhs.y, + } + } +} + +impl std::ops::AddAssign for UPoint { + fn add_assign(&mut self, rhs: Self) { + *self = *self + rhs + } +} + +impl std::ops::Sub for UPoint { + type Output = UPoint; + + fn sub(self, rhs: Self) -> Self::Output { + Self { + x: self.x - rhs.x, + y: self.y - rhs.y, + } + } +} + +impl std::ops::SubAssign for UPoint { + fn sub_assign(&mut self, rhs: Self) { + *self = *self - rhs + } +} + +/// A matrix that allows negative co-oordinates. Will panic if referencing out of bounds, just like +/// a normal 2d array. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct FourQuadrantMatrix { + matrix: [[T; X]; Y], + max_point: Point, + min_point: Point, + zero_coord: UPoint, +} + +impl FourQuadrantMatrix<{ X }, { Y }, T> +where + T: Copy, + T: Default, +{ + /// generates a new FourQuadrantMatrix with a given zero point (the point in the underlying 2d + /// array considered to be (0,0)) + pub fn new(zero_coord: UPoint) -> FourQuadrantMatrix<{ X }, { Y }, T> { + FourQuadrantMatrix { + matrix: [[T::default(); X]; Y], + max_point: UPoint { x: X - 1, y: 0 }.to_point(&zero_coord), + min_point: UPoint { x: 0, y: Y - 1 }.to_point(&zero_coord), + zero_coord, + } + } + + pub fn zero_coord(&self) -> UPoint { + self.zero_coord + } + + pub fn min_point(&self) -> Point { + self.min_point + } + + pub fn max_point(&self) -> Point { + self.max_point + } + + /// makes sure a point is in bounds and if not, brings it in bounds. + pub fn bound_point(&self, point: &mut Point) { + if point.x > self.max_point.x { + point.x = self.max_point.x + } + + if point.y > self.max_point.y { + point.y = self.max_point.y + } + + if point.x < self.min_point.x { + point.x = self.min_point.x + } + + if point.y < self.min_point.y { + point.y = self.min_point.y + } + } + + /// checks if the point is in bounds. + pub fn is_in_bounds(&self, point: &Point) -> bool { + point.x <= self.max_point.x + && point.y <= self.max_point.y + && point.x >= self.min_point.x + && point.y >= self.min_point.y + } + /// fills the matrix with the Ts default value. + pub fn reset_matrix(&mut self) { + self.matrix = [[T::default(); X]; Y]; + } +} + +impl std::ops::IndexMut for FourQuadrantMatrix<{ X }, { Y }, T> { + fn index_mut(&mut self, index: Point) -> &mut Self::Output { + let upoint = index + .to_upoint(&self.zero_coord) + .expect("would result in negative unsigned coordinate!"); + &mut self.matrix[upoint.y][upoint.x] + } +} + +impl std::ops::Index for FourQuadrantMatrix<{ X }, { Y }, T> { + type Output = T; + + fn index(&self, index: Point) -> &Self::Output { + let upoint = index + .to_upoint(&self.zero_coord) + .expect("would result in negative unsigned coordinate!"); + &self.matrix[upoint.y][upoint.x] + } +} + +impl From> for [[T; X]; Y] { + fn from(value: FourQuadrantMatrix<{ X }, { Y }, T>) -> Self { + value.matrix + } +} diff --git a/days/day09/Cargo.toml b/days/day09/Cargo.toml index 1aa04f3..ec42136 100644 --- a/days/day09/Cargo.toml +++ b/days/day09/Cargo.toml @@ -3,3 +3,7 @@ name = "day09" authors.workspace = true description.workspace = true version.workspace = true +edition.workspace = true + +[dependencies] +aoc_libs.workspace = true diff --git a/days/day09/src/input.txt b/days/day09/src/input.txt index e69de29..68e6657 100644 --- a/days/day09/src/input.txt +++ b/days/day09/src/input.txt @@ -0,0 +1,2000 @@ +D 1 +L 2 +D 2 +L 1 +R 1 +D 1 +R 2 +U 1 +R 1 +D 2 +R 1 +L 2 +U 1 +D 2 +R 1 +L 2 +R 1 +U 2 +D 2 +L 1 +U 2 +R 2 +D 1 +R 2 +D 1 +U 2 +D 2 +L 1 +U 1 +R 1 +D 1 +U 1 +D 1 +U 2 +L 2 +R 1 +U 1 +R 2 +L 2 +U 2 +R 1 +L 1 +U 1 +L 2 +R 1 +D 1 +L 1 +D 2 +U 1 +D 1 +R 1 +L 2 +D 1 +R 2 +L 2 +U 1 +D 2 +R 2 +D 1 +U 1 +R 2 +D 1 +L 1 +U 2 +R 2 +D 1 +U 2 +R 1 +D 2 +R 1 +D 1 +U 2 +R 2 +U 1 +R 1 +U 1 +L 1 +U 2 +D 1 +R 2 +D 2 +R 2 +D 1 +L 2 +D 2 +L 1 +R 1 +U 1 +D 2 +L 2 +D 2 +L 1 +D 2 +R 1 +D 1 +R 2 +L 2 +R 2 +D 2 +R 1 +D 2 +R 2 +U 2 +L 2 +R 1 +U 1 +R 1 +U 1 +D 1 +U 1 +R 2 +L 1 +R 1 +D 2 +U 3 +R 1 +L 2 +D 1 +R 3 +U 1 +D 2 +R 1 +D 1 +R 2 +L 1 +R 2 +L 2 +D 3 +R 3 +D 1 +U 2 +D 2 +R 1 +D 2 +R 1 +L 3 +D 1 +L 1 +R 2 +D 3 +R 2 +D 3 +R 3 +L 2 +U 3 +D 3 +L 2 +R 3 +L 1 +U 1 +L 2 +D 2 +U 1 +D 2 +U 1 +D 2 +R 1 +U 1 +D 2 +U 1 +L 1 +R 2 +L 2 +D 3 +U 2 +L 3 +D 2 +U 1 +D 3 +L 1 +U 1 +D 2 +R 2 +U 1 +L 2 +D 3 +L 3 +D 3 +U 1 +R 1 +U 2 +D 1 +R 3 +L 1 +D 1 +U 3 +D 1 +L 2 +U 1 +L 3 +D 2 +L 2 +R 1 +L 3 +U 3 +R 3 +U 1 +R 2 +D 1 +L 3 +U 3 +D 3 +L 2 +D 1 +U 2 +D 2 +U 2 +R 3 +U 2 +L 1 +U 1 +R 2 +L 3 +D 3 +U 3 +R 1 +L 1 +U 1 +D 1 +U 2 +R 1 +D 3 +L 1 +R 3 +L 4 +D 3 +R 2 +U 3 +R 1 +L 4 +R 1 +L 3 +R 3 +U 2 +D 1 +L 3 +D 4 +U 4 +L 3 +U 4 +R 4 +L 1 +R 4 +D 1 +R 1 +L 3 +R 3 +L 1 +R 4 +D 2 +L 3 +D 2 +U 1 +R 3 +D 2 +L 3 +R 4 +L 3 +U 3 +D 3 +R 1 +D 2 +U 4 +L 1 +R 1 +L 4 +R 3 +U 1 +L 4 +R 1 +U 3 +R 1 +L 1 +U 3 +R 3 +U 2 +R 2 +L 4 +U 1 +R 1 +D 3 +L 2 +D 1 +L 3 +R 3 +D 3 +L 4 +U 2 +L 3 +U 4 +L 2 +U 2 +D 4 +L 3 +D 1 +U 2 +L 3 +R 4 +U 1 +L 4 +R 4 +L 3 +U 2 +D 4 +L 1 +R 3 +D 2 +L 3 +U 1 +L 3 +U 4 +R 2 +U 2 +R 1 +D 2 +L 4 +R 3 +D 2 +L 3 +U 3 +D 3 +L 1 +D 4 +R 3 +U 1 +R 3 +L 1 +U 3 +R 2 +D 3 +L 3 +U 3 +L 3 +D 5 +U 4 +L 5 +D 2 +R 1 +D 2 +U 5 +R 1 +U 2 +D 2 +R 4 +U 2 +L 3 +U 2 +R 5 +D 4 +L 3 +U 3 +D 1 +R 2 +L 3 +U 1 +R 5 +D 1 +U 2 +R 1 +U 3 +L 2 +U 5 +R 4 +D 5 +L 4 +D 4 +L 2 +U 4 +R 5 +L 1 +D 1 +R 2 +U 2 +D 5 +R 2 +U 4 +L 3 +D 2 +R 4 +L 1 +R 1 +L 2 +U 4 +D 4 +R 5 +D 3 +R 1 +D 4 +L 4 +U 5 +L 2 +U 2 +L 3 +R 4 +U 5 +L 4 +U 2 +D 1 +R 2 +U 4 +L 1 +U 3 +R 1 +U 5 +D 5 +U 4 +D 3 +L 3 +U 3 +D 2 +U 4 +R 3 +D 1 +U 5 +D 3 +R 1 +U 2 +R 1 +D 4 +R 4 +L 4 +U 1 +L 5 +R 3 +D 2 +U 2 +L 5 +R 1 +L 1 +U 3 +D 4 +R 5 +L 4 +D 5 +L 2 +U 1 +D 1 +U 3 +R 4 +D 4 +L 4 +U 3 +L 2 +D 2 +L 5 +U 1 +R 6 +U 4 +R 3 +D 2 +R 6 +D 2 +R 6 +L 3 +R 4 +L 3 +D 5 +U 2 +R 5 +L 5 +R 4 +U 6 +R 6 +D 1 +U 4 +D 4 +L 3 +D 2 +U 5 +R 2 +U 5 +D 2 +U 3 +R 2 +D 5 +R 2 +D 6 +R 1 +U 5 +D 2 +L 6 +U 2 +L 4 +R 6 +L 6 +D 6 +L 3 +D 5 +L 1 +R 5 +D 4 +L 4 +U 1 +R 3 +D 6 +R 6 +U 2 +R 4 +D 1 +R 4 +U 4 +L 6 +U 6 +D 6 +R 2 +D 2 +L 4 +R 6 +L 1 +U 5 +D 4 +U 4 +R 3 +U 1 +D 3 +R 6 +D 4 +U 5 +R 3 +D 5 +R 5 +D 4 +U 4 +D 3 +U 6 +L 1 +D 4 +U 6 +L 3 +R 3 +D 6 +U 4 +R 3 +L 3 +R 1 +D 6 +R 4 +U 2 +R 6 +L 3 +D 3 +L 4 +R 3 +L 4 +R 3 +U 4 +R 3 +D 4 +R 6 +D 2 +U 1 +D 2 +L 3 +D 4 +L 1 +D 5 +L 6 +U 4 +L 7 +R 6 +U 7 +R 7 +L 5 +D 1 +U 3 +R 6 +U 6 +R 2 +U 5 +R 4 +U 7 +R 1 +L 3 +D 7 +L 4 +D 6 +U 1 +L 1 +R 3 +D 2 +L 5 +R 1 +U 1 +L 1 +R 6 +L 6 +D 2 +U 3 +L 6 +R 6 +L 3 +D 3 +R 2 +L 1 +U 5 +R 6 +D 2 +L 5 +U 1 +D 4 +R 3 +L 6 +R 2 +L 4 +D 4 +R 5 +D 3 +R 2 +L 5 +U 7 +D 5 +L 3 +R 2 +D 5 +U 5 +D 2 +U 2 +L 2 +R 5 +L 2 +D 5 +R 3 +U 4 +R 4 +D 1 +L 6 +U 2 +R 7 +L 3 +U 4 +D 2 +R 5 +L 6 +R 7 +L 1 +U 5 +L 3 +U 7 +D 6 +R 3 +D 3 +U 7 +L 4 +R 2 +U 1 +L 1 +R 6 +D 5 +R 7 +U 4 +D 2 +R 2 +D 4 +L 1 +U 4 +D 2 +R 2 +D 5 +U 7 +D 1 +U 7 +R 3 +U 5 +L 1 +R 7 +L 2 +R 5 +U 5 +R 5 +D 4 +U 5 +L 7 +D 3 +R 5 +L 3 +R 1 +U 8 +L 4 +U 3 +D 4 +U 1 +L 2 +D 5 +L 5 +D 4 +U 3 +L 2 +R 3 +D 6 +L 4 +U 3 +R 1 +U 1 +D 3 +R 5 +D 4 +L 7 +U 7 +R 7 +L 6 +D 7 +U 5 +L 2 +U 4 +R 8 +L 4 +U 4 +R 5 +U 1 +R 1 +D 7 +R 6 +L 8 +R 1 +D 4 +U 5 +R 6 +L 3 +R 7 +L 4 +D 7 +U 8 +R 5 +D 5 +U 4 +L 3 +D 4 +U 1 +L 8 +R 8 +U 2 +L 5 +R 7 +D 5 +L 5 +D 3 +L 5 +U 4 +D 1 +U 6 +R 7 +D 5 +R 4 +D 6 +U 4 +L 5 +D 8 +U 5 +L 7 +D 1 +U 8 +R 3 +U 4 +R 5 +U 7 +R 6 +L 3 +U 4 +L 7 +R 5 +U 6 +L 2 +R 2 +U 7 +R 4 +D 2 +L 2 +D 6 +L 5 +D 5 +L 1 +R 5 +D 1 +U 5 +L 8 +R 3 +D 4 +R 2 +U 2 +L 5 +D 4 +U 7 +D 9 +R 9 +U 9 +R 3 +L 2 +D 8 +U 6 +L 1 +R 1 +D 4 +L 9 +R 9 +L 3 +U 4 +D 7 +U 9 +D 5 +R 8 +D 6 +R 9 +U 2 +R 2 +U 8 +R 5 +U 6 +L 8 +D 7 +L 2 +U 3 +R 3 +U 6 +L 5 +R 4 +D 6 +U 6 +R 6 +D 5 +U 5 +D 6 +L 4 +D 2 +U 6 +L 8 +U 3 +D 6 +U 1 +L 7 +D 6 +R 3 +D 7 +U 6 +D 4 +U 5 +R 3 +D 7 +L 5 +U 6 +L 6 +R 2 +D 7 +L 7 +U 5 +D 9 +R 6 +L 9 +R 1 +L 6 +U 5 +R 4 +U 7 +L 2 +U 5 +L 9 +U 3 +R 2 +L 5 +R 2 +U 6 +L 3 +D 7 +R 9 +D 3 +L 4 +R 2 +D 8 +L 6 +D 9 +L 5 +D 1 +R 8 +D 4 +U 5 +L 7 +D 2 +R 2 +L 7 +D 6 +L 7 +R 1 +D 4 +U 3 +D 3 +U 8 +R 8 +L 3 +D 8 +U 7 +R 4 +D 9 +L 3 +U 10 +L 4 +D 4 +R 7 +U 1 +L 10 +U 10 +R 9 +U 3 +L 3 +R 1 +D 10 +L 4 +U 9 +L 4 +U 7 +L 8 +R 7 +D 1 +U 3 +L 3 +U 2 +R 4 +U 5 +D 9 +L 5 +U 10 +L 2 +U 1 +L 7 +D 9 +L 8 +R 10 +D 7 +U 9 +L 4 +U 10 +L 3 +U 1 +D 1 +L 1 +D 6 +U 8 +R 8 +L 6 +U 9 +L 3 +U 6 +R 6 +U 3 +R 7 +U 2 +D 4 +L 4 +R 8 +D 3 +R 8 +U 2 +R 3 +D 6 +U 4 +R 9 +L 4 +D 4 +L 6 +R 2 +D 10 +L 7 +R 9 +L 7 +D 8 +R 2 +D 2 +U 9 +R 2 +U 1 +R 10 +U 1 +D 2 +U 10 +D 10 +U 5 +R 3 +U 5 +R 10 +L 3 +R 5 +U 5 +L 4 +D 3 +L 7 +D 3 +U 10 +R 7 +L 3 +D 2 +L 1 +D 1 +L 7 +R 2 +L 10 +D 6 +R 4 +L 8 +R 9 +D 5 +L 2 +D 4 +R 1 +L 4 +R 8 +D 5 +R 10 +D 1 +L 10 +D 11 +L 10 +R 4 +L 3 +D 1 +U 4 +L 9 +D 6 +U 2 +R 4 +L 2 +U 5 +D 1 +R 6 +L 5 +U 7 +D 2 +R 5 +D 9 +R 11 +U 9 +D 9 +R 2 +L 9 +D 4 +U 7 +L 10 +D 7 +U 4 +D 1 +U 4 +D 10 +L 8 +D 3 +L 8 +D 8 +R 7 +D 10 +R 5 +U 1 +L 11 +D 2 +L 11 +U 4 +L 8 +D 10 +U 3 +D 11 +R 10 +L 1 +D 2 +U 11 +L 4 +U 2 +L 6 +D 7 +R 10 +L 2 +D 7 +R 9 +U 6 +D 5 +R 9 +U 1 +D 3 +R 8 +D 7 +L 3 +D 8 +U 4 +D 4 +R 8 +L 7 +R 1 +D 3 +U 7 +D 4 +L 10 +R 1 +D 6 +R 1 +L 5 +D 2 +L 9 +R 1 +U 5 +D 4 +U 11 +L 6 +R 11 +D 11 +R 6 +U 9 +R 1 +L 5 +U 3 +R 10 +L 8 +R 6 +L 2 +R 8 +D 11 +L 5 +R 3 +L 1 +R 3 +L 8 +R 10 +U 2 +R 2 +D 7 +L 9 +U 2 +L 8 +D 3 +U 1 +L 11 +D 1 +U 6 +L 2 +R 7 +D 5 +R 1 +D 11 +U 12 +D 10 +L 11 +U 3 +D 10 +L 6 +U 3 +D 12 +R 4 +D 9 +R 2 +U 12 +R 11 +L 2 +R 7 +L 11 +U 12 +R 12 +U 1 +R 2 +D 8 +R 10 +U 2 +D 8 +U 8 +D 5 +U 10 +R 4 +U 8 +D 4 +R 8 +D 8 +R 2 +U 4 +L 10 +D 2 +L 10 +R 2 +D 9 +U 6 +L 2 +D 10 +L 2 +D 11 +R 11 +U 2 +L 6 +D 3 +U 3 +R 4 +U 9 +L 9 +R 8 +D 5 +L 9 +U 8 +L 11 +D 8 +R 12 +U 1 +D 1 +U 7 +L 11 +U 2 +L 12 +R 11 +U 8 +R 12 +U 11 +L 7 +U 5 +L 4 +R 4 +D 1 +U 6 +D 7 +U 5 +R 5 +U 10 +D 2 +R 9 +L 12 +D 9 +U 6 +L 11 +D 7 +L 6 +D 10 +L 9 +D 11 +R 7 +D 10 +L 1 +R 9 +D 10 +L 1 +U 1 +L 13 +R 10 +D 9 +L 9 +U 7 +L 10 +R 1 +U 12 +R 13 +U 8 +L 9 +U 5 +L 11 +D 11 +U 8 +R 2 +D 2 +R 7 +D 3 +L 3 +R 2 +L 6 +U 11 +L 6 +U 8 +L 11 +U 12 +L 13 +D 4 +L 8 +U 11 +D 9 +U 11 +D 10 +U 4 +D 9 +L 12 +D 6 +L 11 +U 11 +L 1 +D 6 +R 12 +U 9 +D 1 +L 4 +R 9 +L 13 +R 10 +D 9 +L 2 +R 3 +D 10 +L 13 +R 3 +L 8 +R 8 +L 1 +R 5 +L 12 +D 10 +R 6 +U 7 +R 11 +U 11 +R 10 +D 9 +R 12 +D 8 +U 6 +L 8 +D 6 +L 10 +R 2 +L 2 +D 12 +U 12 +R 11 +L 8 +U 2 +R 2 +L 11 +U 11 +L 7 +D 2 +U 2 +L 9 +D 4 +R 2 +U 7 +D 3 +R 1 +D 6 +U 13 +R 11 +D 1 +U 4 +R 9 +D 7 +L 12 +U 12 +L 10 +U 9 +L 1 +D 1 +U 6 +L 1 +D 13 +U 14 +L 2 +D 6 +U 8 +D 8 +L 9 +D 1 +R 11 +D 6 +L 8 +R 11 +U 4 +L 5 +R 5 +D 10 +U 10 +R 7 +D 7 +L 8 +U 9 +R 1 +L 5 +D 4 +L 13 +D 4 +R 14 +D 13 +R 9 +L 13 +R 7 +L 14 +R 12 +D 1 +U 8 +L 10 +U 7 +D 9 +U 7 +D 13 +L 1 +R 1 +D 14 +L 9 +U 5 +R 7 +U 2 +L 11 +D 5 +U 7 +D 1 +L 13 +U 14 +L 1 +D 3 +R 3 +D 1 +L 3 +U 4 +R 14 +U 11 +R 4 +L 13 +U 3 +R 8 +D 5 +U 8 +L 6 +R 14 +L 3 +D 2 +L 5 +U 11 +R 8 +L 11 +U 8 +D 11 +U 14 +R 14 +L 4 +D 10 +R 11 +U 1 +D 4 +U 11 +D 5 +L 5 +R 14 +U 12 +L 1 +D 4 +R 11 +L 5 +R 9 +U 9 +D 2 +U 12 +D 2 +R 8 +U 6 +L 11 +U 8 +L 6 +U 9 +L 5 +U 3 +D 10 +R 10 +D 6 +U 1 +R 13 +U 5 +R 8 +U 11 +L 11 +D 10 +R 11 +U 2 +D 3 +R 10 +D 2 +L 9 +R 7 +L 8 +U 1 +R 6 +L 3 +D 10 +U 14 +D 4 +U 7 +L 6 +R 8 +U 15 +D 14 +U 5 +D 15 +U 2 +D 4 +L 11 +U 8 +L 10 +U 15 +R 8 +U 14 +D 6 +R 9 +L 15 +R 9 +L 11 +R 3 +D 2 +U 10 +L 12 +D 2 +L 5 +D 1 +R 8 +U 7 +L 7 +D 7 +L 15 +D 11 +U 3 +L 4 +U 10 +L 14 +U 10 +D 10 +U 11 +D 1 +L 3 +R 11 +L 3 +U 10 +L 2 +D 8 +R 8 +L 12 +D 15 +U 10 +L 14 +R 4 +L 9 +R 11 +U 10 +R 7 +D 13 +U 11 +D 10 +R 3 +U 6 +R 9 +L 15 +R 11 +D 6 +R 14 +L 7 +D 7 +L 3 +D 13 +U 10 +R 14 +U 2 +D 4 +U 1 +R 1 +D 8 +R 12 +L 15 +R 4 +L 15 +U 13 +D 12 +L 8 +D 1 +R 3 +U 11 +R 3 +U 2 +R 4 +D 15 +U 4 +L 6 +D 6 +L 9 +D 2 +L 15 +R 5 +U 2 +R 7 +D 7 +U 15 +L 4 +D 7 +R 9 +D 11 +R 8 +L 4 +R 6 +L 11 +U 16 +L 10 +U 10 +L 11 +U 9 +R 8 +U 13 +R 13 +L 5 +R 8 +L 12 +U 11 +L 4 +D 10 +R 2 +U 13 +R 4 +L 15 +D 15 +L 15 +R 16 +L 7 +R 14 +D 5 +L 16 +U 6 +D 3 +L 13 +D 8 +L 11 +U 13 +L 9 +U 6 +L 4 +U 11 +R 1 +L 13 +R 11 +L 13 +R 13 +L 9 +D 15 +R 1 +L 15 +R 14 +L 14 +U 7 +L 1 +R 6 +D 16 +L 2 +R 12 +L 4 +D 12 +R 8 +U 9 +D 10 +R 1 +L 2 +D 5 +L 3 +R 15 +L 8 +D 1 +L 1 +D 8 +U 13 +R 1 +L 2 +D 1 +R 3 +L 6 +U 12 +L 4 +D 13 +U 2 +L 4 +D 10 +R 16 +D 1 +U 1 +L 11 +D 8 +L 12 +R 8 +L 5 +R 1 +D 12 +R 2 +D 7 +U 16 +D 11 +L 15 +R 4 +U 4 +D 4 +U 4 +L 17 +U 3 +D 8 +U 1 +L 1 +U 4 +L 7 +U 9 +L 13 +D 10 +L 2 +U 7 +L 13 +D 16 +U 6 +L 10 +D 16 +L 8 +U 10 +L 6 +U 16 +L 5 +U 4 +R 9 +D 12 +R 1 +U 14 +L 14 +R 16 +D 5 +L 16 +R 14 +U 10 +R 4 +U 9 +L 15 +D 4 +U 15 +L 11 +R 14 +L 10 +D 14 +L 10 +D 12 +R 2 +D 3 +R 1 +U 1 +L 17 +U 9 +D 13 +R 7 +D 7 +U 13 +D 1 +R 14 +U 10 +R 16 +L 17 +R 7 +D 17 +U 11 +L 2 +U 16 +L 8 +U 13 +R 17 +U 5 +L 7 +R 3 +D 17 +L 10 +U 9 +D 16 +R 3 +U 5 +L 15 +R 16 +D 11 +U 9 +L 3 +R 14 +D 4 +L 4 +U 12 +D 9 +U 10 +D 15 +L 12 +R 6 +D 4 +L 14 +D 5 +L 4 +U 7 +R 15 +D 6 +L 15 +U 14 +D 10 +L 3 +D 9 +L 15 +R 9 +U 1 +L 4 +D 15 +U 12 +D 9 +R 8 +D 14 +R 15 +D 7 +U 18 +L 5 +U 6 +L 6 +D 10 +L 18 +R 3 +L 11 +D 10 +L 13 +U 13 +L 13 +R 3 +L 1 +U 3 +D 7 +L 9 +R 6 +U 18 +R 18 +U 15 +R 9 +U 4 +R 12 +L 12 +D 6 +U 10 +D 13 +L 6 +R 13 +L 13 +D 12 +U 4 +D 15 +L 12 +D 10 +U 12 +R 8 +L 13 +D 11 +L 13 +U 12 +D 5 +U 12 +R 10 +L 9 +U 13 +R 7 +D 2 +L 6 +U 13 +D 15 +R 3 +U 4 +D 5 +L 2 +D 10 +U 7 +L 2 +D 5 +L 5 +D 11 +R 5 +U 18 +L 9 +D 8 +U 12 +R 3 +U 8 +R 14 +D 1 +R 4 +L 5 +D 10 +R 18 +D 2 +R 9 +L 14 +U 4 +R 15 +D 4 +R 2 +L 4 +U 13 +R 6 +U 18 +D 4 +U 7 +L 15 +D 1 +L 6 +D 3 +U 15 +L 17 +U 15 +R 14 +L 9 +U 5 +L 4 +U 13 +R 5 +D 17 +U 17 +L 15 +U 14 +R 5 +L 1 +R 9 +U 8 +R 15 +U 18 +L 12 +R 13 +D 15 +R 5 +L 11 +R 5 +U 12 +R 8 +L 6 +R 1 +L 10 +U 17 +L 16 +U 12 +L 14 +D 16 +U 13 +D 18 +L 5 +U 16 +L 11 +D 15 +U 2 +L 9 +D 5 +L 17 +D 17 +L 4 +D 4 +L 19 +R 6 +D 6 +U 18 +R 16 +U 12 +D 2 +L 4 +U 19 +R 6 +U 1 +D 15 +R 13 +U 18 +D 12 +L 9 +U 1 +R 13 +D 18 +L 4 +D 17 +L 9 +D 8 +U 3 +D 5 +R 7 +L 16 +U 3 +L 1 +D 13 +R 17 +D 8 +R 9 +U 17 +L 2 +U 17 +D 16 +L 8 +R 9 +D 7 +L 16 +R 10 +L 16 +D 10 +L 15 +U 17 +L 2 +U 10 +D 16 +R 1 +L 2 +D 4 +R 13 +L 12 +D 8 +U 10 +L 6 +D 14 +L 6 +D 11 +R 1 +D 10 +L 18 +D 12 +R 14 +L 3 +D 7 +L 12 +R 19 +U 5 +R 19 +D 3 +L 15 +U 13 diff --git a/days/day09/src/main.rs b/days/day09/src/main.rs index 90fb2cd..bfe732a 100644 --- a/days/day09/src/main.rs +++ b/days/day09/src/main.rs @@ -10,8 +10,8 @@ fn main() { let structured_input = parse::parse(input); println!("Part One"); - println!("Result: {}", part1::part1()); + println!("Result: {}", part1::part1(&structured_input)); - println!("Part Two"); - println!("Result: {}", part2::part2()); + // println!("Part Two"); + // println!("Result: {}", part2::part2(&structured_input)); } diff --git a/days/day09/src/part1.rs b/days/day09/src/part1.rs index c268965..92134a6 100644 --- a/days/day09/src/part1.rs +++ b/days/day09/src/part1.rs @@ -1,8 +1,19 @@ -//TODO: -#![allow(unused)] +use std::collections::HashSet; -pub fn part1() -> usize { - unimplemented!() +use aoc_libs::points::Point; + +use crate::parse::Direction; +use crate::rope::Rope; + +pub fn part1(input: &Vec) -> usize { + let mut visited: HashSet = HashSet::new(); + let mut rope: Rope<2> = Rope::new(); + visited.insert(*rope.get_tail_pos()); + for direction in input { + rope.update_rope(direction); + visited.insert(*rope.get_tail_pos()); + } + visited.len() } #[cfg(test)] @@ -11,6 +22,32 @@ mod tests { #[test] fn test_part1() { - assert_eq!(0, 0); + let input = vec![ + Direction::Right, + Direction::Right, + Direction::Right, + Direction::Right, + Direction::Up, + Direction::Up, + Direction::Up, + Direction::Up, + Direction::Left, + Direction::Left, + Direction::Left, + Direction::Down, + Direction::Right, + Direction::Right, + Direction::Right, + Direction::Right, + Direction::Down, + Direction::Left, + Direction::Left, + Direction::Left, + Direction::Left, + Direction::Left, + Direction::Right, + Direction::Right, + ]; + assert_eq!(part1(&input), 13); } } diff --git a/days/day09/src/part2.rs b/days/day09/src/part2.rs index b45d3f6..18ae9ef 100644 --- a/days/day09/src/part2.rs +++ b/days/day09/src/part2.rs @@ -1,8 +1,18 @@ -//TODO: -#![allow(unused)] +use std::collections::HashSet; -pub fn part2() -> usize { - unimplemented!() +use aoc_libs::points::Point; + +use crate::{rope::Rope, parse::Direction}; + +pub fn part2(input: &Vec) -> usize { + let mut visited: HashSet = HashSet::new(); + let mut rope: Rope<10> = Rope::new(); + for direction in input { + visited.insert(*rope.get_tail_pos()); + rope.update_rope(direction); + println!("{}", rope) + } + visited.len() } #[cfg(test)] diff --git a/days/day09/src/rope.rs b/days/day09/src/rope.rs index 6c41300..94bd527 100644 --- a/days/day09/src/rope.rs +++ b/days/day09/src/rope.rs @@ -1,53 +1,48 @@ +use std::fmt::Display; + use crate::parse::Direction; -#[derive(Debug, Clone, Copy)] -struct Point { - x: isize, - y: isize, -} - -impl std::ops::Add for Point { - type Output = Point; - - fn add(self, rhs: Self) -> Self::Output { - Self { - x: self.x + rhs.x, - y: self.y + rhs.y, - } - } -} - -impl std::ops::Sub for Point { - type Output = Point; - - fn sub(self, rhs: Self) -> Self::Output { - Self { - x: self.x - rhs.x, - y: self.y - rhs.y, - } - } -} +use aoc_libs::points::{Point, UPoint}; // L is the length of the rope in segments. #[derive(Debug)] -struct Rope { +pub struct Rope { segments: [Point; L], } impl Rope { - pub fn new()->Rope{ - Rope { segments: () } + pub fn new() -> Rope { + Rope { + segments: [Point::default(); L], + } } - pub fn update_rope(&mut self, direction: Direction) { - todo!() + pub fn update_rope(&mut self, direction: &Direction) { + self.segments[0] += match direction { + Direction::Up => Point { x: 0, y: 1 }, + Direction::Right => Point { x: 1, y: 0 }, + Direction::Down => Point { x: 0, y: -1 }, + Direction::Left => Point { x: -1, y: 0 }, + }; + println!("direction is {:?}", direction); + for segment in 1..self.segments.len() { + self.segments[segment] += Rope::::update_single_segment_pair( + &self.segments[segment - 1], + &self.segments[segment], + ) + } + println!("{}", self); } - pub fn get_tail_pos(&self)->&Point{ - &self.segments[self.segments.len()-1] + pub fn get_tail_pos(&self) -> &Point { + &self.segments[self.segments.len() - 1] } - fn update_single_segment_pair(head: Point, tail: Point) -> Point { - let delta = head - tail; + // the rope segment will not move if the segment ahead of it is only at most one away, and will + // move with the following rules if it is 2 away: It moves straight towards the head if the + // head is directly up/down/left/right, and diagonally towards it if its not straight + // up/down/left/right. + fn update_single_segment_pair(head: &Point, tail: &Point) -> Point { + let delta = *head - *tail; if delta.x.abs() > 2 || delta.y.abs() > 2 { panic!("invalid delta ({}, {})", delta.y, delta.x) } @@ -64,3 +59,102 @@ impl Rope { } } } + +impl Display for Rope<{ L }> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let grid_size = (self.segments.len() * 2) - 1; + let zero_point = UPoint { + x: self.segments.len() - 1, + y: self.segments.len() - 1, + }; + + let mut grid: Vec> = Vec::with_capacity(grid_size); + for y in 0..grid_size { + grid.push(Vec::with_capacity(grid_size)); + for _ in 0..grid_size { + grid[y].push('.') + } + } + + for segment in self.segments.iter().skip(1) { + let delta = *segment-self.segments[0]; + let upoint = delta.to_upoint(&zero_point).unwrap(); + grid[upoint.y][upoint.x] = 'T' + } + + writeln!( + f, + "head is at {}, {}", + self.segments[0].x, self.segments[0].y + )?; + let upoint = Point { x: 0, y: 0 }.to_upoint(&zero_point).unwrap(); + grid[upoint.y][upoint.x] = 'H'; + + for line in grid { + let mut writeline = "".to_string(); + for char in line { + writeline.push(char) + } + writeln!(f, "{}", writeline)?; + } + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use std::collections::HashSet; + + use super::*; + + #[test] + fn test_single_segment() { + let input = [ + Direction::Right, + Direction::Right, + Direction::Right, + Direction::Right, + Direction::Up, + Direction::Up, + Direction::Up, + Direction::Up, + Direction::Left, + Direction::Left, + Direction::Left, + Direction::Down, + Direction::Right, + Direction::Right, + Direction::Right, + Direction::Right, + Direction::Down, + Direction::Left, + Direction::Left, + Direction::Left, + Direction::Left, + Direction::Left, + Direction::Right, + Direction::Right, + ]; + let mut visited: HashSet = HashSet::new(); + let mut rope: Rope<2> = Rope::new(); + visited.insert(*rope.get_tail_pos()); + for direction in input { + rope.update_rope(&direction); + visited.insert(*rope.get_tail_pos()); + } + // let mut graph = [ + // ['.', '.', '.', '.', '.', '.'], + // ['.', '.', '.', '.', '.', '.'], + // ['.', '.', '.', '.', '.', '.'], + // ['.', '.', '.', '.', '.', '.'], + // ['s', '.', '.', '.', '.', '.'], + // ]; + // for point in &visited { + // graph[4 - point.y as usize][point.x as usize] = '#'; + // } + // for line in graph { + // println!("{:?}", line) + // } + assert_eq!(visited.len(), 13) + } +} diff --git a/template/Cargo.toml b/template/Cargo.toml index b79bb50..987a9a3 100644 --- a/template/Cargo.toml +++ b/template/Cargo.toml @@ -3,3 +3,4 @@ name = "template" authors.workspace = true description.workspace = true version.workspace = true +edition.workspace = true