Skip to content

Commit c3e1825

Browse files
committed
16th day
1 parent 09a2f6c commit c3e1825

File tree

2 files changed

+171
-0
lines changed

2 files changed

+171
-0
lines changed

data/examples/16.txt

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#################
2+
#...#...#...#..E#
3+
#.#.#.#.#.#.#.#.#
4+
#.#.#.#...#...#.#
5+
#.#.#.#.###.#.#.#
6+
#...#.#.#.....#.#
7+
#.#.#.#.#.#####.#
8+
#.#...#.#.#.....#
9+
#.#.#####.#.###.#
10+
#.#.#.......#...#
11+
#.#.###.#####.###
12+
#.#.#...#.....#.#
13+
#.#.#.#####.###.#
14+
#.#.#.........#.#
15+
#.#.#.#########.#
16+
#S#.............#
17+
#################

src/bin/16.rs

+154
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
advent_of_code::solution!(16);
2+
3+
use std::u32;
4+
5+
use advent_of_code::maneatingape::grid::*;
6+
use advent_of_code::maneatingape::hash::*;
7+
use advent_of_code::maneatingape::heap::*;
8+
use advent_of_code::maneatingape::point::*;
9+
10+
fn parse_data(input: &str) -> Grid<u8> {
11+
Grid::parse(input)
12+
}
13+
14+
fn neighbors(
15+
grid: &Grid<u8>,
16+
position: Point,
17+
direction: Point,
18+
cost: u32,
19+
) -> Vec<(Point, Point, u32)> {
20+
let mut result = Vec::with_capacity(4);
21+
22+
for n_direction in [LEFT, RIGHT, UP, DOWN] {
23+
let n_position = position + n_direction;
24+
25+
if grid[n_position] != b'#' {
26+
let n_cost_diff = match (direction, n_direction) {
27+
(LEFT, LEFT) => 1,
28+
(LEFT, UP) => 1001,
29+
(LEFT, DOWN) => 1001,
30+
(LEFT, RIGHT) => 2001,
31+
32+
(RIGHT, RIGHT) => 1,
33+
(RIGHT, UP) => 1001,
34+
(RIGHT, DOWN) => 1001,
35+
(RIGHT, LEFT) => 2001,
36+
37+
(UP, UP) => 1,
38+
(UP, LEFT) => 1001,
39+
(UP, RIGHT) => 1001,
40+
(UP, DOWN) => 2001,
41+
42+
(DOWN, DOWN) => 1,
43+
(DOWN, LEFT) => 1001,
44+
(DOWN, RIGHT) => 1001,
45+
(DOWN, UP) => 2001,
46+
47+
_ => panic!("Invalid state"),
48+
};
49+
50+
result.push((n_position, n_direction, cost + n_cost_diff));
51+
}
52+
}
53+
54+
result
55+
}
56+
57+
fn find_shortest_path_cost(grid: Grid<u8>) -> u32 {
58+
let start_position = grid.find(b'S').unwrap();
59+
let start_direction = RIGHT;
60+
61+
let mut min_heap = MinHeap::new();
62+
let mut g_score = FastMap::new();
63+
64+
min_heap.push(0, (start_position, start_direction));
65+
g_score.insert((start_position, start_direction), 0);
66+
67+
while let Some((cost, (position, direction))) = min_heap.pop() {
68+
if grid[position] == b'E' {
69+
return cost;
70+
}
71+
72+
for (n_position, n_direction, n_cost) in neighbors(&grid, position, direction, cost) {
73+
if n_cost < *g_score.get(&(n_position, n_direction)).unwrap_or(&u32::MAX) {
74+
g_score.insert((n_position, n_direction), n_cost);
75+
min_heap.push(n_cost, (n_position, n_direction));
76+
}
77+
}
78+
}
79+
80+
u32::MAX
81+
}
82+
83+
fn find_all_shortest_paths_points(grid: Grid<u8>) -> FastSet<Point> {
84+
let start_position = grid.find(b'S').unwrap();
85+
let start_direction = RIGHT;
86+
let start_path = vec![start_position];
87+
88+
let mut min_heap = MinHeap::new();
89+
let mut g_score = FastMap::new();
90+
91+
min_heap.push(0, (start_position, start_direction, start_path));
92+
g_score.insert((start_position, start_direction), 0);
93+
94+
let mut first_winner_cost = u32::MAX;
95+
let mut all_shortest_paths_points = FastSet::new();
96+
97+
while let Some((cost, (position, direction, path))) = min_heap.pop() {
98+
if grid[position] == b'E' {
99+
if cost > first_winner_cost {
100+
return all_shortest_paths_points;
101+
} else {
102+
first_winner_cost = cost;
103+
all_shortest_paths_points.extend(path.iter());
104+
}
105+
}
106+
107+
for (n_position, n_direction, n_cost) in neighbors(&grid, position, direction, cost) {
108+
if n_cost <= *g_score.get(&(n_position, n_direction)).unwrap_or(&u32::MAX) {
109+
g_score.insert((n_position, n_direction), n_cost);
110+
111+
let mut n_path = Vec::with_capacity(path.len() + 1);
112+
n_path.extend(path.iter());
113+
n_path.push(n_position);
114+
115+
min_heap.push(n_cost, (n_position, n_direction, n_path));
116+
}
117+
}
118+
}
119+
120+
all_shortest_paths_points
121+
}
122+
123+
pub fn part_one(input: &str) -> Option<u32> {
124+
let grid = parse_data(input);
125+
126+
let result = find_shortest_path_cost(grid);
127+
128+
Some(result)
129+
}
130+
131+
pub fn part_two(input: &str) -> Option<u32> {
132+
let grid = parse_data(input);
133+
134+
let result = find_all_shortest_paths_points(grid).len() as u32;
135+
136+
Some(result)
137+
}
138+
139+
#[cfg(test)]
140+
mod tests {
141+
use super::*;
142+
143+
#[test]
144+
fn test_part_one() {
145+
let result = part_one(&advent_of_code::template::read_file("examples", DAY));
146+
assert_eq!(result, Some(11048));
147+
}
148+
149+
#[test]
150+
fn test_part_two() {
151+
let result = part_two(&advent_of_code::template::read_file("examples", DAY));
152+
assert_eq!(result, Some(64));
153+
}
154+
}

0 commit comments

Comments
 (0)