Skip to content

Commit 3cbe249

Browse files
committed
solve: day15
1 parent d208d34 commit 3cbe249

File tree

3 files changed

+233
-1
lines changed

3 files changed

+233
-1
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
resolver = "2"
33
members = [
44
"utils",
5-
"aoc_derive", "day1", "day2", "day3", "day4", "day5", "day6", "day7", "day8", "day9", "day10", "day11", "day12", "day13", "day14",
5+
"aoc_derive", "day1", "day2", "day3", "day4", "day5", "day6", "day7", "day8", "day9", "day10", "day11", "day12", "day13", "day14", "day15",
66
]
77

88
[workspace.dependencies]

day15/Cargo.toml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
[package]
2+
name = "day15"
3+
version = "0.1.0"
4+
edition = "2024"
5+
6+
[dependencies]
7+
aoc_derive.path = '../aoc_derive'
8+
utils.path = '../utils'
9+
derive_more.workspace = true
10+
itertools.workspace = true
11+
lazy-regex.workspace = true
12+
parse-display.workspace = true
13+
rayon.workspace = true
14+
regex.workspace = true
15+
num.workspace = true
16+
17+
[dev-dependencies]
18+
pretty_assertions.workspace = true

day15/src/main.rs

Lines changed: 214 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,214 @@
1+
use aoc_derive::aoc_main;
2+
use grid::Grid;
3+
use itertools::Itertools;
4+
use math::Vec2D;
5+
use utils::*;
6+
7+
fn try_move_part1(pos: Vec2D, heading: Vec2D, map: &mut Grid<char>) -> bool {
8+
match map[pos] {
9+
'.' => {
10+
map.swap(pos, pos - heading);
11+
true
12+
}
13+
'#' => false,
14+
'O' => {
15+
let can_move = try_move_part1(pos + heading, heading, map);
16+
if can_move {
17+
map.swap(pos, pos - heading);
18+
}
19+
can_move
20+
}
21+
_ => unreachable!(),
22+
}
23+
}
24+
25+
fn part1(mut map: Grid<char>, instructions: &str) -> i64 {
26+
let mut pos = map.iter().find_map(|(pos, &c)| (c == '@').then_some(pos)).unwrap();
27+
map[pos] = '.';
28+
29+
for heading in instructions.chars().filter(|c| !c.is_ascii_whitespace()).map(|instr| {
30+
Vec2D::from(match instr {
31+
'v' => (0, 1),
32+
'>' => (1, 0),
33+
'<' => (-1, 0),
34+
'^' => (0, -1),
35+
_ => unreachable!(),
36+
})
37+
}) {
38+
if try_move_part1(pos + heading, heading, &mut map) {
39+
pos += heading;
40+
}
41+
}
42+
43+
map.iter().filter_map(|(pos, &c)| (c == 'O').then_some(pos.x + 100 * pos.y)).sum()
44+
}
45+
46+
fn try_move_horizontally_part2(pos: Vec2D, heading: Vec2D, map: &mut Grid<char>) -> bool {
47+
if let Some(dot) = (1..)
48+
.find_map(|i| match map[pos + i * heading] {
49+
'.' => Some(Some(i)),
50+
'#' => Some(None),
51+
_ => None,
52+
})
53+
.unwrap()
54+
{
55+
for j in (0..dot).rev() {
56+
map.swap(pos + (j + 1) * heading, pos + j * heading);
57+
}
58+
return true;
59+
}
60+
false
61+
}
62+
63+
fn try_move_vertically_part2(pos: Vec2D, heading: Vec2D, map: &mut Grid<char>) -> bool {
64+
match map[pos + heading] {
65+
'#' => return false,
66+
'.' => {
67+
return true;
68+
}
69+
_ => (),
70+
}
71+
72+
let mut to_move = vec![vec![
73+
pos + heading,
74+
pos + heading + if map[pos + heading] == ']' { (-1, 0) } else { (1, 0) },
75+
]];
76+
loop {
77+
let upper_row = to_move.last().unwrap();
78+
79+
if upper_row.iter().any(|&pos| map[pos + heading] == '#') {
80+
// Can't move
81+
return false;
82+
}
83+
84+
if upper_row.iter().all(|&pos| map[pos + heading] == '.') {
85+
for row in to_move.into_iter().rev() {
86+
for pos in row {
87+
map.swap(pos + heading, pos);
88+
}
89+
}
90+
91+
return true;
92+
}
93+
94+
to_move.push(
95+
upper_row
96+
.iter()
97+
.flat_map(|&pos| match map[pos + heading] {
98+
']' => vec![pos + heading, pos + heading + (-1, 0)],
99+
'[' => vec![pos + heading, pos + heading + (1, 0)],
100+
_ => vec![],
101+
})
102+
.unique()
103+
.collect(),
104+
);
105+
}
106+
}
107+
108+
fn part2(map: &str, instructions: &str) -> i64 {
109+
let mut map = map
110+
.trim()
111+
.lines()
112+
.map(|line| {
113+
line.chars().flat_map(|c| {
114+
match c {
115+
'#' => "##",
116+
'O' => "[]",
117+
'.' => "..",
118+
'@' => "@.",
119+
_ => unreachable!(),
120+
}
121+
.chars()
122+
})
123+
})
124+
.collect::<Grid<char>>();
125+
126+
let mut pos = map.iter().find_map(|(pos, &c)| (c == '@').then_some(pos)).unwrap();
127+
map[pos] = '.';
128+
129+
for heading in instructions.chars().filter(|c| !c.is_ascii_whitespace()).map(|instr| {
130+
Vec2D::from(match instr {
131+
'v' => (0, 1),
132+
'>' => (1, 0),
133+
'<' => (-1, 0),
134+
'^' => (0, -1),
135+
_ => unreachable!(),
136+
})
137+
}) {
138+
if heading.y == 0 && try_move_horizontally_part2(pos, heading, &mut map)
139+
|| try_move_vertically_part2(pos, heading, &mut map)
140+
{
141+
pos += heading
142+
}
143+
}
144+
145+
map.iter().filter_map(|(pos, &c)| (c == '[').then_some(pos.x + 100 * pos.y)).sum()
146+
}
147+
148+
#[aoc_main]
149+
fn solve(input: Input) -> impl Into<Solution> {
150+
let (map, instructions) = input.blocks().collect_tuple().unwrap();
151+
152+
(part1(map.lines().map(str::chars).collect(), instructions), part2(map, instructions))
153+
}
154+
155+
#[cfg(test)]
156+
mod tests {
157+
use super::*;
158+
#[test]
159+
fn test_examples() {
160+
part2(
161+
"
162+
#######
163+
#...#.#
164+
#.....#
165+
#..OO@#
166+
#..O..#
167+
#.....#
168+
#######",
169+
"<vv<<^^<<^^",
170+
);
171+
172+
assert_example!(
173+
"
174+
########
175+
#..O.O.#
176+
##@.O..#
177+
#...O..#
178+
#.#.O..#
179+
#...O..#
180+
#......#
181+
########
182+
183+
<^^>>>vv<v>>v<<
184+
",
185+
2028
186+
);
187+
188+
assert_example!(
189+
r"##########
190+
#..O..O.O#
191+
#......O.#
192+
#.OO..O.O#
193+
194+
#O#..O...#
195+
#O..O..O.#
196+
#.OO.O.OO#
197+
#....O...#
198+
##########
199+
200+
<vv>^<v^>v>^vv^v>v<>v^v<v<^vv<<<^><<><>>v<vvv<>^v^>^<<<><<v<<<v^vv^v>^
201+
vvv<<^>^v^^><<>>><>^<<><^vv^^<>vvv<>><^^v>^>vv<>v<<<<v<^v>^<^^>>>^<v<v
202+
><>vv>v^v^<>><>>>><^^>vv>v<^^^>>v^v^<^^>v^^>v^<^v>v<>>v^v^<v>v^^<^^vv<
203+
<<v<^>>^^^^>>>v^<>vvv^><v<<<>^^^vv^<vvv>^>v<^^^^v<>^>vvvv><>>v^<<^^^^^
204+
^><^><>>><>^^<<^^v>>><^<v>^<vv>>v>>>^v><>^v><<<<v>>v<v<v>vvv>^<><<>^><
205+
^>><>^v<><^vvv<^^<><v<<<<<><^v<<<><<<^^<v<^^^><^>>^<v^><<<^>>^v<v^v<v^
206+
>^>>^v>vv>^<<^v<>><<><<v<<v><>v<^vv<<<>^^v^>^^>>><<^v>>v^v><^^>>^<>vv^
207+
<><^^>^^^<><vvvvv^v<v<<>^v<v>v<<^><<><<><<<^^<<<^<<>><<><^^^>^^<>^>v<>
208+
^^>vv<^v^v<vv>^<><v<^v>^^^>>>^^vvv^>vvv<>>>^<^>>>>>^<<^v>^vvv<>^<><<v>
209+
v^^>>><<^^<>>^v^<v^vv<>v^<<>^<^v^v><^<<<><<^<v><v<>vv>>v><v^<vv<>v^<<^",
210+
10092,
211+
9021
212+
);
213+
}
214+
}

0 commit comments

Comments
 (0)