Skip to content

Commit 3826741

Browse files
committed
Year 2024 Day 15
1 parent eaa553e commit 3826741

File tree

7 files changed

+195
-4
lines changed

7 files changed

+195
-4
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ Performance is reasonable even on older hardware, for example a 2011 MacBook Pro
8686
| 12 | [Garden Groups](https://adventofcode.com/2024/day/12) | [Source](src/year2024/day12.rs) | 289 |
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 |
89+
| 15 | [Warehouse Woes](https://adventofcode.com/2024/day/15) | [Source](src/year2024/day15.rs) | 379 |
8990

9091
## 2023
9192

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
91+
day14, day15
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
71+
day14, day15
7272
);

src/main.rs

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

141141
run!(year2024
142142
day01, day02, day03, day04, day05, day06, day07, day08, day09, day10, day11, day12, day13,
143-
day14
143+
day14, day15
144144
);

src/year2024/day15.rs

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
//! # Warehouse Woes
2+
use crate::util::grid::*;
3+
use crate::util::point::*;
4+
use std::mem::swap;
5+
6+
type Input<'a> = (Grid<u8>, &'a str);
7+
8+
pub fn parse(input: &str) -> Input<'_> {
9+
let (prefix, suffix) = input.split_once("\n\n").unwrap();
10+
let grid = Grid::parse(prefix);
11+
(grid, suffix)
12+
}
13+
14+
pub fn part1(input: &Input<'_>) -> i32 {
15+
let (grid, moves) = input;
16+
17+
let mut grid = grid.clone();
18+
let mut position = grid.find(b'@').unwrap();
19+
20+
for b in moves.bytes() {
21+
let direction = match b {
22+
b'<' => LEFT,
23+
b'>' => RIGHT,
24+
b'^' => UP,
25+
b'v' => DOWN,
26+
_ => continue,
27+
};
28+
29+
push_one(&mut grid, &mut position, direction);
30+
}
31+
32+
gps(&grid, b'O')
33+
}
34+
35+
pub fn part2(input: &Input<'_>) -> i32 {
36+
let (grid, moves) = input;
37+
38+
let mut grid = stretch(grid);
39+
let mut position = grid.find(b'@').unwrap();
40+
41+
let mut todo = Vec::new();
42+
let mut seen = grid.same_size_with(usize::MAX);
43+
44+
for (id, b) in moves.bytes().enumerate() {
45+
match b {
46+
b'<' => push_one(&mut grid, &mut position, LEFT),
47+
b'>' => push_one(&mut grid, &mut position, RIGHT),
48+
b'^' => push_two(&mut grid, &mut todo, &mut seen, id, &mut position, UP),
49+
b'v' => push_two(&mut grid, &mut todo, &mut seen, id, &mut position, DOWN),
50+
_ => (),
51+
}
52+
}
53+
54+
gps(&grid, b'[')
55+
}
56+
57+
fn push_one(grid: &mut Grid<u8>, start: &mut Point, direction: Point) {
58+
let mut position = *start;
59+
let mut size = 1;
60+
61+
loop {
62+
match grid[position] {
63+
b'#' => return,
64+
b'.' => break,
65+
_ => {
66+
position += direction;
67+
size += 1;
68+
}
69+
}
70+
}
71+
72+
let mut previous = b'.';
73+
let mut position = *start;
74+
75+
for _ in 0..size {
76+
swap(&mut grid[position], &mut previous);
77+
position += direction;
78+
}
79+
80+
*start += direction;
81+
}
82+
83+
fn push_two(grid: &mut Grid<u8>, todo: &mut Vec<Point>, seen: &mut Grid<usize>, id: usize, start: &mut Point, direction: Point) {
84+
let mut index = 0;
85+
86+
todo.clear();
87+
todo.push(*start);
88+
89+
while index < todo.len() {
90+
let next = todo[index] + direction;
91+
index += 1;
92+
93+
let other = match grid[next] {
94+
b'#' => return,
95+
b'[' => RIGHT,
96+
b']' => LEFT,
97+
_ => continue,
98+
};
99+
100+
let first = next;
101+
if seen[first] != id {
102+
seen[first] = id;
103+
todo.push(first);
104+
}
105+
106+
let second = next + other;
107+
if seen[second] != id {
108+
seen[second] = id;
109+
todo.push(second);
110+
}
111+
}
112+
113+
for &point in todo.iter().rev() {
114+
grid[point + direction] = grid[point];
115+
grid[point] = b'.';
116+
}
117+
118+
*start += direction;
119+
}
120+
121+
fn stretch(grid: &Grid<u8>) -> Grid<u8> {
122+
let mut next = Grid::new(grid.width * 2, grid.height, b'.');
123+
124+
for y in 0..grid.height {
125+
for x in 0..grid.width {
126+
let (left, right) = match grid[Point::new(x, y)] {
127+
b'#' => (b'#', b'#'),
128+
b'O' => (b'[', b']'),
129+
b'@' => (b'@', b'.'),
130+
_ => continue,
131+
};
132+
133+
next[Point::new(2 * x, y)] = left;
134+
next[Point::new(2 * x + 1, y)] = right;
135+
}
136+
}
137+
138+
next
139+
}
140+
141+
fn gps(grid: &Grid<u8>, needle: u8) -> i32 {
142+
let mut result = 0;
143+
144+
for y in 0..grid.height {
145+
for x in 0..grid.width {
146+
let point = Point::new(x, y);
147+
if grid[point] == needle {
148+
result += 100 * point.y + point.x;
149+
}
150+
}
151+
}
152+
153+
result
154+
}

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
84+
day14, day15
8585
);

tests/year2024/day15.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
use aoc::year2024::day15::*;
2+
3+
const EXAMPLE: &str = "\
4+
##########
5+
#..O..O.O#
6+
#......O.#
7+
#.OO..O.O#
8+
9+
#O#..O...#
10+
#O..O..O.#
11+
#.OO.O.OO#
12+
#....O...#
13+
##########
14+
15+
<vv>^<v^>v>^vv^v>v<>v^v<v<^vv<<<^><<><>>v<vvv<>^v^>^<<<><<v<<<v^vv^v>^
16+
vvv<<^>^v^^><<>>><>^<<><^vv^^<>vvv<>><^^v>^>vv<>v<<<<v<^v>^<^^>>>^<v<v
17+
><>vv>v^v^<>><>>>><^^>vv>v<^^^>>v^v^<^^>v^^>v^<^v>v<>>v^v^<v>v^^<^^vv<
18+
<<v<^>>^^^^>>>v^<>vvv^><v<<<>^^^vv^<vvv>^>v<^^^^v<>^>vvvv><>>v^<<^^^^^
19+
^><^><>>><>^^<<^^v>>><^<v>^<vv>>v>>>^v><>^v><<<<v>>v<v<v>vvv>^<><<>^><
20+
^>><>^v<><^vvv<^^<><v<<<<<><^v<<<><<<^^<v<^^^><^>>^<v^><<<^>>^v<v^v<v^
21+
>^>>^v>vv>^<<^v<>><<><<v<<v><>v<^vv<<<>^^v^>^^>>><<^v>>v^v><^^>>^<>vv^
22+
<><^^>^^^<><vvvvv^v<v<<>^v<v>v<<^><<><<><<<^^<<<^<<>><<><^^^>^^<>^>v<>
23+
^^>vv<^v^v<vv>^<><v<^v>^^^>>>^^vvv^>vvv<>>>^<^>>>>>^<<^v>^vvv<>^<><<v>
24+
v^^>>><<^^<>>^v^<v^vv<>v^<<>^<^v^v><^<<<><<^<v><v<>vv>>v><v^<vv<>v^<<^";
25+
26+
#[test]
27+
fn part1_test() {
28+
let input = parse(EXAMPLE);
29+
assert_eq!(part1(&input), 10092);
30+
}
31+
32+
#[test]
33+
fn part2_test() {
34+
let input = parse(EXAMPLE);
35+
assert_eq!(part2(&input), 9021);
36+
}

0 commit comments

Comments
 (0)