From 285cefa67002e2615e54d23d080e0ae781773818 Mon Sep 17 00:00:00 2001 From: Jan-Bulthuis Date: Sat, 21 Dec 2024 22:45:13 +0100 Subject: [PATCH] day21 faster than Dirk >:) --- aoc_2024/src/day21.rs | 119 ++++++++++++++++++++++++++++++++---------- 1 file changed, 92 insertions(+), 27 deletions(-) diff --git a/aoc_2024/src/day21.rs b/aoc_2024/src/day21.rs index 6377118..ea5f532 100644 --- a/aoc_2024/src/day21.rs +++ b/aoc_2024/src/day21.rs @@ -1,12 +1,12 @@ use aoc_runner_derive::{aoc, aoc_generator}; #[derive(Debug, Clone, Copy, PartialEq, Eq)] -struct Path { +struct Path { steps: usize, - path: [Option; 6], + path: [Option; 6], } -impl Path { +impl Path { fn new() -> Self { Self { steps: 0, @@ -14,7 +14,7 @@ impl Path { } } - fn push(&mut self, button: T) { + fn push(&mut self, button: DirButton) { self.path[self.steps] = Some(button); self.steps += 1; } @@ -24,11 +24,30 @@ impl Path { self.push(other.path[i].unwrap()); } } + + fn reversed(&self) -> Self { + let mut path = [None; 6]; + (0..self.steps).for_each(|i| { + path[i] = match self.path[self.steps - i - 1] { + Some(DirButton::Up) => Some(DirButton::Down), + Some(DirButton::Down) => Some(DirButton::Up), + Some(DirButton::Left) => Some(DirButton::Right), + Some(DirButton::Right) => Some(DirButton::Left), + Some(DirButton::A) => Some(DirButton::A), + None => None, + }; + }); + + Self { + steps: self.steps, + path, + } + } } -impl IntoIterator for Path { - type Item = T; - type IntoIter = std::iter::Flatten, 6>>; +impl IntoIterator for Path { + type Item = DirButton; + type IntoIter = std::iter::Flatten, 6>>; fn into_iter(self) -> Self::IntoIter { self.path.into_iter().flatten() @@ -65,7 +84,7 @@ impl DirButton { } } - fn to(&self, other: &DirButton) -> [Option>; 2] { + fn to(&self, other: &DirButton) -> [Option; 2] { let start = self.pos(); let end = other.pos(); @@ -134,7 +153,8 @@ impl NumButton { } } - fn to(&self, other: &NumButton) -> [Option>; 2] { + #[inline(always)] + fn to(&self, other: &NumButton) -> [Option; 2] { let start = self.pos(); let end = other.pos(); @@ -203,26 +223,67 @@ fn parse(input: &str) -> Input { type DistanceMatrix = [[usize; 5]; 5]; -fn calculate_steps(start: DirButton, end: DirButton, steps: &mut [DistanceMatrix]) -> usize { - if steps.is_empty() { - return 1; +fn precompute_steps(steps: &mut [DistanceMatrix]) { + if steps.len() == 1 { + return; } - if steps[0][start.index()][end.index()] == 0 { - let extension = start - .to(&end) - .into_iter() - .flatten() - .map(|path| shortest_dir_path(path, &mut steps[1..])) - .min() - .unwrap(); - steps[0][start.index()][end.index()] = extension; - } + precompute_steps(&mut steps[1..]); - steps[0][start.index()][end.index()] + let buttons = [ + DirButton::Up, + DirButton::Down, + DirButton::Left, + DirButton::Right, + DirButton::A, + ]; + + buttons.iter().enumerate().for_each(|(i, start)| { + buttons[i + 1..].iter().for_each(|end| { + let (forward, reversed) = start + .to(end) + .into_iter() + .flatten() + .map(|mut path| { + path.steps -= 1; + let mut reversed = path.reversed(); + let mut forward = path; + reversed.push(DirButton::A); + forward.push(DirButton::A); + + ( + forward + .path + .into_iter() + .flatten() + .fold((0, DirButton::A), |acc, next| { + let extension = steps[1][acc.1.index()][next.index()]; + + (acc.0 + extension, next) + }) + .0, + reversed + .path + .into_iter() + .flatten() + .fold((0, DirButton::A), |acc, next| { + let extension = steps[1][acc.1.index()][next.index()]; + + (acc.0 + extension, next) + }) + .0, + ) + }) + .fold((usize::MAX, usize::MAX), |acc, next| { + (acc.0.min(next.0), acc.1.min(next.1)) + }); + steps[0][start.index()][end.index()] = forward; + steps[0][end.index()][start.index()] = reversed; + }); + }); } -fn shortest_dir_path(path: Path, steps: &mut [DistanceMatrix]) -> usize { +fn shortest_dir_path(path: Path, steps: &mut [DistanceMatrix]) -> usize { path.path .into_iter() .flatten() @@ -230,7 +291,7 @@ fn shortest_dir_path(path: Path, steps: &mut [DistanceMatrix]) -> usi let sum = acc.0; let pos = acc.1; - let extension = calculate_steps(pos, next, steps); + let extension = steps[0][pos.index()][next.index()]; (sum + extension, next) }) @@ -257,7 +318,9 @@ fn shortest_path(path: Vec, steps: &mut [DistanceMatrix]) -> usize { #[aoc(day21, part1)] fn part1(input: &Input) -> usize { - let mut steps = vec![[[0; 5]; 5]; 3 - 1]; + let mut steps = vec![[[1; 5]; 5]; 3]; + + precompute_steps(&mut steps); input .iter() @@ -268,7 +331,9 @@ fn part1(input: &Input) -> usize { #[aoc(day21, part2)] fn part2(input: &Input) -> usize { - let mut steps = vec![[[0; 5]; 5]; 26 - 1]; + let mut steps = vec![[[1; 5]; 5]; 26]; + + precompute_steps(&mut steps); input .iter()