Skip to content
Snippets Groups Projects
Commit 81be6e77 authored by Christopher Bohn's avatar Christopher Bohn :thinking:
Browse files

Completed Year 2022 Day 14

parent 2aea3789
No related branches found
No related tags found
No related merge requests found
......@@ -543,7 +543,28 @@ The subproblems are
Since I created a `compareTo()` method as part of Part 1, Part 2 is easy.
## Day 14
## Day 1
- [The problem](https://adventofcode.com/2022/day/14)
- [The solution](src/main/java/edu/unl/cse/bohn/year2022/Day14.java)
### Part 1
The subproblems are
- Determine which locations are blocked
- Determine where a unit of sand moves to
- Can it move?
- Down, diagonally left, diagonally right?
- Determine the final status of a unit of sand
- Stationary, blocking a location
- Falling forever
### Part 2
Same subproblems, except that falling forever isn't an option.
Instead, we'll have to pretend there's an infinitely-long floor.
## Day 15
(coming soon)
package edu.unl.cse.bohn.year2022;
import edu.unl.cse.bohn.Puzzle;
import java.util.*;
@SuppressWarnings("unused")
public class Day14 extends Puzzle {
public Day14(boolean isProductionReady) {
super(isProductionReady);
sampleData = """
498,4 -> 498,6 -> 496,6
503,4 -> 502,4 -> 502,9 -> 494,9""";
}
public static final int SAND_ORIGIN = 500;
public static final boolean verbose = false;
@Override
public long computePart1(List<String> data) {
for (String datum : data) {
Location.block(datum);
}
int amountOfRestingSand = 0;
Sand sand;
do {
sand = new Sand();
//noinspection StatementWithEmptyBody
while (sand.fall() && !sand.isFallingForever()) {
}
if (sand.isStationary()) amountOfRestingSand++;
} while (!sand.isFallingForever());
return amountOfRestingSand;
}
@Override
public long computePart2(List<String> data) {
Location.reset();
for (String datum : data) {
Location.block(datum);
}
Location.addFloor();
int amountOfRestingSand = 0;
Sand sand;
do {
sand = new Sand();
//noinspection StatementWithEmptyBody
while (sand.fall()) {
}
amountOfRestingSand++;
} while (!Location.isBlocked(SAND_ORIGIN, 0));
return amountOfRestingSand;
}
private record Location(int x, int y) {
private static Set<Location> blockedLocations = new HashSet<>();
private static int maximumDepth = Integer.MIN_VALUE;
private static boolean hasFloor = false;
public static void block(int x, int y) {
blockedLocations.add(new Location(x, y));
if (verbose) {
System.out.println("Blocking (" + x + "," + y + ")"
+ ((y > maximumDepth) ? " ** new maximum depth **" : ""));
}
if (!hasFloor && y > maximumDepth) {
maximumDepth = y;
}
}
public static boolean isBlocked(int x, int y) {
return (hasFloor && y >= maximumDepth + 2) || blockedLocations.contains(new Location(x, y));
}
public static void block(String structure) {
if (structure.contains(" -> ")) {
int firstArrowIndex = structure.indexOf(" -> ");
int[] firstPoint = Arrays.stream(structure.substring(0, firstArrowIndex).strip().split(","))
.mapToInt(Integer::parseInt).toArray();
String restOftheStructure = structure.substring(firstArrowIndex + " -> ".length());
int endOfNextPointIndex = restOftheStructure.indexOf(" -> ");
endOfNextPointIndex = endOfNextPointIndex == -1 ? restOftheStructure.length() : endOfNextPointIndex;
int[] nextPoint = Arrays.stream(restOftheStructure.substring(0, endOfNextPointIndex).strip().split(","))
.mapToInt(Integer::parseInt).toArray();
int x = firstPoint[0];
int y = firstPoint[1];
while (x != nextPoint[0] || y != nextPoint[1]) {
Location.block(x, y);
if (x < nextPoint[0]) x++;
if (x > nextPoint[0]) x--;
if (y < nextPoint[1]) y++;
if (y > nextPoint[1]) y--;
}
block(restOftheStructure);
} else {
int[] coordinates = Arrays.stream(structure.strip().split(",")).mapToInt(Integer::parseInt).toArray();
block(coordinates[0], coordinates[1]);
}
}
public static int getDeepestDepths() {
return maximumDepth;
}
public static void reset() {
blockedLocations = new HashSet<>();
maximumDepth = Integer.MIN_VALUE;
hasFloor = false;
}
public static void addFloor() {
hasFloor = true;
}
public static void removeFloor() {
hasFloor = false;
}
@Override
public boolean equals(Object other) {
if (this == other) return true;
if (!(other instanceof Location location)) return false;
return x == location.x && y == location.y;
}
}
private static class Sand {
private int x, y;
public Sand() {
x = SAND_ORIGIN;
y = 0;
}
/**
* Causes a grain of sand to move if it can. If (x,y+1) is unblocked, then the sand moves to (x,y+1).
* Otherwise, if (x-1,y+1) is unblocked, then the sand moves to (x-1,y+1).
* Otherwise, if (x+1,y+1) is unblocked, then the sand moves to (x+1,y+1).
* Otherwise, the sand remains stationary.
*
* @return <code>true</code> if the sand moves, <code>false</code> if the sand remains stationary
*/
public boolean fall() {
boolean moved = false;
if (!Location.isBlocked(x, y + 1)) {
y++;
moved = true;
} else if (!Location.isBlocked(x - 1, y + 1)) {
x--;
y++;
moved = true;
} else if (!Location.isBlocked(x + 1, y + 1)) {
x++;
y++;
moved = true;
} else {
Location.block(x, y);
if (verbose) {
System.out.println("Sand is resting at " + x + "," + y);
}
}
return moved;
}
public boolean isStationary() {
return Location.isBlocked(x, y + 1) && Location.isBlocked(x - 1, y + 1) && Location.isBlocked(x + 1, y + 1);
}
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
public boolean isFallingForever() {
if (verbose && y > Location.getDeepestDepths()) {
System.out.println("Sand at " + x + "," + y + " is falling forever");
}
return y > Location.getDeepestDepths();
}
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment