Skip to content

Commit 66c8b4b

Browse files
committed
aoc 2024 day 16
1 parent 4ea1bb5 commit 66c8b4b

File tree

15 files changed

+241
-18
lines changed

15 files changed

+241
-18
lines changed

adventofcode/README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1454,7 +1454,7 @@
14541454
[20232402tests]: src/test/java/org/ck/adventofcode/year2023/Day24Test.java
14551455
[20232501tests]: src/test/java/org/ck/adventofcode/year2023/Day25Test.java
14561456

1457-
# 2024 (30/49)
1457+
# 2024 (32/49)
14581458

14591459
| # | Name | Solution | Test |
14601460
|---------:|---------------------------------------------------|:------------------------------------:|:---------------------------------:|
@@ -1488,8 +1488,8 @@
14881488
| 20241402 | [Day 14: Restroom Redoubt - Part 2][20241402] | ✅[💾][20241402solution] | ✅[💾][20241402tests] |
14891489
| 20241501 | [Day 15: Warehouse Woes][20241501] | ✅[💾][20241501solution] | ✅[💾][20241501tests] |
14901490
| 20241502 | [Day 15: Warehouse Woes - Part 2][20241502] | ✅[💾][20241502solution] | ✅[💾][20241502tests] |
1491-
| 20241601 | [Day 16: ?][20241601] | [💾][20241601solution] | [💾][20241601tests] |
1492-
| 20241602 | [Day 16: ? - Part 2][20241602] | [💾][20241602solution] | [💾][20241602tests] |
1491+
| 20241601 | [Day 16: Reindeer Maze][20241601] | ✅[💾][20241601solution] | ✅[💾][20241601tests] |
1492+
| 20241602 | [Day 16: Reindeer Maze - Part 2][20241602] | ✅[💾][20241602solution] | ✅[💾][20241602tests] |
14931493
| 20241701 | [Day 17: ?][20241701] | [💾][20241701solution] | [💾][20241701tests] |
14941494
| 20241702 | [Day 17: ? - Part 2][20241702] | [💾][20241702solution] | [💾][20241702tests] |
14951495
| 20241801 | [Day 18: ?][20241801] | [💾][20241801solution] | [💾][20241801tests] |
Lines changed: 164 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,187 @@
11
package org.ck.adventofcode.year2024;
22

3-
import java.util.Scanner;
3+
import java.util.*;
4+
import java.util.function.ToLongBiFunction;
5+
import java.util.stream.Collectors;
46
import org.ck.adventofcode.util.AOCSolution;
57
import org.ck.codechallengelib.annotation.Solution;
68

79
@Solution(
810
id = 20241601,
9-
name = "Day 16: ?",
11+
name = "Day 16: Reindeer Maze",
1012
url = "https://adventofcode.com/2024/day/16",
11-
category = "2024",
12-
solved = false)
13+
category = "2024")
1314
@Solution(
1415
id = 20241602,
15-
name = "Day 16: ? - Part 2",
16+
name = "Day 16: Reindeer Maze - Part 2",
1617
url = "https://adventofcode.com/2024/day/16#part2",
17-
category = "2024",
18-
solved = false)
18+
category = "2024")
1919
public class Day16 extends AOCSolution {
2020

2121
@Override
2222
protected void runPartOne(final Scanner in) {
23-
run(in);
23+
run(
24+
in,
25+
(cache, end) ->
26+
getMinPoints(cache[end.y()][end.x()]).stream().findFirst().orElseThrow().points());
2427
}
2528

2629
@Override
2730
protected void runPartTwo(final Scanner in) {
28-
run(in);
31+
run(in, this::getUniquePathElements);
2932
}
3033

31-
private void run(final Scanner in) {
32-
print("Whoopsie");
34+
private void run(
35+
final Scanner in, final ToLongBiFunction<CacheValue[][][], Coordinate> getResult) {
36+
final List<String> grid = new ArrayList<>();
37+
38+
Coordinate start = null;
39+
Coordinate end = null;
40+
41+
int row = 0;
42+
while (in.hasNextLine()) {
43+
final String line = in.nextLine();
44+
45+
if (line.contains("S")) {
46+
start = new Coordinate(line.indexOf('S'), row);
47+
}
48+
if (line.contains("E")) {
49+
end = new Coordinate(line.indexOf('E'), row);
50+
}
51+
52+
grid.add(line);
53+
++row;
54+
}
55+
56+
if (start == null || end == null) {
57+
throw new IllegalStateException();
58+
}
59+
60+
final CacheValue[][][] cache = getCacheValues(grid, start);
61+
62+
print(getResult.applyAsLong(cache, end));
63+
}
64+
65+
private static CacheValue[][][] getCacheValues(final List<String> grid, final Coordinate start) {
66+
final Queue<State> queue = new PriorityQueue<>(Comparator.comparingLong(State::points));
67+
queue.add(new State(new Position(start, Direction.EAST), null, 0));
68+
69+
final CacheValue[][][] cache = new CacheValue[grid.size()][grid.getFirst().length()][4];
70+
for (int y = 0; y < cache.length; ++y) {
71+
for (int x = 0; x < cache.length; ++x) {
72+
for (int direction = 0; direction < 4; ++direction) {
73+
cache[y][x][direction] = new CacheValue(Long.MAX_VALUE, new HashSet<>());
74+
}
75+
}
76+
}
77+
78+
while (!queue.isEmpty()) {
79+
final State state = queue.poll();
80+
final Position current = state.current();
81+
final Coordinate coordinate = current.coordinate();
82+
final Direction direction = current.direction();
83+
final long points = state.points();
84+
85+
if (cache[coordinate.y()][coordinate.x()][direction.ordinal()].points() < points) {
86+
continue;
87+
}
88+
cache[coordinate.y()][coordinate.x()][direction.ordinal()] =
89+
new CacheValue(points, cache[coordinate.y()][coordinate.x()][direction.ordinal()].from());
90+
if (state.last() != null) {
91+
cache[coordinate.y()][coordinate.x()][direction.ordinal()].from().add(state.last());
92+
}
93+
94+
final Position next = direction.next(current);
95+
if (grid.get(next.coordinate().y()).charAt(next.coordinate().x()) != '#') {
96+
queue.add(new State(next, current, points + 1));
97+
}
98+
99+
queue.add(new State(direction.turnCW(current), current, points + 1000));
100+
queue.add(new State(direction.turnCCW(current), current, points + 1000));
101+
}
102+
return cache;
103+
}
104+
105+
private Set<CacheValue> getMinPoints(final CacheValue[] cache) {
106+
final long min =
107+
Math.min(
108+
Math.min(cache[0].points(), cache[1].points()),
109+
Math.min(cache[2].points(), cache[3].points()));
110+
111+
return Arrays.stream(cache).filter(entry -> entry.points() == min).collect(Collectors.toSet());
112+
}
113+
114+
private int getUniquePathElements(final CacheValue[][][] cache, final Coordinate end) {
115+
final Queue<Position> queue =
116+
getMinPoints(cache[end.y()][end.x()]).stream()
117+
.map(CacheValue::from)
118+
.flatMap(Set::stream)
119+
.distinct()
120+
.collect(Collectors.toCollection(LinkedList::new));
121+
final Set<Coordinate> pathPieces = new HashSet<>();
122+
123+
while (!queue.isEmpty()) {
124+
final Position position = queue.poll();
125+
126+
pathPieces.add(position.coordinate());
127+
128+
queue.addAll(
129+
cache[position.coordinate().y()][position.coordinate().x()][
130+
position.direction().ordinal()]
131+
.from());
132+
}
133+
134+
return pathPieces.size() + 1;
135+
}
136+
137+
private record CacheValue(long points, Set<Position> from) {}
138+
139+
private record State(Position current, Position last, long points) {}
140+
141+
private record Position(Coordinate coordinate, Direction direction) {}
142+
143+
private record Coordinate(int x, int y) {}
144+
145+
private enum Direction {
146+
NORTH(0, -1),
147+
EAST(1, 0),
148+
SOUTH(0, 1),
149+
WEST(-1, 0);
150+
151+
private final int deltaX;
152+
private final int deltaY;
153+
154+
Direction(int deltaX, int deltaY) {
155+
this.deltaX = deltaX;
156+
this.deltaY = deltaY;
157+
}
158+
159+
public Position turnCW(final Position current) {
160+
return new Position(
161+
current.coordinate(),
162+
switch (this) {
163+
case NORTH -> Direction.EAST;
164+
case EAST -> Direction.SOUTH;
165+
case SOUTH -> Direction.WEST;
166+
case WEST -> Direction.NORTH;
167+
});
168+
}
169+
170+
public Position turnCCW(final Position current) {
171+
return new Position(
172+
current.coordinate(),
173+
switch (this) {
174+
case NORTH -> Direction.WEST;
175+
case EAST -> Direction.NORTH;
176+
case SOUTH -> Direction.EAST;
177+
case WEST -> Direction.SOUTH;
178+
});
179+
}
180+
181+
public Position next(Position current) {
182+
return new Position(
183+
new Coordinate(current.coordinate().x() + deltaX, current.coordinate().y() + deltaY),
184+
current.direction());
185+
}
33186
}
34187
}

adventofcode/src/test/java/org/ck/adventofcode/year2024/Day16Test.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,18 @@
11
package org.ck.adventofcode.year2024;
22

33
import org.ck.adventofcode.util.BaseAOCTest;
4-
import org.junit.jupiter.api.Disabled;
54
import org.junit.jupiter.params.ParameterizedTest;
65
import org.junit.jupiter.params.provider.ValueSource;
76

8-
@Disabled
97
class Day16Test extends BaseAOCTest {
108
@ParameterizedTest
11-
@ValueSource(strings = {"01a"})
9+
@ValueSource(strings = {"01a", "01b"})
1210
void testPartOneExamples(final String name) throws Exception {
1311
runTest(new Day16()::partOne, "day16/%s".formatted(name));
1412
}
1513

1614
@ParameterizedTest
17-
@ValueSource(strings = {"02a"})
15+
@ValueSource(strings = {"02a", "02b"})
1816
void testPartTwoExamples(final String name) throws Exception {
1917
runTest(new Day16()::partTwo, "day16/%s".formatted(name));
2018
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
127520

adventofcode/src/test/resources/org/ck/adventofcode/year2024/day16/01.txt

Lines changed: 1 addition & 0 deletions
Large diffs are not rendered by default.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
7036
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+
###############
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
11048
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+
#################
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
565

0 commit comments

Comments
 (0)