1
0
Fork 0

day 23 solution

main
Andrew Coleman 2024-02-29 11:47:19 -05:00
parent 5054b1b498
commit c6ca78cbef
2 changed files with 217 additions and 6 deletions

View File

@ -0,0 +1,23 @@
#.#####################
#.......#########...###
#######.#########.#.###
###.....#.>.>.###.#.###
###v#####.#v#.###.#.###
###.>...#.#.#.....#...#
###v###.#.#.#########.#
###...#.#.#.......#...#
#####.#.#.#######.#.###
#.....#.#.#.......#...#
#.#####.#.#.#########v#
#.#...#...#...###...>.#
#.#.#v#######v###.###v#
#...#.>.#...>.>.#.###.#
#####v#.#.###v#.#.###.#
#.....#...#...#.#.#...#
#.#########.###.#.#.###
#...###...#...#...#.###
###.###.#.###v#####v###
#...#...#.#.>.>.#.>.###
#.###.###.#.###.#.#v###
#.....###...###...#...#
#####################.#

View File

@ -1,11 +1,199 @@
advent_of_code::solution!(23); advent_of_code::solution!(23);
pub fn part_one(input: &str) -> Option<u32> { use std::collections::{HashMap, HashSet};
None
struct Map {
m: [[char; 141]; 141],
width: usize,
height: usize,
} }
pub fn part_two(input: &str) -> Option<u32> { 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<Coord>) -> Option<usize> {
let mut p = path.clone();
let mut cur = start.clone();
loop {
p.insert(cur);
let mut next: Vec<Coord> = 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<usize> {
let map = parse(input);
find_path(&map, (0, 1), &HashSet::new())
}
type Graph = HashMap<Coord, HashMap<Coord, usize>>;
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<Coord> = 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<Coord> = 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<Coord>,
) -> Option<usize> {
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 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<usize> {
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)] #[cfg(test)]
@ -15,12 +203,12 @@ mod tests {
#[test] #[test]
fn test_part_one() { fn test_part_one() {
let result = part_one(&advent_of_code::template::read_file("examples", DAY)); let result = part_one(&advent_of_code::template::read_file("examples", DAY));
assert_eq!(result, None); assert_eq!(result, Some(94));
} }
#[test] #[test]
fn test_part_two() { fn test_part_two() {
let result = part_two(&advent_of_code::template::read_file("examples", DAY)); let result = part_two(&advent_of_code::template::read_file("examples", DAY));
assert_eq!(result, None); assert_eq!(result, Some(154));
} }
} }