Skip to content

Commit

Permalink
aoc 2024 day 16
Browse files Browse the repository at this point in the history
  • Loading branch information
TheCK committed Dec 16, 2024
1 parent 4ea1bb5 commit 66c8b4b
Show file tree
Hide file tree
Showing 15 changed files with 241 additions and 18 deletions.
6 changes: 3 additions & 3 deletions adventofcode/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1454,7 +1454,7 @@
[20232402tests]: src/test/java/org/ck/adventofcode/year2023/Day24Test.java
[20232501tests]: src/test/java/org/ck/adventofcode/year2023/Day25Test.java

# 2024 (30/49)
# 2024 (32/49)

| # | Name | Solution | Test |
|---------:|---------------------------------------------------|:------------------------------------:|:---------------------------------:|
Expand Down Expand Up @@ -1488,8 +1488,8 @@
| 20241402 | [Day 14: Restroom Redoubt - Part 2][20241402] | ✅[💾][20241402solution] | ✅[💾][20241402tests] |
| 20241501 | [Day 15: Warehouse Woes][20241501] | ✅[💾][20241501solution] | ✅[💾][20241501tests] |
| 20241502 | [Day 15: Warehouse Woes - Part 2][20241502] | ✅[💾][20241502solution] | ✅[💾][20241502tests] |
| 20241601 | [Day 16: ?][20241601] | [💾][20241601solution] | [💾][20241601tests] |
| 20241602 | [Day 16: ? - Part 2][20241602] | [💾][20241602solution] | [💾][20241602tests] |
| 20241601 | [Day 16: Reindeer Maze][20241601] | ✅[💾][20241601solution] | ✅[💾][20241601tests] |
| 20241602 | [Day 16: Reindeer Maze - Part 2][20241602] | ✅[💾][20241602solution] | ✅[💾][20241602tests] |
| 20241701 | [Day 17: ?][20241701] | [💾][20241701solution] | [💾][20241701tests] |
| 20241702 | [Day 17: ? - Part 2][20241702] | [💾][20241702solution] | [💾][20241702tests] |
| 20241801 | [Day 18: ?][20241801] | [💾][20241801solution] | [💾][20241801tests] |
Expand Down
175 changes: 164 additions & 11 deletions adventofcode/src/main/java/org/ck/adventofcode/year2024/Day16.java
Original file line number Diff line number Diff line change
@@ -1,34 +1,187 @@
package org.ck.adventofcode.year2024;

import java.util.Scanner;
import java.util.*;
import java.util.function.ToLongBiFunction;
import java.util.stream.Collectors;
import org.ck.adventofcode.util.AOCSolution;
import org.ck.codechallengelib.annotation.Solution;

