Skip to content

Commit 13de94a

Browse files
committed
Add year 2022 day9
1 parent fac8861 commit 13de94a

File tree

6 files changed

+2170
-8
lines changed

6 files changed

+2170
-8
lines changed

year2022/src/main/java/dev/linl33/adventofcode/year2022/Day8.java

+8-8
Original file line numberDiff line numberDiff line change
@@ -90,14 +90,14 @@ public Integer part2(@NotNull BufferedReader reader) {
9090
var rows = input.length;
9191
var max = -1;
9292
var colBackRef = new int[cols * rows];
93-
var colBackRefPointer = cols - 1;
93+
var colBackRefPointer = 0;
9494
var skippedColumns = new boolean[cols];
9595

9696
for (int treeY = 1; treeY < rows - 1; treeY++) {
9797
colBackRefPointer = treeY * cols;
9898

9999
var row = input[treeY];
100-
var backRef = new int[cols];
100+
var rowBackRef = new int[cols];
101101

102102
for (int treeX = 1; treeX < cols - 1; treeX++) {
103103
colBackRefPointer++;
@@ -110,21 +110,21 @@ public Integer part2(@NotNull BufferedReader reader) {
110110
var t = row.codePointAt(x);
111111
if (t >= tree) {
112112
if (t == tree) {
113-
backRef[x] = treeX;
113+
rowBackRef[x] = treeX;
114114
}
115115
x++;
116116
break;
117117
}
118118

119-
backRef[x] = treeX;
119+
rowBackRef[x] = treeX;
120120
}
121121
score *= (x - 1) - treeX;
122122
// look left
123-
score *= treeX - backRef[treeX];
123+
score *= treeX - rowBackRef[treeX];
124124

125125
var maxPotential = (treeY - colBackRef[colBackRefPointer]) * ((rows - 1) - treeY) * score;
126126
if (maxPotential <= max) {
127-
skippedColumns[treeY] = true;
127+
skippedColumns[treeX] = true;
128128
continue;
129129
}
130130

@@ -148,7 +148,7 @@ public Integer part2(@NotNull BufferedReader reader) {
148148
score *= (y - 1) - treeY;
149149

150150
// look down
151-
if (skippedColumns[treeY]) {
151+
if (skippedColumns[treeX]) {
152152
// if this column had been skipped, colBackRef can only provide a lower bound not the exact index
153153
for (y = treeY - 1; y >= colBackRef[colBackRefPointer]; y--) {
154154
var t = input[y].codePointAt(treeX);
@@ -165,7 +165,7 @@ public Integer part2(@NotNull BufferedReader reader) {
165165
max = Math.max(max, score);
166166

167167
// colBackRef is correct again, re-enable fast path
168-
skippedColumns[treeY] = false;
168+
skippedColumns[treeX] = false;
169169
}
170170
}
171171

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
package dev.linl33.adventofcode.year2022;
2+
3+
import dev.linl33.adventofcode.lib.solution.ByteBufferAdventSolution;
4+
import dev.linl33.adventofcode.lib.solution.NullBufferedReaderSolution;
5+
import dev.linl33.adventofcode.lib.solution.ResourceIdentifier;
6+
import org.jetbrains.annotations.NotNull;
7+
8+
import java.nio.ByteBuffer;
9+
10+
public class Day9 extends AdventSolution2022<Integer, Integer> implements ByteBufferAdventSolution<Integer, Integer>, NullBufferedReaderSolution<Integer, Integer> {
11+
private static final int HASH_TABLE_BUCKET_SIZE = 20;
12+
private static final int HASH_TABLE_BUCKETS = 1024;
13+
14+
public static void main(String[] args) {
15+
new Day9().runAndPrintAll();
16+
}
17+
18+
@Override
19+
public Integer part1(@NotNull ResourceIdentifier identifier) throws Exception {
20+
return ByteBufferAdventSolution.super.part1(identifier);
21+
}
22+
23+
@Override
24+
public Integer part2(@NotNull ResourceIdentifier identifier) throws Exception {
25+
return ByteBufferAdventSolution.super.part2(identifier);
26+
}
27+
28+
@Override
29+
public Integer part1(@NotNull ByteBuffer byteBuffer) {
30+
return countUniqueTailPositions(byteBuffer, 2);
31+
}
32+
33+
@Override
34+
public Integer part2(@NotNull ByteBuffer byteBuffer) {
35+
return countUniqueTailPositions(byteBuffer, 10);
36+
}
37+
38+
private static int countUniqueTailPositions(@NotNull ByteBuffer byteBuffer, int knots) {
39+
var positions = new short[knots * 2];
40+
41+
var visitedTable = new int[HASH_TABLE_BUCKETS * HASH_TABLE_BUCKET_SIZE];
42+
var visitedTableBucketSizes = new int[HASH_TABLE_BUCKETS];
43+
visitedTableBucketSizes[0]++;
44+
var count = 0;
45+
46+
while (byteBuffer.hasRemaining()) {
47+
var dir = byteBuffer.get();
48+
// skip space
49+
byteBuffer.position(byteBuffer.position() + 1);
50+
var magnitude = byteBuffer.get() - '0';
51+
// could be \n or a digit
52+
var magnitudeNext = byteBuffer.get();
53+
54+
if (magnitudeNext != '\n') {
55+
magnitude = magnitude * 10 + (magnitudeNext - '0');
56+
// skip \n
57+
byteBuffer.position(byteBuffer.position() + 1);
58+
}
59+
60+
switch (dir) {
61+
case 'R' -> positions[0] += magnitude;
62+
case 'L' -> positions[0] -= magnitude;
63+
case 'U' -> positions[knots] -= magnitude;
64+
case 'D' -> positions[knots] += magnitude;
65+
default -> throw new IllegalArgumentException();
66+
}
67+
68+
moveKnots:
69+
for (int i = 0; i < magnitude; i++) {
70+
var prevKnotX = positions[0];
71+
var prevKnotY = positions[knots];
72+
for (int x = 1, y = knots + 1; x < knots; x++, y++) {
73+
var currKnotX = positions[x];
74+
var currKnotY = positions[y];
75+
76+
if (!isValid(prevKnotX, prevKnotY, currKnotX, currKnotY)) {
77+
prevKnotX = (positions[x] += Integer.signum(prevKnotX - currKnotX));
78+
prevKnotY = (positions[y] += Integer.signum(prevKnotY - currKnotY));
79+
} else {
80+
// all following knots will not move either
81+
continue moveKnots;
82+
}
83+
}
84+
85+
var tailPosition = positionToInt(positions[knots - 1], positions[knots - 1 + knots]);
86+
var hashKey = Math.abs(tailPosition % HASH_TABLE_BUCKETS);
87+
var hashTableIndex = hashKey * HASH_TABLE_BUCKET_SIZE;
88+
var hashBucketSize = hashTableIndex + visitedTableBucketSizes[hashKey];
89+
for (; hashTableIndex < hashBucketSize; hashTableIndex++) {
90+
if (visitedTable[hashTableIndex] == tailPosition) {
91+
continue moveKnots;
92+
}
93+
}
94+
95+
visitedTable[hashTableIndex] = tailPosition;
96+
visitedTableBucketSizes[hashKey]++;
97+
count++;
98+
}
99+
}
100+
101+
return count + 1;
102+
}
103+
104+
private static boolean isValid(int prevX, int prevY, int currX, int currY) {
105+
return Math.abs(prevX - currX) <= 1 && Math.abs(prevY - currY) <= 1;
106+
}
107+
108+
private static int positionToInt(short x, short y) {
109+
@SuppressWarnings("SuspiciousNameCombination")
110+
var pos = Integer.expand(Short.toUnsignedInt(x), 0b10101010101010101010101010101010)
111+
| Integer.expand(Short.toUnsignedInt(y), 0b01010101010101010101010101010101);
112+
return pos;
113+
}
114+
}

0 commit comments

Comments
 (0)