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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy