Skip to content

Commit 7cb0abd

Browse files
committed
Add day 18 solution
1 parent adc693a commit 7cb0abd

File tree

10 files changed

+2421
-0
lines changed

10 files changed

+2421
-0
lines changed
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
package eu.happycoders.adventofcode2022.day18;
2+
3+
import java.util.ArrayDeque;
4+
import java.util.List;
5+
import java.util.Queue;
6+
7+
/**
8+
* Advent of Code 2022 – Object-Oriented Solutions in Java.
9+
*
10+
* <p>A box in which to put the droplet and flood-fill the outside.
11+
*
12+
* @author <a href="mailto:sven@happycoders.eu">Sven Woltmann</a>
13+
*/
14+
class Box {
15+
16+
private final Droplet droplet;
17+
private final int sizeX;
18+
private final int sizeY;
19+
private final int sizeZ;
20+
private final boolean[][][] grid;
21+
22+
private int externalSurfaceArea;
23+
24+
Box(Droplet droplet) {
25+
this.droplet = droplet;
26+
27+
int maxX = 0;
28+
int maxY = 0;
29+
int maxZ = 0;
30+
31+
List<Cube> allCubes = droplet.getAllCubes();
32+
for (Cube cube : allCubes) {
33+
if (cube.x() < 0 || cube.y() < 0 || cube.z() < 0) {
34+
throw new IllegalArgumentException(
35+
"Each cube's x, y, z coordinates must be >= 0; cube = " + cube);
36+
}
37+
maxX = Math.max(maxX, cube.x());
38+
maxY = Math.max(maxY, cube.y());
39+
maxZ = Math.max(maxZ, cube.z());
40+
}
41+
42+
// x, y, z is 0-based, therefore add 1.
43+
// Add two more, so we have at least one area of free cubes on each side.
44+
this.sizeX = maxX + 3;
45+
this.sizeY = maxY + 3;
46+
this.sizeZ = maxZ + 3;
47+
48+
this.grid = new boolean[sizeX][sizeY][sizeZ];
49+
}
50+
51+
void floodFill() {
52+
// As the cubes may have 0 as X, Y, Z coordinates, our grid starts at (-1, -1, -1).
53+
Cube startCube = new Cube(-1, -1, -1);
54+
fillGridAt(startCube);
55+
56+
Queue<Cube> queue = new ArrayDeque<>();
57+
queue.add(startCube);
58+
59+
// Now we take one from the queue, fill all empty neighbors and add them to the queue.
60+
// Empty means there's no steam and no lava.
61+
// And whenever there's lava, we increase the externalSurfaceArea by 1.
62+
while (!queue.isEmpty()) {
63+
Cube cube = queue.poll();
64+
fillIfEmpty(cube.left(), queue);
65+
fillIfEmpty(cube.right(), queue);
66+
fillIfEmpty(cube.top(), queue);
67+
fillIfEmpty(cube.bottom(), queue);
68+
fillIfEmpty(cube.front(), queue);
69+
fillIfEmpty(cube.back(), queue);
70+
}
71+
}
72+
73+
private void fillIfEmpty(Cube cube, Queue<Cube> queue) {
74+
if (!isInGrid(cube) || gridFilledAt(cube)) {
75+
return;
76+
}
77+
78+
if (droplet.contains(cube)) {
79+
externalSurfaceArea++;
80+
} else {
81+
fillGridAt(cube);
82+
queue.add(cube);
83+
}
84+
}
85+
86+
private boolean isInGrid(Cube cube) {
87+
return cube.x() + 1 >= 0
88+
&& cube.x() + 1 < sizeX
89+
&& cube.y() + 1 >= 0
90+
&& cube.y() + 1 < sizeY
91+
&& cube.z() + 1 >= 0
92+
&& cube.z() + 1 < sizeZ;
93+
}
94+
95+
private boolean gridFilledAt(Cube cube) {
96+
return grid[cube.x() + 1][cube.y() + 1][cube.z() + 1];
97+
}
98+
99+
private void fillGridAt(Cube cube) {
100+
grid[cube.x() + 1][cube.y() + 1][cube.z() + 1] = true;
101+
}
102+
103+
public int getExternalSurfaceArea() {
104+
return externalSurfaceArea;
105+
}
106+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package eu.happycoders.adventofcode2022.day18;
2+
3+
/**
4+
* Advent of Code 2022 – Object-Oriented Solutions in Java.
5+
*
6+
* <p>A single cube consisting of X, Y, and Z coordinates.
7+
*
8+
* @author <a href="mailto:sven@happycoders.eu">Sven Woltmann</a>
9+
*/
10+
@SuppressWarnings("PMD.ShortVariable") // x, y, and z are OK!
11+
record Cube(int x, int y, int z) {
12+
Cube left() {
13+
return new Cube(x - 1, y, z);
14+
}
15+
16+
Cube right() {
17+
return new Cube(x + 1, y, z);
18+
}
19+
20+
Cube back() {
21+
return new Cube(x, y - 1, z);
22+
}
23+
24+
Cube front() {
25+
return new Cube(x, y + 1, z);
26+
}
27+
28+
Cube top() {
29+
return new Cube(x, y, z + 1);
30+
}
31+
32+
Cube bottom() {
33+
return new Cube(x, y, z - 1);
34+
}
35+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package eu.happycoders.adventofcode2022.day18;
2+
3+
import java.util.List;
4+
import java.util.regex.Matcher;
5+
import java.util.regex.Pattern;
6+
7+
/**
8+
* Advent of Code 2022 – Object-Oriented Solutions in Java.
9+
*
10+
* <p>Parses the input string into a list of cubes.
11+
*
12+
* @author <a href="mailto:sven@happycoders.eu">Sven Woltmann</a>
13+
*/
14+
class CubesParser {
15+
16+
private static final Pattern PATTERN = Pattern.compile("(\\d+),(\\d+),(\\d+)");
17+
18+
static List<Cube> parse(String input) {
19+
return input.lines().map(CubesParser::parseCube).toList();
20+
}
21+
22+
@SuppressWarnings("PMD.ShortVariable") // x, y, and z are OK!
23+
private static Cube parseCube(String input) {
24+
Matcher matcher = PATTERN.matcher(input);
25+
if (!matcher.matches()) {
26+
throw new IllegalArgumentException(input);
27+
}
28+
29+
int x = Integer.parseInt(matcher.group(1));
30+
int y = Integer.parseInt(matcher.group(2));
31+
int z = Integer.parseInt(matcher.group(3));
32+
33+
return new Cube(x, y, z);
34+
}
35+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package eu.happycoders.adventofcode2022.day18;
2+
3+
import java.util.List;
4+
5+
/**
6+
* Advent of Code 2022 – Object-Oriented Solutions in Java.
7+
*
8+
* <p>Puzzle solver for day 18.
9+
*
10+
* @author <a href="mailto:sven@happycoders.eu">Sven Woltmann</a>
11+
*/
12+
class Day18Solver {
13+
14+
static int solveTask1(String input) {
15+
List<Cube> cubes = CubesParser.parse(input);
16+
Droplet droplet = new Droplet(cubes);
17+
return droplet.getSurfaceArea();
18+
}
19+
20+
static int solveTask2(String input) {
21+
List<Cube> cubes = CubesParser.parse(input);
22+
Droplet droplet = new Droplet(cubes);
23+
Box box = new Box(droplet);
24+
box.floodFill();
25+
return box.getExternalSurfaceArea();
26+
}
27+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package eu.happycoders.adventofcode2022.day18;
2+
3+
import java.util.HashSet;
4+
import java.util.List;
5+
import java.util.Set;
6+
7+
/**
8+
* Advent of Code 2022 – Object-Oriented Solutions in Java.
9+
*
10+
* <p>A lava droplet consisting of cubes.
11+
*
12+
* @author <a href="mailto:sven@happycoders.eu">Sven Woltmann</a>
13+
*/
14+
class Droplet {
15+
16+
private final Set<Cube> cubes;
17+
18+
Droplet(List<Cube> cubes) {
19+
this.cubes = new HashSet<>(cubes);
20+
}
21+
22+
List<Cube> getAllCubes() {
23+
return List.copyOf(cubes);
24+
}
25+
26+
boolean contains(Cube cube) {
27+
return cubes.contains(cube);
28+
}
29+
30+
int getSurfaceArea() {
31+
int result = 0;
32+
for (Cube coordinate : cubes) {
33+
result += countNonConnectedSides(coordinate);
34+
}
35+
return result;
36+
}
37+
38+
private int countNonConnectedSides(Cube coordinate) {
39+
int connected = 0;
40+
if (cubes.contains(coordinate.left())) {
41+
connected++;
42+
}
43+
if (cubes.contains(coordinate.right())) {
44+
connected++;
45+
}
46+
if (cubes.contains(coordinate.front())) {
47+
connected++;
48+
}
49+
if (cubes.contains(coordinate.back())) {
50+
connected++;
51+
}
52+
if (cubes.contains(coordinate.top())) {
53+
connected++;
54+
}
55+
if (cubes.contains(coordinate.bottom())) {
56+
connected++;
57+
}
58+
return 6 - connected;
59+
}
60+
}

0 commit comments

Comments
 (0)