Implement 2023 day 23 part 2

This commit is contained in:
2023-12-24 14:17:06 +01:00
parent f9c977ab33
commit 9cc64a7904

View File

@@ -12,6 +12,13 @@ enum Slope {
} }
impl 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 { fn combine(self, other: Self) -> Self {
match (self, other) { match (self, other) {
(Slope::Level, next) | (next, Slope::Level) => next, (Slope::Level, next) | (next, Slope::Level) => next,
@@ -25,7 +32,7 @@ impl Slope {
} }
} }
fn simplify_graph(input: &[u8]) -> anyhow::Result<Vec<Vec<(usize, u32)>>> { fn simplify_graph(input: &[u8]) -> anyhow::Result<Vec<Vec<(Slope, usize, u32)>>> {
let map = Grid::new(input)?; let map = Grid::new(input)?;
let width = map.width(); let width = map.width();
let height = map.height(); let height = map.height();
@@ -76,12 +83,8 @@ fn simplify_graph(input: &[u8]) -> anyhow::Result<Vec<Vec<(usize, u32)>>> {
return; return;
} }
if matches!(slope, Slope::Down | Slope::Level) { graph[id].push((slope, other, dist + 1));
graph[id].push((other, dist + 1)); graph[other].push((slope.invert(), id, dist + 1));
}
if matches!(slope, Slope::Up | Slope::Level) {
graph[other].push((id, dist + 1));
}
} else if visited.insert(x + y * width) { } else if visited.insert(x + y * width) {
let tile_slope = if map[(y, x)] == up { let tile_slope = if map[(y, x)] == up {
Slope::Up Slope::Up
@@ -96,12 +99,8 @@ fn simplify_graph(input: &[u8]) -> anyhow::Result<Vec<Vec<(usize, u32)>>> {
let new_id = graph.len(); let new_id = graph.len();
nodes.insert((x, y), new_id); nodes.insert((x, y), new_id);
graph.push(Vec::new()); graph.push(Vec::new());
if matches!(slope, Slope::Down | Slope::Level) { graph[id].push((slope, new_id, dist + 1));
graph[id].push((new_id, dist + 1)); graph[new_id].push((slope.invert(), id, dist + 1));
}
if matches!(slope, Slope::Up | Slope::Level) {
graph[new_id].push((id, dist + 1));
}
todo_junctions.push((new_id, x, y)); todo_junctions.push((new_id, x, y));
} else { } else {
@@ -122,7 +121,7 @@ fn simplify_graph(input: &[u8]) -> anyhow::Result<Vec<Vec<(usize, u32)>>> {
fn longest_path( fn longest_path(
pos: usize, pos: usize,
travelled: u32, travelled: u32,
graph: &[Vec<(usize, u32)>], graph: &[Vec<(Slope, usize, u32)>],
visited: &mut HashSet<usize>, visited: &mut HashSet<usize>,
) -> u32 { ) -> u32 {
if pos == 1 { if pos == 1 {
@@ -131,8 +130,8 @@ fn longest_path(
let mut best = 0; let mut best = 0;
for &(other, dist) in &graph[pos] { for &(slope, other, dist) in &graph[pos] {
if visited.insert(other) { if !matches!(slope, Slope::Up) && visited.insert(other) {
best = Ord::max(best, longest_path(other, travelled + dist, graph, visited)); best = Ord::max(best, longest_path(other, travelled + dist, graph, visited));
visited.remove(&other); visited.remove(&other);
} }
@@ -147,8 +146,35 @@ pub fn part1(input: &[u8]) -> anyhow::Result<String> {
Ok(longest_path(0, 0, &graph, &mut HashSet::new()).to_string()) Ok(longest_path(0, 0, &graph, &mut HashSet::new()).to_string())
} }
pub fn part2(_input: &[u8]) -> anyhow::Result<String> { fn longer_longest_path(
anyhow::bail!("Not implemented") pos: usize,
travelled: u32,
graph: &[Vec<(Slope, usize, u32)>],
visited: &mut HashSet<usize>,
) -> 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<String> {
let graph = simplify_graph(input)?;
Ok(longer_longest_path(0, 0, &graph, &mut HashSet::new()).to_string())
} }
#[cfg(test)] #[cfg(test)]
@@ -161,4 +187,9 @@ mod tests {
fn sample_part1() { fn sample_part1() {
assert_eq!("94", part1(SAMPLE).unwrap()); assert_eq!("94", part1(SAMPLE).unwrap());
} }
#[test]
fn sample_part2() {
assert_eq!("154", part2(SAMPLE).unwrap());
}
} }