Skip to content

Commit 704f03a

Browse files
committed
Day 16
1 parent 7a4f778 commit 704f03a

File tree

9 files changed

+267
-9
lines changed

9 files changed

+267
-9
lines changed

1

Whitespace-only changes.

README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,11 @@ Solutions for [Advent of Code](https://adventofcode.com/) in [Rust](https://www.
2424
| [Day 11](./src/bin/11.rs) | `284.6µs` | `12.8ms` |
2525
| [Day 12](./src/bin/12.rs) | `434.7µs` | `674.6µs` |
2626
| [Day 13](./src/bin/13.rs) | `90.9µs` | `91.8µs` |
27-
| [Day 14](./src/bin/14.rs) | `31.0µs` | `3.6ms` |
27+
| [Day 14](./src/bin/14.rs) | `30.8µs` | `3.5ms` |
2828
| [Day 15](./src/bin/15.rs) | `119.7µs` | `591.0µs` |
29+
| [Day 16](./src/bin/16.rs) | `195.4µs` | `173.6ms` |
2930

30-
**Total: 31.43ms**
31+
**Total: 205.12ms**
3132
<!--- benchmarking table --->
3233

3334
---

data/examples/16-1.txt

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
###############
2+
#.......#....E#
3+
#.#.###.#.###.#
4+
#.....#.#...#.#
5+
#.###.#####.#.#
6+
#.#.#.......#.#
7+
#.#.#####.###.#
8+
#...........#.#
9+
###.#.#####.#.#
10+
#...#.....#.#.#
11+
#.#.#.###.#.#.#
12+
#.....#...#.#.#
13+
#.###.#.#.#.#.#
14+
#S..#.....#...#
15+
###############

data/examples/16-2.txt

Lines changed: 17 additions & 0 deletions
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+
#################

mygrid/src/point.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,19 @@ impl Point {
7575
|| (a.column == b.column && a.column == self.column && is_between_lines)
7676
}
7777

78+
#[inline]
79+
pub fn from_usize(value: usize, grid_width: usize) -> Self {
80+
Point::new(
81+
value as isize / grid_width as isize,
82+
value as isize % grid_width as isize,
83+
)
84+
}
85+
86+
#[inline]
87+
pub fn to_usize(&self, grid_width: usize) -> usize {
88+
(self.line as usize) * grid_width + self.column as usize
89+
}
90+
7891
#[inline]
7992
pub fn to_u128(&self) -> u128 {
8093
((self.line as u128) << 64) | (self.column as u128)

src/bin/14.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use mygrid::{direction::Direction, grid::Grid, point::Point};
1+
use mygrid::{direction::Direction, heapless_grid::HeaplessGrid, point::Point};
22

33
advent_of_code::solution!(14);
44

@@ -86,7 +86,7 @@ pub fn part_two(input: &str) -> Option<u32> {
8686
robots: parse_input(input),
8787
};
8888

89-
let base_dbg_grid = Grid::new(
89+
let base_dbg_grid = HeaplessGrid::<char, { 103 * 101 }>::new(
9090
configuration.grid_size.column as usize,
9191
configuration.grid_size.line as usize,
9292
'.',

src/bin/16.rs

Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
use std::collections::VecDeque;
2+
3+
use mygrid::{
4+
direction::{Direction, DOWN, LEFT, RIGHT, UP},
5+
grid::Grid,
6+
point::Point,
7+
};
8+
9+
advent_of_code::solution!(16);
10+
11+
pub fn part_one(input: &str) -> Option<u64> {
12+
let (grid, start) = Grid::new_from_str_capture_start(input, &|c| c, &|c| c == 'S');
13+
let target_pos = grid
14+
.iter_item_and_position()
15+
.filter(|&(_, c)| *c == 'E')
16+
.map(|(p, _)| p)
17+
.next()
18+
.unwrap();
19+
20+
#[derive(Debug, PartialEq, Eq)]
21+
struct State {
22+
pos: Point,
23+
dir: Direction,
24+
cost: u64,
25+
}
26+
27+
let mut q = VecDeque::new();
28+
q.push_back(State {
29+
pos: start,
30+
dir: RIGHT,
31+
cost: 0,
32+
});
33+
34+
let mut best_cost_grid = Grid::new(grid.width, grid.height, [u64::MAX; 4]);
35+
let dir_to_index = |d: Direction| match d {
36+
RIGHT => 0,
37+
DOWN => 1,
38+
LEFT => 2,
39+
UP => 3,
40+
_ => unreachable!(),
41+
};
42+
43+
while let Some(s) = q.pop_front() {
44+
if s.pos == target_pos {
45+
best_cost_grid[s.pos][dir_to_index(s.dir)] = s.cost;
46+
continue;
47+
}
48+
49+
let right = s.dir.rotate_clockwise();
50+
let left = s.dir.rotate_counterclockwise();
51+
52+
for &(pos, dir, cost) in [
53+
(s.pos + s.dir, s.dir, s.cost + 1),
54+
(s.pos + right, right, s.cost + 1000 + 1),
55+
(s.pos + left, left, s.cost + 1000 + 1),
56+
]
57+
.iter()
58+
{
59+
if grid[pos] == '#' {
60+
continue;
61+
}
62+
let best_cost = best_cost_grid[pos][dir_to_index(dir)];
63+
if best_cost <= cost {
64+
continue;
65+
}
66+
best_cost_grid[pos][dir_to_index(dir)] = cost;
67+
68+
let new_state = State { pos, dir, cost };
69+
q.push_back(new_state);
70+
}
71+
}
72+
73+
let min_cost = *best_cost_grid[target_pos].iter().min().unwrap();
74+
Some(min_cost)
75+
}
76+
77+
pub fn part_two(input: &str) -> Option<u64> {
78+
let (grid, start) = Grid::new_from_str_capture_start(input, &|c| c, &|c| c == 'S');
79+
let target_pos = grid
80+
.iter_item_and_position()
81+
.filter(|&(_, c)| *c == 'E')
82+
.map(|(p, _)| p)
83+
.next()
84+
.unwrap();
85+
86+
#[derive(Debug, PartialEq, Eq)]
87+
struct State {
88+
path: Vec<Point>,
89+
pos: Point,
90+
dir: Direction,
91+
cost: u64,
92+
}
93+
94+
let mut q = VecDeque::new();
95+
let mut path = Vec::with_capacity(1024);
96+
path.push(start);
97+
q.push_back(State {
98+
path,
99+
pos: start,
100+
dir: RIGHT,
101+
cost: 0,
102+
});
103+
104+
let base_false_grid = Grid::new(grid.width, grid.height, false);
105+
let mut best_spots_grid = base_false_grid.clone();
106+
let mut best_target_cost = u64::MAX;
107+
let mut best_cost_grid = Grid::new(grid.width, grid.height, [u64::MAX; 4]);
108+
let dir_to_index = |d: Direction| match d {
109+
RIGHT => 0,
110+
DOWN => 1,
111+
LEFT => 2,
112+
UP => 3,
113+
_ => unreachable!(),
114+
};
115+
116+
while let Some(s) = q.pop_front() {
117+
if s.pos == target_pos {
118+
if best_target_cost < s.cost {
119+
continue;
120+
}
121+
122+
// reset best_spots_grid if we found a better path
123+
if best_target_cost > s.cost {
124+
best_spots_grid = base_false_grid.clone();
125+
}
126+
127+
for &p in s.path.iter() {
128+
best_spots_grid[p] = true;
129+
}
130+
131+
best_target_cost = s.cost;
132+
continue;
133+
}
134+
135+
best_cost_grid[s.pos][dir_to_index(s.dir)] = s.cost;
136+
137+
let right = s.dir.rotate_clockwise();
138+
let left = s.dir.rotate_counterclockwise();
139+
for &(pos, dir, cost) in [
140+
(s.pos + s.dir, s.dir, s.cost + 1),
141+
(s.pos + left, left, s.cost + 1000 + 1),
142+
(s.pos + right, right, s.cost + 1000 + 1),
143+
]
144+
.iter()
145+
{
146+
if grid[pos] == '#' {
147+
continue;
148+
}
149+
let best_cost_to_next_pos = best_cost_grid[pos][dir_to_index(dir)];
150+
if best_cost_to_next_pos < cost {
151+
continue;
152+
}
153+
154+
if cost > best_target_cost {
155+
continue;
156+
}
157+
158+
let mut new_path = s.path.clone();
159+
new_path.push(pos);
160+
let new_state = State {
161+
path: new_path,
162+
pos,
163+
dir,
164+
cost,
165+
};
166+
q.push_back(new_state);
167+
}
168+
}
169+
170+
let tile_count = best_spots_grid.iter().filter(|&&b| b).count();
171+
Some(tile_count as u64)
172+
}
173+
174+
#[cfg(test)]
175+
mod tests {
176+
use super::*;
177+
178+
#[test]
179+
fn test_part_one_1() {
180+
let result = part_one(&advent_of_code::template::read_file_part(
181+
"examples", DAY, 1,
182+
));
183+
assert_eq!(result, Some(7036));
184+
}
185+
186+
#[test]
187+
fn test_part_one_2() {
188+
let result = part_one(&advent_of_code::template::read_file_part(
189+
"examples", DAY, 2,
190+
));
191+
assert_eq!(result, Some(11048));
192+
}
193+
194+
#[test]
195+
fn test_part_two_1() {
196+
let result = part_two(&advent_of_code::template::read_file_part(
197+
"examples", DAY, 1,
198+
));
199+
assert_eq!(result, Some(45));
200+
}
201+
202+
#[test]
203+
fn test_part_two_2() {
204+
let result = part_two(&advent_of_code::template::read_file_part(
205+
"examples", DAY, 2,
206+
));
207+
assert_eq!(result, Some(64));
208+
}
209+
}

src/main.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ mod args {
3030
},
3131
Flame {
3232
day: Day,
33-
release: bool,
33+
debug: bool,
3434
dhat: bool,
3535
},
3636
All {
@@ -75,7 +75,7 @@ mod args {
7575
},
7676
Some("flame") => AppArguments::Flame {
7777
day: args.free_from_str()?,
78-
release: args.contains("--release"),
78+
debug: args.contains("--debug"),
7979
dhat: args.contains("--dhat"),
8080
},
8181
Some("solve") => AppArguments::Solve {
@@ -132,7 +132,7 @@ fn main() {
132132
dhat,
133133
submit,
134134
} => solve::handle(day, release, dhat, submit),
135-
AppArguments::Flame { day, release, dhat } => flame::handle(day, release, dhat),
135+
AppArguments::Flame { day, debug, dhat } => flame::handle(day, debug, dhat),
136136
#[cfg(feature = "today")]
137137
AppArguments::Today => {
138138
match Day::today() {

src/template/commands/flame.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use std::process::{Command, Stdio};
22

33
use crate::template::Day;
44

5-
pub fn handle(day: Day, release: bool, dhat: bool) {
5+
pub fn handle(day: Day, debug: bool, dhat: bool) {
66
let mut cmd_args = vec![
77
"flamegraph".to_string(),
88
"--bin".to_string(),
@@ -16,11 +16,14 @@ pub fn handle(day: Day, release: bool, dhat: bool) {
1616
"--features".to_string(),
1717
"dhat-heap".to_string(),
1818
]);
19-
} else if release {
19+
}
20+
21+
if !debug {
2022
cmd_args.push("--release".to_string());
2123
}
2224

2325
cmd_args.push("--".to_string());
26+
cmd_args.push("--time".to_string());
2427

2528
let mut cmd = Command::new("cargo")
2629
.args(&cmd_args)

0 commit comments

Comments
 (0)