Skip to content

Commit 4aa6730

Browse files
committed
Day 14
1 parent 8baf857 commit 4aa6730

File tree

2 files changed

+214
-0
lines changed

2 files changed

+214
-0
lines changed

src/test/java/com/macasaet/Day14.java

Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
package com.macasaet;
2+
3+
import org.junit.jupiter.api.Test;
4+
5+
import java.util.Arrays;
6+
import java.util.Collection;
7+
import java.util.Collections;
8+
import java.util.HashMap;
9+
import java.util.List;
10+
import java.util.Map;
11+
import java.util.stream.StreamSupport;
12+
13+
/**
14+
* --- Day 14: Regolith Reservoir ---
15+
* <a href="https://adventofcode.com/2022/day/14">https://adventofcode.com/2022/day/14</a>
16+
*/
17+
public class Day14 {
18+
19+
public enum Cell {
20+
ROCK,
21+
SAND
22+
}
23+
24+
record Coordinate(int verticalDepth, int horizontalOffset) {
25+
26+
public static Coordinate parse(final String string) {
27+
final var components = string.split(",");
28+
final var verticalDepth = Integer.parseInt(components[1]);
29+
final var horizontalOffset = Integer.parseInt(components[0]);
30+
return new Coordinate(verticalDepth, horizontalOffset);
31+
}
32+
}
33+
34+
public record Cave(Map<Integer, Map<Integer, Cell>> grid, int maxDepth, int minHorizontalOffset, int maxHorizontalOffset) {
35+
36+
public int pourSandIntoAbyss() {
37+
int settledSand = 0;
38+
while(true) {
39+
var fallingSandCoordinate = new Coordinate(0, 500);
40+
while(true) {
41+
final var next = getNextCoordinate(fallingSandCoordinate, null);
42+
if(next != null) {
43+
fallingSandCoordinate = next;
44+
if(fallingSandCoordinate.verticalDepth() >= maxDepth()) {
45+
return settledSand;
46+
}
47+
} else {
48+
final var row = grid.computeIfAbsent(fallingSandCoordinate.verticalDepth(), key -> new HashMap<>());
49+
row.put(fallingSandCoordinate.horizontalOffset(), Cell.SAND);
50+
settledSand++;
51+
break;
52+
}
53+
}
54+
}
55+
}
56+
57+
public int fillAperture() {
58+
int settledSand = 0;
59+
while(true) {
60+
var fallingSandCoordinate = new Coordinate(0, 500);
61+
while(true) {
62+
final var next = getNextCoordinate(fallingSandCoordinate, floorDepth());
63+
if(next != null) {
64+
fallingSandCoordinate = next;
65+
} else {
66+
final var secondRow = grid().computeIfAbsent(1, key -> new HashMap<>());
67+
if(secondRow.containsKey(499) && secondRow.containsKey(500) && secondRow.containsKey(501)) {
68+
return settledSand + 1;
69+
}
70+
final var row = grid.computeIfAbsent(fallingSandCoordinate.verticalDepth(), key -> new HashMap<>());
71+
row.put(fallingSandCoordinate.horizontalOffset(), Cell.SAND);
72+
settledSand++;
73+
break;
74+
}
75+
}
76+
}
77+
}
78+
79+
int floorDepth() {
80+
return maxDepth() + 2;
81+
}
82+
83+
Coordinate getNextCoordinate(final Coordinate start, Integer floorDepth) {
84+
final var x = start.verticalDepth();
85+
final var y = start.horizontalOffset();
86+
if(floorDepth != null && x + 1 >= floorDepth) {
87+
return null;
88+
}
89+
final var nextRow = grid().computeIfAbsent(x + 1, key -> new HashMap<>());
90+
if(!nextRow.containsKey(y)) {
91+
return new Coordinate(x + 1, y);
92+
} else if(!nextRow.containsKey(y - 1)) {
93+
return new Coordinate(x + 1, y - 1);
94+
} else if(!nextRow.containsKey(y + 1)) {
95+
return new Coordinate(x + 1, y + 1);
96+
}
97+
return null;
98+
}
99+
100+
public static Cave parse(final Collection<? extends String> lines) {
101+
int maxDepth = 0;
102+
int maxHorizontalOffset = Integer.MIN_VALUE;
103+
int minHorizontalOffset = Integer.MAX_VALUE;
104+
105+
final var grid = new HashMap<Integer, Map<Integer, Cell>>();
106+
for(final var line : lines) {
107+
final var rockPath = parseRockPaths(line);
108+
var last = rockPath.get(0);
109+
if(last.verticalDepth() > maxDepth) {
110+
maxDepth = last.verticalDepth();
111+
}
112+
if(last.horizontalOffset() < minHorizontalOffset) {
113+
minHorizontalOffset = last.horizontalOffset();
114+
}
115+
if(last.horizontalOffset() > maxHorizontalOffset) {
116+
maxHorizontalOffset = last.horizontalOffset();
117+
}
118+
for(int i = 1; i < rockPath.size(); i++) {
119+
final var current = rockPath.get(i);
120+
if(last.verticalDepth() == current.verticalDepth()) {
121+
// horizontal line
122+
int start;
123+
int end;
124+
if(last.horizontalOffset() < current.horizontalOffset()) {
125+
start = last.horizontalOffset();
126+
end = current.horizontalOffset();
127+
} else {
128+
start = current.horizontalOffset();
129+
end = last.horizontalOffset();
130+
}
131+
final var row = grid.computeIfAbsent(last.verticalDepth(), key -> new HashMap<>());
132+
for(int y = start; y <= end; y++) {
133+
row.put(y, Cell.ROCK);
134+
}
135+
} else {
136+
if(last.horizontalOffset() != current.horizontalOffset()) {
137+
throw new IllegalStateException("Line segments are not on the same vertical axis");
138+
}
139+
// vertical line
140+
int start;
141+
int end;
142+
if(last.verticalDepth() < current.verticalDepth()) {
143+
start = last.verticalDepth();
144+
end = current.verticalDepth();
145+
} else {
146+
start = current.verticalDepth();
147+
end = last.verticalDepth();
148+
}
149+
for(int x = start; x <= end; x++) {
150+
final var row = grid.computeIfAbsent(x, key -> new HashMap<>());
151+
row.put(last.horizontalOffset(), Cell.ROCK);
152+
}
153+
}
154+
if(current.verticalDepth() > maxDepth) {
155+
maxDepth = current.verticalDepth();
156+
}
157+
if(current.horizontalOffset() < minHorizontalOffset) {
158+
minHorizontalOffset = current.horizontalOffset();
159+
}
160+
if(current.horizontalOffset() > maxHorizontalOffset) {
161+
maxHorizontalOffset = current.horizontalOffset();
162+
}
163+
last = current;
164+
}
165+
}
166+
return new Cave(grid, maxDepth, minHorizontalOffset, maxHorizontalOffset);
167+
}
168+
169+
static List<Coordinate> parseRockPaths(final String line) {
170+
return Arrays.stream(line.split(" -> ")).map(Coordinate::parse).toList();
171+
}
172+
173+
@Override
174+
public String toString() {
175+
final var buffer = new StringBuilder();
176+
for(int i = 0; i <= floorDepth(); i++) {
177+
buffer.append(i).append(' ');
178+
final var row = grid.getOrDefault(i, Collections.emptyMap());
179+
for(int j = minHorizontalOffset(); j <= maxHorizontalOffset(); j++) {
180+
final var cell = row.get(j);
181+
final char marker = cell == null ? ' ' : Cell.ROCK.equals(cell) ? '#' : 'o';
182+
buffer.append(marker);
183+
}
184+
buffer.append('\n');
185+
}
186+
return buffer.toString();
187+
}
188+
}
189+
190+
protected Cave getInput() {
191+
final var lines = StreamSupport.stream(new LineSpliterator("day-14.txt"), false)
192+
.toList();
193+
return Cave.parse(lines);
194+
}
195+
196+
@Test
197+
public final void part1() {
198+
final var cave = getInput();
199+
final var result = cave.pourSandIntoAbyss();
200+
201+
System.out.println("Part 1: " + result);
202+
}
203+
204+
@Test
205+
public final void part2() {
206+
final var cave = getInput();
207+
final var result = cave.fillAperture();
208+
209+
System.out.println("Part 2: " + result);
210+
}
211+
212+
}

src/test/resources/sample/day-14.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
498,4 -> 498,6 -> 496,6
2+
503,4 -> 502,4 -> 502,9 -> 494,9

0 commit comments

Comments
 (0)