From bdc150d0ed7c94b49961bf89f8dbca6c7f204664 Mon Sep 17 00:00:00 2001 From: Andrew Glaze Date: Wed, 27 Dec 2023 09:04:34 -0500 Subject: [PATCH] day23 --- src/day15.rs | 4 +- src/day23.rs | 156 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 1 + 3 files changed, 159 insertions(+), 2 deletions(-) create mode 100644 src/day23.rs diff --git a/src/day15.rs b/src/day15.rs index cfe692e..270eb9b 100644 --- a/src/day15.rs +++ b/src/day15.rs @@ -47,10 +47,10 @@ fn part2(input: &Vec) -> usize { if let Some(position) = boxes[box_number].iter().position(|(l, _)| *l == *label) { let _ = std::mem::replace( &mut boxes[box_number][position], - (label.clone().to_string(), *focal_length as usize), + (label.to_string(), *focal_length as usize), ); } else { - boxes[box_number].push((label.clone().to_string(), *focal_length as usize)); + boxes[box_number].push((label.to_string(), *focal_length as usize)); } } else { panic!("invalid step AHHH {}", step) diff --git a/src/day23.rs b/src/day23.rs new file mode 100644 index 0000000..2a7db34 --- /dev/null +++ b/src/day23.rs @@ -0,0 +1,156 @@ +use std::collections::HashMap; + +use aoc_runner_derive::{aoc, aoc_generator}; + +const NEIGHBORS: &[(i64,i64)] = &[(-1,0),(0,1),(1,0),(0,-1)]; +use itertools::Itertools; + +#[aoc_generator(day23)] +fn parse(input: &str) -> Vec> { + input.lines().map(|x| x.chars().collect::>()).collect::>() +} + +fn dfs(graph: &HashMap<(usize,usize), Vec<(usize,usize,usize)>>, seen: &mut Vec>, (r,c): (usize, usize)) -> Option { + if r == seen.len() - 1 { + return Some(0); + } + let mut max_dist = None; + for &(rr, cc, d) in &graph[&(r,c)] { + if !seen[rr][cc] { + seen[rr][cc] = true; + if let Some(dist) = dfs(graph, seen, (rr,cc)) { + max_dist = Some(max_dist.unwrap_or(0).max(d+dist)) + } + seen[rr][cc] = false; + } + } + + max_dist +} + +#[aoc(day23, part1)] +fn part1(grid: &Vec>) -> usize { + let mut graph = HashMap::<_,Vec<_>>::new(); + for (r, c) in (0..grid.len()).cartesian_product(0..grid[0].len()) { + let neighbors = match grid[r][c] { + '#' => continue, + '.' => NEIGHBORS, + '^' => &NEIGHBORS[0..][..1], + '>' => &NEIGHBORS[1..][..1], + 'v' => &NEIGHBORS[2..][..1], + '<' => &NEIGHBORS[3..][..1], + _ => unreachable!(), + }; + let e = graph.entry((r,c)).or_default(); + + for (dr, dc) in neighbors { + let rr = (r as i64 + dr) as usize; + let cc = (c as i64 + dc) as usize; + if grid.get(rr).and_then(|row| row.get(cc)).is_some_and(|&t| t != '#') { + e.push((rr,cc,1)); + } + } + } + + let corridors = graph.iter() + .filter(|(_, n)| n.len() == 2) + .map(|(&node, _)| node) + .collect::>(); + + for (r,c) in corridors { + let neighbors = graph.remove(&(r,c)).unwrap(); + let (r1, c1, d1) = neighbors[0]; + let (r2, c2, d2) = neighbors[1]; + let n1 = graph.get_mut(&(r1,c1)).unwrap(); + if let Some(i) = n1.iter().position(|&(rr,cc,_)| (rr,cc) == (r,c)) { + n1[i] = (r2,c2,d1+d2); + } + let n2 = graph.get_mut(&(r2,c2)).unwrap(); + if let Some(i) = n2.iter().position(|&(rr,cc,_)| (rr,cc) == (r,c)) { + n2[i] = (r1,c1,d1+d2); + } + } + + dfs(&graph, &mut vec![vec![false; grid[0].len()]; grid.len()], (0,1)).unwrap() +} + +#[aoc(day23, part2)] +fn part2(grid: &Vec>) -> usize { + let mut graph = HashMap::<_,Vec<_>>::new(); + for (r, c) in (0..grid.len()).cartesian_product(0..grid[0].len()) { + let neighbors = match grid[r][c] { + '#' => continue, + _ => NEIGHBORS, + }; + let e = graph.entry((r,c)).or_default(); + + for (dr, dc) in neighbors { + let rr = (r as i64 + dr) as usize; + let cc = (c as i64 + dc) as usize; + if grid.get(rr).and_then(|row| row.get(cc)).is_some_and(|&t| t != '#') { + e.push((rr,cc,1)); + } + } + } + + let corridors = graph.iter() + .filter(|(_, n)| n.len() == 2) + .map(|(&node, _)| node) + .collect::>(); + + for (r,c) in corridors { + let neighbors = graph.remove(&(r,c)).unwrap(); + let (r1, c1, d1) = neighbors[0]; + let (r2, c2, d2) = neighbors[1]; + let n1 = graph.get_mut(&(r1,c1)).unwrap(); + if let Some(i) = n1.iter().position(|&(rr,cc,_)| (rr,cc) == (r,c)) { + n1[i] = (r2,c2,d1+d2); + } + let n2 = graph.get_mut(&(r2,c2)).unwrap(); + if let Some(i) = n2.iter().position(|&(rr,cc,_)| (rr,cc) == (r,c)) { + n2[i] = (r1,c1,d1+d2); + } + } + + dfs(&graph, &mut vec![vec![false; grid[0].len()]; grid.len()], (0,1)).unwrap() +} + + +#[cfg(test)] +mod tests { + use super::*; + + const EX: &str = r"#.##################### +#.......#########...### +#######.#########.#.### +###.....#.>.>.###.#.### +###v#####.#v#.###.#.### +###.>...#.#.#.....#...# +###v###.#.#.#########.# +###...#.#.#.......#...# +#####.#.#.#######.#.### +#.....#.#.#.......#...# +#.#####.#.#.#########v# +#.#...#...#...###...>.# +#.#.#v#######v###.###v# +#...#.>.#...>.>.#.###.# +#####v#.#.###v#.#.###.# +#.....#...#...#.#.#...# +#.#########.###.#.#.### +#...###...#...#...#.### +###.###.#.###v#####v### +#...#...#.#.>.>.#.>.### +#.###.###.#.###.#.#v### +#.....###...###...#...# +#####################.#"; + + #[test] + fn part1_example() { + assert_eq!(part1(&parse(EX)), 94); + } + + #[test] + fn part2_example() { + assert_eq!(part2(&parse(EX)), 154); + } +} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 68470b1..bbefed4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,4 @@ +mod day23; mod day22; mod day21; mod day20;