@Solution(
id = 20241601,
name = "Day 16: ?",
name = "Day 16: Reindeer Maze",
url = "https://adventofcode.com/2024/day/16",
category = "2024",
solved = false)
category = "2024")
@Solution(
id = 20241602,
name = "Day 16: ? - Part 2",
name = "Day 16: Reindeer Maze - Part 2",
url = "https://adventofcode.com/2024/day/16#part2",
category = "2024",
solved = false)
category = "2024")
public class Day16 extends AOCSolution {

@Override
protected void runPartOne(final Scanner in) {
run(in);
run(
in,
(cache, end) ->
getMinPoints(cache[end.y()][end.x()]).stream().findFirst().orElseThrow().points());
}

@Override
protected void runPartTwo(final Scanner in) {
run(in);
run(in, this::getUniquePathElements);
}

private void run(final Scanner in) {
print("Whoopsie");
private void run(
final Scanner in, final ToLongBiFunction<CacheValue[][][], Coordinate> getResult) {
final List<String> grid = new ArrayList<>();

Coordinate start = null;
Coordinate end = null;

int row = 0;
while (in.hasNextLine()) {
final String line = in.nextLine();

if (line.contains("S")) {
start = new Coordinate(line.indexOf('S'), row);
}
if (line.contains("E")) {
end = new Coordinate(line.indexOf('E'), row);
}

grid.add(line);
++row;
}

if (start == null || end == null) {
throw new IllegalStateException();
}

final CacheValue[][][] cache = getCacheValues(grid, start);

print(getResult.applyAsLong(cache, end));
}

private static CacheValue[][][] getCacheValues(final List<String> grid, final Coordinate start) {
final Queue<State> queue = new PriorityQueue<>(Comparator.comparingLong(State::points));
queue.add(new State(new Position(start, Direction.EAST), null, 0));

final CacheValue[][][] cache = new CacheValue[grid.size()][grid.getFirst().length()][4];
for (int y = 0; y < cache.length; ++y) {
for (int x = 0; x < cache.length; ++x) {
for (int direction = 0; direction < 4; ++direction) {
cache[y][x][direction] = new CacheValue(Long.MAX_VALUE, new HashSet<>());
}
}
}

while (!queue.isEmpty()) {
final State state = queue.poll();
final Position current = state.current();
final Coordinate coordinate = current.coordinate();
final Direction direction = current.direction();
final long points = state.points();

if (cache[coordinate.y()][coordinate.x()][direction.ordinal()].points() < points) {
continue;
}
cache[coordinate.y()][coordinate.x()][direction.ordinal()] =
new CacheValue(points, cache[coordinate.y()][coordinate.x()][direction.ordinal()].from());
if (state.last() != null) {
cache[coordinate.y()][coordinate.x()][direction.ordinal()].from().add(state.last());
}

final Position next = direction.next(current);
if (grid.get(next.coordinate().y()).charAt(next.coordinate().x()) != '#') {
queue.add(new State(next, current, points + 1));
}

queue.add(new State(direction.turnCW(current), current, points + 1000));
queue.add(new State(direction.turnCCW(current), current, points + 1000));
}
return cache;
}

private Set<CacheValue> getMinPoints(final CacheValue[] cache) {
final long min =
Math.min(
Math.min(cache[0].points(), cache[1].points()),
Math.min(cache[2].points(), cache[3].points()));

return Arrays.stream(cache).filter(entry -> entry.points() == min).collect(Collectors.toSet());
}

private int getUniquePathElements(final CacheValue[][][] cache, final Coordinate end) {
final Queue<Position> queue =
getMinPoints(cache[end.y()][end.x()]).stream()
.map(CacheValue::from)
.flatMap(Set::stream)
.distinct()
.collect(Collectors.toCollection(LinkedList::new));
final Set<Coordinate> pathPieces = new HashSet<>();

while (!queue.isEmpty()) {
final Position position = queue.poll();

pathPieces.add(position.coordinate());

queue.addAll(
cache[position.coordinate().y()][position.coordinate().x()][
position.direction().ordinal()]
.from());
}

return pathPieces.size() + 1;
}

private record CacheValue(long points, Set<Position> from) {}

private record State(Position current, Position last, long points) {}

private record Position(Coordinate coordinate, Direction direction) {}

private record Coordinate(int x, int y) {}

private enum Direction {
NORTH(0, -1),
EAST(1, 0),
SOUTH(0, 1),
WEST(-1, 0);

private final int deltaX;
private final int deltaY;

Direction(int deltaX, int deltaY) {
this.deltaX = deltaX;
this.deltaY = deltaY;
}

public Position turnCW(final Position current) {
return new Position(
current.coordinate(),
switch (this) {
case NORTH -> Direction.EAST;
case EAST -> Direction.SOUTH;
case SOUTH -> Direction.WEST;
case WEST -> Direction.NORTH;
});
}

public Position turnCCW(final Position current) {
return new Position(
current.coordinate(),
switch (this) {
case NORTH -> Direction.WEST;
case EAST -> Direction.NORTH;
case SOUTH -> Direction.EAST;
case WEST -> Direction.SOUTH;
});
}

public Position next(Position current) {
return new Position(
new Coordinate(current.coordinate().x() + deltaX, current.coordinate().y() + deltaY),
current.direction());
}
}
}
Original file line number Diff line number Diff line change
@@ -1,20 +1,18 @@
package org.ck.adventofcode.year2024;

import org.ck.adventofcode.util.BaseAOCTest;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;

@Disabled
class Day16Test extends BaseAOCTest {
@ParameterizedTest
@ValueSource(strings = {"01a"})
@ValueSource(strings = {"01a", "01b"})
void testPartOneExamples(final String name) throws Exception {
runTest(new Day16()::partOne, "day16/%s".formatted(name));
}

@ParameterizedTest
@ValueSource(strings = {"02a"})
@ValueSource(strings = {"02a", "02b"})
void testPartTwoExamples(final String name) throws Exception {
runTest(new Day16()::partTwo, "day16/%s".formatted(name));
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
127520

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
7036
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
###############
#.......#....E#
#.#.###.#.###.#
#.....#.#...#.#
#.###.#####.#.#
#.#.#.......#.#
#.#.#####.###.#
#...........#.#
###.#.#####.#.#
#...#.....#.#.#
#.#.#.###.#.#.#
#.....#...#.#.#
#.###.#.#.#.#.#
#S..#.....#...#
###############
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
11048
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#################
#...#...#...#..E#
#.#.#.#.#.#.#.#.#
#.#.#.#...#...#.#
#.#.#.#.###.#.#.#
#...#.#.#.....#.#
#.#.#.#.#.#####.#
#.#...#.#.#.....#
#.#.#####.#.###.#
#.#.#.......#...#
#.#.###.#####.###
#.#.#...#.....#.#
#.#.#.#####.###.#
#.#.#.........#.#
#.#.#.#########.#
#S#.............#
#################
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
565

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
45
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
###############
#.......#....E#
#.#.###.#.###.#
#.....#.#...#.#
#.###.#####.#.#
#.#.#.......#.#
#.#.#####.###.#
#...........#.#
###.#.#####.#.#
#...#.....#.#.#
#.#.#.###.#.#.#
#.....#...#.#.#
#.###.#.#.#.#.#
#S..#.....#...#
###############
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
64
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#################
#...#...#...#..E#
#.#.#.#.#.#.#.#.#
#.#.#.#...#...#.#
#.#.#.#.###.#.#.#
#...#.#.#.....#.#
#.#.#.#.#.#####.#
#.#...#.#.#.....#
#.#.#####.#.###.#
#.#.#.......#...#
#.#.###.#####.###
#.#.#...#.....#.#
#.#.#.#####.###.#
#.#.#.........#.#
#.#.#.#########.#
#S#.............#
#################

0 comments on commit 66c8b4b

Please sign in to comment.