-
Notifications
You must be signed in to change notification settings - Fork 0
/
AoC2022_18.java
136 lines (119 loc) Β· 4.49 KB
/
AoC2022_18.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
import static com.github.pareronia.aoc.SetUtils.disjunction;
import static java.util.stream.Collectors.toSet;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Stream;
import com.github.pareronia.aoc.IntegerSequence.Range;
import com.github.pareronia.aoc.geometry3d.Cuboid;
import com.github.pareronia.aoc.geometry3d.Position3D;
import com.github.pareronia.aoc.graph.BFS;
import com.github.pareronia.aocd.Aocd;
import com.github.pareronia.aocd.Puzzle;
public class AoC2022_18 extends AoCBase {
private final Set<Position3D> cubes;
private AoC2022_18(final List<String> input, final boolean debug) {
super(debug);
this.cubes = input.stream()
.map(line -> line.split(","))
.map(splits -> Arrays.stream(splits).mapToInt(Integer::parseInt).toArray())
.map(nums -> Position3D.of(nums[0], nums[1], nums[2]))
.collect(toSet());
}
public static final AoC2022_18 create(final List<String> input) {
return new AoC2022_18(input, false);
}
public static final AoC2022_18 createDebug(final List<String> input) {
return new AoC2022_18(input, true);
}
private int surfaceArea(final Set<Position3D> cubes) {
return (int) cubes.stream()
.flatMap(Position3D::capitalNeighbours)
.filter(n -> !cubes.contains(n))
.count();
}
private Bounds getBounds() {
final var statsX = cubes.stream()
.mapToInt(Position3D::getX).summaryStatistics();
final var statsY = cubes.stream()
.mapToInt(Position3D::getY).summaryStatistics();
final var statsZ = cubes.stream()
.mapToInt(Position3D::getZ).summaryStatistics();
return new Bounds(
Range.between(statsX.getMin(), statsX.getMax()),
Range.between(statsY.getMin(), statsY.getMax()),
Range.between(statsZ.getMin(), statsZ.getMax())
);
}
private Set<Position3D> findOutside(final Bounds bounds) {
final var start = Position3D.of(
bounds.x.getMinimum() - 1,
bounds.y.getMinimum() - 1,
bounds.z.getMinimum() - 1);
final var searchSpace = Cuboid.of(
bounds.x.getMinimum() - 1, bounds.x.getMaximum() + 1,
bounds.y.getMinimum() - 1, bounds.y.getMaximum() + 1,
bounds.z.getMinimum() - 1, bounds.z.getMaximum() + 1);
final Function<Position3D, Stream<Position3D>> adjacent =
pos -> pos.capitalNeighbours()
.filter(searchSpace::contains)
.filter(n -> !this.cubes.contains(n));
return BFS.floodFill(start, adjacent);
}
private Set<Position3D> findInside(final Bounds bounds) {
final var outside = findOutside(bounds);
final Cuboid cuboid = Cuboid.of(
bounds.x.getMinimum(), bounds.x.getMaximum(),
bounds.y.getMinimum(), bounds.y.getMaximum(),
bounds.z.getMinimum(), bounds.z.getMaximum());
return cuboid.positions()
.filter(pos -> !this.cubes.contains(pos) && !outside.contains(pos))
.collect(toSet());
}
@Override
public Integer solvePart1() {
return surfaceArea(this.cubes);
}
@Override
public Integer solvePart2() {
final var inside = findInside(getBounds());
return surfaceArea(disjunction(this.cubes, inside));
}
public static void main(final String[] args) throws Exception {
assert AoC2022_18.createDebug(TEST1).solvePart1() == 10;
assert AoC2022_18.createDebug(TEST2).solvePart1() == 64;
assert AoC2022_18.createDebug(TEST2).solvePart2() == 58;
final Puzzle puzzle = Aocd.puzzle(2022, 18);
final List<String> inputData = puzzle.getInputData();
puzzle.check(
() -> lap("Part 1", AoC2022_18.create(inputData)::solvePart1),
() -> lap("Part 2", AoC2022_18.create(inputData)::solvePart2)
);
}
private static final List<String> TEST1 = splitLines("""
1,1,1
2,1,1
""");
private static final List<String> TEST2 = splitLines("""
2,2,2
1,2,2
3,2,2
2,1,2
2,3,2
2,2,1
2,2,3
2,2,4
2,2,6
1,2,5
3,2,5
2,1,5
2,3,5
""");
private static final record Bounds (
Range x,
Range y,
Range z
) {
}
}