Skip to content

Commit a3f7728

Browse files
committed
Year 2024 Day 16
1 parent fe27da3 commit a3f7728

File tree

7 files changed

+180
-4
lines changed

7 files changed

+180
-4
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ Performance is reasonable even on older hardware, for example a 2011 MacBook Pro
8787
| 13 | [Claw Contraption](https://adventofcode.com/2024/day/13) | [Source](src/year2024/day13.rs) | 14 |
8888
| 14 | [Restroom Redoubt](https://adventofcode.com/2024/day/14) | [Source](src/year2024/day14.rs) | 74 |
8989
| 15 | [Warehouse Woes](https://adventofcode.com/2024/day/15) | [Source](src/year2024/day15.rs) | 303 |
90+
| 16 | [Reindeer Maze](https://adventofcode.com/2024/day/16) | [Source](src/year2024/day16.rs) | 6400 |
9091

9192
## 2023
9293

benches/benchmark.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,5 +88,5 @@ benchmark!(year2023
8888

8989
benchmark!(year2024
9090
day01, day02, day03, day04, day05, day06, day07, day08, day09, day10, day11, day12, day13,
91-
day14, day15
91+
day14, day15, day16
9292
);

src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,5 +68,5 @@ library!(year2023 "Restore global snow production."
6868

6969
library!(year2024 "Locate the Chief Historian in time for the big Christmas sleigh launch."
7070
day01, day02, day03, day04, day05, day06, day07, day08, day09, day10, day11, day12, day13,
71-
day14, day15
71+
day14, day15, day16
7272
);

src/main.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,5 +142,5 @@ run!(year2023
142142

143143
run!(year2024
144144
day01, day02, day03, day04, day05, day06, day07, day08, day09, day10, day11, day12, day13,
145-
day14, day15
145+
day14, day15, day16
146146
);

src/year2024/day16.rs

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
//! # Reindeer Maze
2+
//!
3+
//! Part one is a normal [Dijkstra](https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm)
4+
//! search from start to end.
5+
//!
6+
//! Part two we modify the search to check all possible paths. Then we perform a BFS *backwards*
7+
//! from the end to the finish, using the inverse cost to find all possible paths.
8+
use crate::util::grid::*;
9+
use crate::util::hash::*;
10+
use crate::util::heap::*;
11+
use crate::util::point::*;
12+
use std::collections::VecDeque;
13+
14+
type Input = (Grid<u8>, Point, Point);
15+
16+
pub fn parse(input: &str) -> Input {
17+
let grid = Grid::parse(input);
18+
let start = grid.find(b'S').unwrap();
19+
let end = grid.find(b'E').unwrap();
20+
(grid, start, end)
21+
}
22+
23+
pub fn part1(input: &Input) -> u32 {
24+
let (grid, ..) = input;
25+
let &(_, start, end) = input;
26+
27+
let mut todo = MinHeap::new();
28+
let mut seen = FastMap::new();
29+
30+
todo.push(0, (start, RIGHT));
31+
seen.insert((start, RIGHT), 0);
32+
33+
while let Some((cost, (position, direction))) = todo.pop() {
34+
if position == end {
35+
// Stop search.
36+
return cost;
37+
}
38+
39+
let left = direction.counter_clockwise();
40+
let right = direction.clockwise();
41+
let next = [
42+
(position + direction, direction, cost + 1),
43+
(position, left, cost + 1000),
44+
(position, right, cost + 1000),
45+
];
46+
47+
for (next_position, next_direction, next_cost) in next {
48+
if grid[next_position] != b'#' {
49+
let key = (next_position, next_direction);
50+
let existing = *seen.get(&key).unwrap_or(&u32::MAX);
51+
52+
if existing > next_cost {
53+
todo.push(next_cost, key);
54+
seen.insert(key, next_cost);
55+
}
56+
}
57+
}
58+
}
59+
60+
unreachable!()
61+
}
62+
63+
pub fn part2(input: &Input) -> usize {
64+
let (grid, ..) = input;
65+
let &(_, start, end) = input;
66+
67+
// Forwards Dijkstra
68+
let mut todo = MinHeap::new();
69+
let mut seen = FastMap::new();
70+
let mut lowest = u32::MAX;
71+
72+
todo.push(0, (start, RIGHT));
73+
seen.insert((start, RIGHT), 0);
74+
75+
while let Some((cost, (position, direction))) = todo.pop() {
76+
if position == end {
77+
lowest = lowest.min(cost);
78+
// Keep searching.
79+
continue;
80+
}
81+
82+
let left = direction.counter_clockwise();
83+
let right = direction.clockwise();
84+
let next = [
85+
(position + direction, direction, cost + 1),
86+
(position, left, cost + 1000),
87+
(position, right, cost + 1000),
88+
];
89+
90+
for (next_position, next_direction, next_cost) in next {
91+
if grid[next_position] != b'#' {
92+
let key = (next_position, next_direction);
93+
let existing = *seen.get(&key).unwrap_or(&u32::MAX);
94+
95+
if existing > next_cost {
96+
todo.push(next_cost, key);
97+
seen.insert(key, next_cost);
98+
}
99+
}
100+
}
101+
}
102+
103+
// Backwards BFS
104+
let mut todo = VecDeque::new();
105+
let mut path = FastSet::new();
106+
107+
for direction in ORTHOGONAL {
108+
if let Some(&amount) = seen.get(&(end, direction)) {
109+
if amount == lowest {
110+
todo.push_back((end, direction, lowest));
111+
}
112+
}
113+
}
114+
115+
while let Some((position, direction, cost)) = todo.pop_front() {
116+
path.insert(position);
117+
118+
if position == start {
119+
continue;
120+
}
121+
122+
// Subtract cost
123+
let left = direction.counter_clockwise();
124+
let right = direction.clockwise();
125+
let next = [
126+
(position - direction, direction, cost - 1),
127+
(position, left, cost - 1000),
128+
(position, right, cost - 1000),
129+
];
130+
131+
for (next_position, next_direction, next_cost) in next {
132+
let key = (next_position, next_direction);
133+
134+
if let Some(&amount) = seen.get(&key) {
135+
if amount == next_cost {
136+
todo.push_back((next_position, next_direction, next_cost));
137+
}
138+
}
139+
}
140+
}
141+
142+
path.len()
143+
}

tests/test.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,5 +81,5 @@ test!(year2023
8181

8282
test!(year2024
8383
day01, day02, day03, day04, day05, day06, day07, day08, day09, day10, day11, day12, day13,
84-
day14, day15
84+
day14, day15, day16
8585
);

tests/year2024/day16.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
use aoc::year2024::day16::*;
2+
3+
const EXAMPLE: &str = "\
4+
#################
5+
#...#...#...#..E#
6+
#.#.#.#.#.#.#.#.#
7+
#.#.#.#...#...#.#
8+
#.#.#.#.###.#.#.#
9+
#...#.#.#.....#.#
10+
#.#.#.#.#.#####.#
11+
#.#...#.#.#.....#
12+
#.#.#####.#.###.#
13+
#.#.#.......#...#
14+
#.#.###.#####.###
15+
#.#.#...#.....#.#
16+
#.#.#.#####.###.#
17+
#.#.#.........#.#
18+
#.#.#.#########.#
19+
#S#.............#
20+
#################";
21+
22+
#[test]
23+
fn part1_test() {
24+
let input = parse(EXAMPLE);
25+
assert_eq!(part1(&input), 11048);
26+
}
27+
28+
#[test]
29+
fn part2_test() {
30+
let input = parse(EXAMPLE);
31+
assert_eq!(part2(&input), 64);
32+
}

0 commit comments

Comments
 (0)