-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathPuzzle16.java
155 lines (138 loc) · 4.51 KB
/
Puzzle16.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
package advent2023;
import static java.lang.Integer.max;
import static java.nio.charset.StandardCharsets.UTF_8;
import static java.util.stream.Collectors.toCollection;
import java.io.InputStream;
import java.util.ArrayDeque;
import java.util.Comparator;
import java.util.Deque;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
/**
* @author Éamonn McManus
*/
public class Puzzle16 {
public static void main(String[] args) throws Exception {
try (InputStream in = Puzzle16.class.getResourceAsStream("puzzle16.txt")) {
String lineString = new String(in.readAllBytes(), UTF_8);
List<String> lines = List.of(lineString.split("\n"));
int tiles = solve(new Beam(0, 0, Dir.RIGHT), lines);
System.out.println("Total " + tiles);
int best = -1;
for (int x = 0; x < lines.get(0).length(); x++) {
int t1 = solve(new Beam(x, 0, Dir.DOWN), lines);
best = max(best, t1);
int t2 = solve(new Beam(x, lines.size() - 1, Dir.UP), lines);
best = max(best, t2);
}
for (int y = 0; y < lines.size(); y++) {
int t1 = solve(new Beam(0, y, Dir.RIGHT), lines);
best = max(best, t1);
int t2 = solve(new Beam(lines.get(0).length() - 1, y, Dir.LEFT), lines);
best = max(best, t2);
}
System.out.println("Best total " + best);
}
}
// A BFS to determine all the positions the given start beam can reach.
// A recursive DFS would also have been possible, and perhaps simpler.
private static int solve(Beam startBeam, List<String> lines) {
Set<Beam> beams = new HashSet<>();
Deque<Beam> queue = new ArrayDeque<>();
queue.add(startBeam);
while (!queue.isEmpty()) {
Beam beam = queue.remove();
if (!beams.add(beam)) {
continue;
}
queue.addAll(advance(beam, lines));
}
Set<Coord> tiles =
beams.stream().map(b -> new Coord(b.x, b.y)).collect(toCollection(TreeSet::new));
return tiles.size();
}
/**
* Given an incoming beam position, advances by one position. This may result in beam splitting,
* hence the list return type.
*/
private static List<Beam> advance(Beam beam, List<String> lines) {
char c = lines.get(beam.y).charAt(beam.x);
List<Beam> beams =
switch (c) {
case '.' -> List.of(beam.advance());
case '-' -> {
if (beam.dir == Dir.LEFT || beam.dir == Dir.RIGHT) {
yield List.of(beam.advance());
} else {
yield List.of(beam.moveLeft(), beam.moveRight());
}
}
case '|' -> {
if (beam.dir == Dir.UP || beam.dir == Dir.DOWN) {
yield List.of(beam.advance());
} else {
yield List.of(beam.moveUp(), beam.moveDown());
}
}
case '/' ->
List.of(
switch (beam.dir) {
case LEFT -> beam.moveDown();
case RIGHT -> beam.moveUp();
case UP -> beam.moveRight();
case DOWN -> beam.moveLeft();
});
case '\\' ->
List.of(
switch (beam.dir) {
case LEFT -> beam.moveUp();
case RIGHT -> beam.moveDown();
case UP -> beam.moveLeft();
case DOWN -> beam.moveRight();
});
default -> throw new AssertionError(c);
};
return beams.stream()
.filter(b -> b.x >= 0 && b.x < lines.get(0).length() && b.y >= 0 && b.y < lines.size())
.toList();
}
record Beam(int x, int y, Dir dir) {
Beam advance() {
return new Beam(x + dir.deltaX, y + dir.deltaY, dir);
}
Beam moveUp() {
return new Beam(x, y - 1, Dir.UP);
}
Beam moveDown() {
return new Beam(x, y + 1, Dir.DOWN);
}
Beam moveLeft() {
return new Beam(x - 1, y, Dir.LEFT);
}
Beam moveRight() {
return new Beam(x + 1, y, Dir.RIGHT);
}
}
record Coord(int x, int y) implements Comparable<Coord> {
private static final Comparator<Coord> COMPARATOR =
Comparator.comparing(Coord::y).thenComparing(Coord::x);
@Override
public int compareTo(Coord that) {
return COMPARATOR.compare(this, that);
}
}
enum Dir {
LEFT(-1, 0),
RIGHT(+1, 0),
UP(0, -1),
DOWN(0, +1);
final int deltaX;
final int deltaY;
private Dir(int deltaX, int deltaY) {
this.deltaX = deltaX;
this.deltaY = deltaY;
}
}
}