From 9cc64a7904758f77ac341d1bc2540bb4a7520c50 Mon Sep 17 00:00:00 2001 From: Bert Peters Date: Sun, 24 Dec 2023 14:17:06 +0100 Subject: [PATCH] Implement 2023 day 23 part 2 --- 2023/src/day23.rs | 67 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 49 insertions(+), 18 deletions(-) diff --git a/2023/src/day23.rs b/2023/src/day23.rs index 58f95c1..1a14652 100644 --- a/2023/src/day23.rs +++ b/2023/src/day23.rs @@ -12,6 +12,13 @@ enum Slope { } impl Slope { + fn invert(self) -> Self { + match self { + Slope::Level => Self::Level, + Slope::Up => Self::Down, + Slope::Down => Self::Up, + } + } fn combine(self, other: Self) -> Self { match (self, other) { (Slope::Level, next) | (next, Slope::Level) => next, @@ -25,7 +32,7 @@ impl Slope { } } -fn simplify_graph(input: &[u8]) -> anyhow::Result>> { +fn simplify_graph(input: &[u8]) -> anyhow::Result>> { let map = Grid::new(input)?; let width = map.width(); let height = map.height(); @@ -76,12 +83,8 @@ fn simplify_graph(input: &[u8]) -> anyhow::Result>> { return; } - if matches!(slope, Slope::Down | Slope::Level) { - graph[id].push((other, dist + 1)); - } - if matches!(slope, Slope::Up | Slope::Level) { - graph[other].push((id, dist + 1)); - } + graph[id].push((slope, other, dist + 1)); + graph[other].push((slope.invert(), id, dist + 1)); } else if visited.insert(x + y * width) { let tile_slope = if map[(y, x)] == up { Slope::Up @@ -96,12 +99,8 @@ fn simplify_graph(input: &[u8]) -> anyhow::Result>> { let new_id = graph.len(); nodes.insert((x, y), new_id); graph.push(Vec::new()); - if matches!(slope, Slope::Down | Slope::Level) { - graph[id].push((new_id, dist + 1)); - } - if matches!(slope, Slope::Up | Slope::Level) { - graph[new_id].push((id, dist + 1)); - } + graph[id].push((slope, new_id, dist + 1)); + graph[new_id].push((slope.invert(), id, dist + 1)); todo_junctions.push((new_id, x, y)); } else { @@ -122,7 +121,7 @@ fn simplify_graph(input: &[u8]) -> anyhow::Result>> { fn longest_path( pos: usize, travelled: u32, - graph: &[Vec<(usize, u32)>], + graph: &[Vec<(Slope, usize, u32)>], visited: &mut HashSet, ) -> u32 { if pos == 1 { @@ -131,8 +130,8 @@ fn longest_path( let mut best = 0; - for &(other, dist) in &graph[pos] { - if visited.insert(other) { + for &(slope, other, dist) in &graph[pos] { + if !matches!(slope, Slope::Up) && visited.insert(other) { best = Ord::max(best, longest_path(other, travelled + dist, graph, visited)); visited.remove(&other); } @@ -147,8 +146,35 @@ pub fn part1(input: &[u8]) -> anyhow::Result { Ok(longest_path(0, 0, &graph, &mut HashSet::new()).to_string()) } -pub fn part2(_input: &[u8]) -> anyhow::Result { - anyhow::bail!("Not implemented") +fn longer_longest_path( + pos: usize, + travelled: u32, + graph: &[Vec<(Slope, usize, u32)>], + visited: &mut HashSet, +) -> u32 { + if pos == 1 { + return travelled; + } + + let mut best = 0; + + for &(_, other, dist) in &graph[pos] { + if visited.insert(other) { + best = Ord::max( + best, + longer_longest_path(other, travelled + dist, graph, visited), + ); + visited.remove(&other); + } + } + + best +} + +pub fn part2(input: &[u8]) -> anyhow::Result { + let graph = simplify_graph(input)?; + + Ok(longer_longest_path(0, 0, &graph, &mut HashSet::new()).to_string()) } #[cfg(test)] @@ -161,4 +187,9 @@ mod tests { fn sample_part1() { assert_eq!("94", part1(SAMPLE).unwrap()); } + + #[test] + fn sample_part2() { + assert_eq!("154", part2(SAMPLE).unwrap()); + } }