Skip to content

Commit c366802

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

File tree

7 files changed

+165
-4
lines changed

7 files changed

+165
-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) | 2774 |
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: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
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::heap::*;
10+
use crate::util::point::*;
11+
12+
type Input = (Grid<u8>, Point, Point);
13+
14+
const DIRECTIONS: [Point; 4] = [RIGHT, DOWN, LEFT, UP];
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 = grid.same_size_with([u32::MAX; 4]);
29+
30+
todo.push(0, (start, 0));
31+
seen[start][0] = 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 + 3) % 4;
40+
let right = (direction + 1) % 4;
41+
let next = [
42+
(position + DIRECTIONS[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'#' && next_cost < seen[next_position][next_direction] {
49+
todo.push(next_cost, (next_position, next_direction));
50+
seen[next_position][next_direction] = next_cost;
51+
}
52+
}
53+
}
54+
55+
unreachable!()
56+
}
57+
58+
pub fn part2(input: &Input) -> usize {
59+
let (grid, ..) = input;
60+
let &(_, start, end) = input;
61+
62+
// Forwards Dijkstra
63+
let mut todo = MinHeap::new();
64+
let mut seen = grid.same_size_with([u32::MAX; 4]);
65+
let mut lowest = u32::MAX;
66+
67+
todo.push(0, (start, 0));
68+
seen[start][0] = 0;
69+
70+
while let Some((cost, (position, direction))) = todo.pop() {
71+
if position == end {
72+
lowest = lowest.min(cost);
73+
// Keep searching.
74+
continue;
75+
}
76+
77+
let left = (direction + 3) % 4;
78+
let right = (direction + 1) % 4;
79+
let next = [
80+
(position + DIRECTIONS[direction], direction, cost + 1),
81+
(position, left, cost + 1000),
82+
(position, right, cost + 1000),
83+
];
84+
85+
for (next_position, next_direction, next_cost) in next {
86+
if grid[next_position] != b'#' && next_cost < seen[next_position][next_direction] {
87+
todo.push(next_cost, (next_position, next_direction));
88+
seen[next_position][next_direction] = next_cost;
89+
}
90+
}
91+
}
92+
93+
// Backwards BFS
94+
let mut todo = Vec::new();
95+
let mut path = grid.same_size_with(false);
96+
97+
for direction in 0..4 {
98+
if seen[end][direction] == lowest {
99+
todo.push((end, direction, lowest));
100+
}
101+
}
102+
103+
while let Some((position, direction, cost)) = todo.pop() {
104+
path[position] = true;
105+
106+
if position == start {
107+
continue;
108+
}
109+
110+
// Reverse direction and subtract cost.
111+
let left = (direction + 3) % 4;
112+
let right = (direction + 1) % 4;
113+
let next = [
114+
(position - DIRECTIONS[direction], direction, cost - 1),
115+
(position, left, cost - 1000),
116+
(position, right, cost - 1000),
117+
];
118+
119+
for (next_position, next_direction, next_cost) in next {
120+
if next_cost == seen[next_position][next_direction] {
121+
todo.push((next_position, next_direction, next_cost));
122+
seen[next_position][next_direction] = u32::MAX;
123+
}
124+
}
125+
}
126+
127+
path.bytes.iter().filter(|&&b| b).count()
128+
}

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)