From 7647cd8487d4a20bc4d1e88ecccff10a018ad96c Mon Sep 17 00:00:00 2001 From: Bauke Date: Wed, 15 Dec 2021 18:11:19 +0100 Subject: [PATCH] Solve day 15! --- Cargo.toml | 1 + source/day_15/mod.rs | 105 +++++++++++++++++++++++++++++++++++++++++++ source/main.rs | 2 + 3 files changed, 108 insertions(+) create mode 100644 source/day_15/mod.rs diff --git a/Cargo.toml b/Cargo.toml index c295b2b..390479f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,3 +13,4 @@ path = "source/main.rs" [dependencies] color-eyre = "0.5.11" itertools = "0.10.1" +pathfinding = "3.0.5" diff --git a/source/day_15/mod.rs b/source/day_15/mod.rs new file mode 100644 index 0000000..c2dbfdc --- /dev/null +++ b/source/day_15/mod.rs @@ -0,0 +1,105 @@ +use std::collections::HashMap; + +use color_eyre::{eyre::eyre, Result}; +use pathfinding::prelude::{absdiff, astar}; + +pub fn solve() -> Result<()> { + let input_data = include_str!("../../data/day_15.txt").trim(); + println!("Day 15 Part 1: {}", part_1(input_data)?); + println!("Day 15 Part 2: {}", part_2(input_data)?); + Ok(()) +} + +type Grid = HashMap; + +#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] +struct Coordinate(isize, isize); + +impl Coordinate { + fn distance(&self, target: &Coordinate) -> isize { + absdiff(self.0, target.0) + absdiff(self.1, target.1) + } + + fn successors(&self, grid: &Grid) -> Vec<(Coordinate, isize)> { + let &Coordinate(x, y) = self; + let mut successors = vec![]; + + for coordinate in [ + Coordinate(x, y - 1), // Up + Coordinate(x - 1, y), // Left + Coordinate(x, y + 1), // Down + Coordinate(x + 1, y), // Right + ] { + if let Some(value) = grid.get(&coordinate) { + successors.push((coordinate, *value)); + } + } + + successors + } +} + +fn parse(input: &str) -> Result<(Grid, Coordinate)> { + let mut grid = Grid::new(); + let mut end = Coordinate(0, 0); + + for (y, line) in input.lines().enumerate() { + let y = (y + 1).try_into()?; + + for (x, character) in line.char_indices() { + let x = (x + 1).try_into()?; + grid.insert(Coordinate(x, y), character.to_string().parse()?); + + if end.0 < x && end.1 < y { + end = Coordinate(x, y); + } + } + } + + Ok((grid, end)) +} + +fn enlarge_grid(grid: Grid, end: Coordinate) -> (Grid, Coordinate) { + let Coordinate(width, height) = end; + let mut larger_grid = grid.clone(); + + for (Coordinate(x, y), risk) in grid { + for step_x in 0..5 { + for step_y in 0..5 { + let risk = match (risk + step_x + step_y) % 9 { + 0 => 9, + n => n, + }; + let x = x + (width * step_x); + let y = y + (height * step_y); + larger_grid.insert(Coordinate(x, y), risk); + } + } + } + + (larger_grid, Coordinate(width * 5, height * 5)) +} + +fn run(grid: Grid, end: Coordinate) -> Result { + Ok( + astar( + &Coordinate(1, 1), + |p| p.successors(&grid), + |p| p.distance(&end), + |p| p == &end, + ) + .ok_or_else(|| eyre!("No path found"))? + .1, + ) +} + +fn part_1(input: &str) -> Result { + let (grid, end) = parse(input)?; + run(grid, end) +} + +fn part_2(input: &str) -> Result { + let (grid, end) = parse(input)?; + let (grid, end) = enlarge_grid(grid, end); + run(grid, end) +} diff --git a/source/main.rs b/source/main.rs index 1860461..57f5cff 100644 --- a/source/main.rs +++ b/source/main.rs @@ -14,6 +14,7 @@ mod day_09; mod day_10; mod day_13; mod day_14; +mod day_15; fn main() -> Result<()> { color_eyre::install()?; @@ -33,6 +34,7 @@ fn main() -> Result<()> { day_10::solve, day_13::solve, day_14::solve, + day_15::solve, ]; for day in days {