From c6ca78cbef536101dc32480c6376141e36738e6b Mon Sep 17 00:00:00 2001 From: Andrew Coleman Date: Thu, 29 Feb 2024 11:47:19 -0500 Subject: [PATCH] day 23 solution --- 2023/data/examples/23.txt | 23 +++++ 2023/src/bin/23.rs | 200 ++++++++++++++++++++++++++++++++++++-- 2 files changed, 217 insertions(+), 6 deletions(-) diff --git a/2023/data/examples/23.txt b/2023/data/examples/23.txt index e69de29..ea945a4 100644 --- a/2023/data/examples/23.txt +++ b/2023/data/examples/23.txt @@ -0,0 +1,23 @@ +#.##################### +#.......#########...### +#######.#########.#.### +###.....#.>.>.###.#.### +###v#####.#v#.###.#.### +###.>...#.#.#.....#...# +###v###.#.#.#########.# +###...#.#.#.......#...# +#####.#.#.#######.#.### +#.....#.#.#.......#...# +#.#####.#.#.#########v# +#.#...#...#...###...>.# +#.#.#v#######v###.###v# +#...#.>.#...>.>.#.###.# +#####v#.#.###v#.#.###.# +#.....#...#...#.#.#...# +#.#########.###.#.#.### +#...###...#...#...#.### +###.###.#.###v#####v### +#...#...#.#.>.>.#.>.### +#.###.###.#.###.#.#v### +#.....###...###...#...# +#####################.# diff --git a/2023/src/bin/23.rs b/2023/src/bin/23.rs index 6c6a946..0cb9210 100644 --- a/2023/src/bin/23.rs +++ b/2023/src/bin/23.rs @@ -1,11 +1,199 @@ advent_of_code::solution!(23); -pub fn part_one(input: &str) -> Option { - None +use std::collections::{HashMap, HashSet}; + +struct Map { + m: [[char; 141]; 141], + width: usize, + height: usize, } -pub fn part_two(input: &str) -> Option { - None +type Coord = (usize, usize); + +fn parse(input: &str) -> Map { + let mut m = [[' '; 141]; 141]; + let mut width = 0; + let mut height = 0; + for (x, line) in input.lines().enumerate() { + for (y, char) in line.chars().enumerate() { + m[x][y] = char; + width = y; + } + height = x; + } + Map { m, width, height } +} + +fn find_path(map: &Map, start: Coord, path: &HashSet) -> Option { + let mut p = path.clone(); + let mut cur = start.clone(); + loop { + p.insert(cur); + let mut next: Vec = vec![]; + let c = map.m[cur.0][cur.1]; + if c == '>' { + next.push((cur.0, cur.1 + 1)); + } else if c == '<' { + next.push((cur.0, cur.1 - 1)); + } else if c == 'v' { + next.push((cur.0 + 1, cur.1)); + } else { + if cur.1 > 0 { + let lcoord = (cur.0, cur.1 - 1); + let l = map.m[lcoord.0][lcoord.1]; + if !p.contains(&lcoord) && l != '#' && l != '>' { + next.push(lcoord); + } + } + if cur.1 < map.width - 1 { + let rcoord = (cur.0, cur.1 + 1); + let r = map.m[rcoord.0][rcoord.1]; + if !p.contains(&rcoord) && r != '#' { + next.push(rcoord); + } + } + if cur.0 > 0 { + let ucoord = (cur.0 - 1, cur.1); + let u = map.m[ucoord.0][ucoord.1]; + if !p.contains(&ucoord) && u != '#' && u != 'v' { + next.push(ucoord); + } + } + if cur.0 <= map.height - 1 { + let dcoord = (cur.0 + 1, cur.1); + let d = map.m[dcoord.0][dcoord.1]; + if !p.contains(&dcoord) && d != '#' { + next.push(dcoord); + } + } + } + if next.is_empty() { + return None; + } else if next.len() == 1 { + cur = next[0]; + } else { + return next.iter().filter_map(|k| find_path(map, *k, &p)).max(); + } + if cur.0 == map.height { + break; + } + } + Some(p.len()) +} + +pub fn part_one(input: &str) -> Option { + let map = parse(input); + find_path(&map, (0, 1), &HashSet::new()) +} + +type Graph = HashMap>; + +fn to_graph(map: &Map, initial: Coord, start: Coord, r: &mut Graph) { + if !r.contains_key(&initial) { + r.insert(initial, HashMap::new()); + } + let mut v: HashSet = HashSet::new(); + v.insert(initial); + let mut cur = start.clone(); + let mut steps = 1; + if initial.0 == 0 && initial.1 == 1 { + steps -= 1; + } + loop { + let mut next: Vec = vec![]; + v.insert(cur); + if cur.1 > 0 { + let lcoord = (cur.0, cur.1 - 1); + let l = map.m[lcoord.0][lcoord.1]; + if l != '#' { + next.push(lcoord); + } + } + if cur.1 <= map.width - 1 { + let rcoord = (cur.0, cur.1 + 1); + let r = map.m[rcoord.0][rcoord.1]; + if r != '#' { + next.push(rcoord); + } + } + if cur.0 > 0 { + let ucoord = (cur.0 - 1, cur.1); + let u = map.m[ucoord.0][ucoord.1]; + if u != '#' { + next.push(ucoord); + } + } + if cur.0 <= map.height - 1 { + let dcoord = (cur.0 + 1, cur.1); + let d = map.m[dcoord.0][dcoord.1]; + if d != '#' { + next.push(dcoord); + } + } + if next.len() > 2 { + let parent = r.get_mut(&initial).unwrap(); + if parent.contains_key(&cur) { + return; + } else { + parent.insert(cur, steps); + for x in next.iter() { + to_graph(map, cur, *x, r); + } + } + } else { + if let Some(next_spot) = next.iter().find(|n| !v.contains(*n)) { + steps += 1; + cur = *next_spot; + } else { + let parent = r.get_mut(&initial).unwrap(); + if !parent.contains_key(&cur) { + parent.insert(cur, steps); + } + return; + } + } + } +} + +fn dfs( + g: &Graph, + steps: usize, + cur: Coord, + dest: Coord, + visited: &mut HashSet, +) -> Option { + if cur == dest { + return Some(steps); + } + let neighbors = g.get(&cur).unwrap(); + visited.insert(cur); + let m = neighbors + .iter() + .filter_map(|(n, dist)| { + if visited.contains(&n) { + None + } else if *n == dest { + Some(steps + dist) + } else { + dfs(g, steps + dist, *n, dest, visited) + } + }) + .max(); + visited.remove(&cur); + m +} + +pub fn part_two(input: &str) -> Option { + let map = parse(input); + let mut g: Graph = HashMap::new(); + to_graph(&map, (0, 1), (0, 1), &mut g); + dfs( + &g, + 0, + (0, 1), + (map.height, map.width - 1), + &mut HashSet::new(), + ) } #[cfg(test)] @@ -15,12 +203,12 @@ mod tests { #[test] fn test_part_one() { let result = part_one(&advent_of_code::template::read_file("examples", DAY)); - assert_eq!(result, None); + assert_eq!(result, Some(94)); } #[test] fn test_part_two() { let result = part_two(&advent_of_code::template::read_file("examples", DAY)); - assert_eq!(result, None); + assert_eq!(result, Some(154)); } }