From 2803b323f6fa72411fd0a96b15fe5b4b31416f6d Mon Sep 17 00:00:00 2001 From: MK13 Date: Sat, 13 Dec 2025 00:23:31 +0100 Subject: [PATCH] Day 7 Off-heap --- .../de/advent_of_code_2025/day7/Main3.java | 142 ++++++++++++------ 1 file changed, 98 insertions(+), 44 deletions(-) diff --git a/src/main/java/de/advent_of_code_2025/day7/Main3.java b/src/main/java/de/advent_of_code_2025/day7/Main3.java index 2441aaa..1a3a2e8 100644 --- a/src/main/java/de/advent_of_code_2025/day7/Main3.java +++ b/src/main/java/de/advent_of_code_2025/day7/Main3.java @@ -12,7 +12,11 @@ import java.util.Map; import java.util.concurrent.StructuredTaskScope; import java.util.concurrent.atomic.AtomicLong; +// This needs about 350.000.000GB RAM to complete public class Main3 { + private static final boolean PRINT_TRAVEL = false; + private static final boolean PRINT_COMPLETE = false; + private static final int SKIP_ROWS = 2; private static final long ALIGNMENT = 16; @@ -43,15 +47,8 @@ public class Main3 { for(int i = 0; i < SPLITTER_POSITIONS[0].length; i++) { if(SPLITTER_POSITIONS[0][i]) { try(var scope = StructuredTaskScope.open()) { - int finalI = i; - - // Left - final MemorySegment leftSegment = copyAndSet(initialSegment, arena, 0, i - 1); - scope.fork(() -> travel(counter, leftSegment, arena, 2, finalI - 1)); - - // Right - final MemorySegment rightSegment = copyAndSet(initialSegment, arena, 0, i + 1); - scope.fork(() -> travel(counter, rightSegment, arena, 2, finalI + 1)); + branchLeft(counter, initialSegment, arena, 0, i, scope); + branchRight(counter, initialSegment, arena, 0, i, scope); scope.join(); } @@ -65,39 +62,89 @@ public class Main3 { } private static final void travel(AtomicLong counter, MemorySegment current, Arena arena, int row, int column) { - if(row >= RELEVANT_ROWS - 1) { + if(row >= RELEVANT_ROWS) { counter.incrementAndGet(); - - printAsPuzzle(current); - + if(PRINT_COMPLETE) printAsPuzzle(current); return; } - for(int i = column; i < SPLITTER_POSITIONS[row].length; i++) { - int finalI = i; - try(var scope = StructuredTaskScope.open()) { - if(SPLITTER_POSITIONS[row][i]) { - // Left - final MemorySegment leftSegment = copyAndSet(current, arena, row, i - 1); - scope.fork(() -> travel(counter, leftSegment, arena, row + 2, finalI - 1)); + try(var scope = StructuredTaskScope.open()) { + if(SPLITTER_POSITIONS[row][column]) { // current position is a splitter + branchLeft(counter, current, arena, row, column, scope); + branchRight(counter, current, arena, row, column, scope); + } + else { // The cell below the beam is free + continueDown(counter, current, arena, row, column, scope); + } - // Right - final MemorySegment rightSegment = copyAndSet(current, arena, row, i + 1); - scope.fork(() -> travel(counter, rightSegment, arena, row + 2, finalI + 1)); - } - else { - // The cell under the beam is free - final MemorySegment leftSegment = copyAndSetOnce(current, arena, row + 1, i); - scope.fork(() -> travel(counter, leftSegment, arena, row + 1, finalI)); - } + scope.join(); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } - scope.join(); + private static void continueDown(AtomicLong counter, MemorySegment current, Arena arena, int row, int column, StructuredTaskScope scope) { + final MemorySegment belowSegment = copyAndSetOnce(current, arena, row, column); + int freeRow = row + 1; + boolean free = isFree(belowSegment, freeRow, column); + boolean isSplitter = false; // when we come here first, the down cell is guaranteed to not be a splitter - return; - } catch (InterruptedException e) { - throw new RuntimeException(e); + while(free && !isSplitter) { + set(belowSegment, freeRow, column); + if(PRINT_TRAVEL) System.out.println("Travel from " + (freeRow - 1) + "|" + column + " to " + freeRow + "|" + column + " (DOWN)"); + freeRow += 1; + + if(freeRow < SPLITTER_POSITIONS.length) { + isSplitter = SPLITTER_POSITIONS[freeRow][column]; + } + else { + isSplitter = false; + } + + if(freeRow < RELEVANT_ROWS && !isSplitter) { + free = isFree(belowSegment, freeRow, column); + } + else { + free = false; } } + + if(freeRow < RELEVANT_ROWS && SPLITTER_POSITIONS[freeRow][column]) { + branchLeft(counter, belowSegment, arena, freeRow, column, scope); + branchRight(counter, belowSegment, arena, freeRow, column, scope); + } + else if(freeRow == RELEVANT_ROWS) { + counter.incrementAndGet(); + if(PRINT_COMPLETE) printAsPuzzle(belowSegment); + } + } + + private static void branchRight(AtomicLong counter, MemorySegment current, Arena arena, int row, int column, StructuredTaskScope scope) { + final int newColumn = column + 1; + final int newRow = row + 2; + final MemorySegment rightSegment = copyAndSet(current, arena, row, newColumn); + scope.fork(() -> travel(counter, rightSegment, arena, newRow, newColumn)); + if(PRINT_TRAVEL) System.out.println("Travel from " + row + "|" + column + " to " + newRow + "|" + newColumn); + } + + private static void branchLeft(AtomicLong counter, MemorySegment current, Arena arena, int row, int column, StructuredTaskScope scope) { + final int newColumn = column - 1; + final int newRow = row + 2; + final MemorySegment leftSegment = copyAndSet(current, arena, row, newColumn); + scope.fork(() -> travel(counter, leftSegment, arena, newRow, newColumn)); + if(PRINT_TRAVEL) System.out.println("Travel from " + row + "|" + column + " to " + newRow + "|" + newColumn); + } + + private static final boolean isFree(MemorySegment segment, int row, int column) { + final long offset = calculateOffset(row, column); + final byte current = segment.get(ValueLayout.OfByte.JAVA_BYTE, offset); + final byte bit = calculateBit(column); + + return current == 0 || (current & bit) != bit; + } + + private static byte calculateBit(int column) { + return (byte) (column < 8 ? 7 - column : 7 - (column - ((column / 8) * 8))); } private static final MemorySegment copyAndSetOnce(MemorySegment src, Arena arena, int row, int column) { @@ -111,7 +158,10 @@ public class Main3 { private static final MemorySegment copyAndSet(MemorySegment src, Arena arena, int row, int column) { final MemorySegment copy = arena.allocate(src.byteSize(), ALIGNMENT).copyFrom(src); + // Set the beam in the current row + column set(copy, row, column); + + // and also in the next row (same column) since the row below splitters is always free set(copy, row + 1, column); return copy; @@ -120,8 +170,7 @@ public class Main3 { private static final void set(MemorySegment segment, int row, int column) { final long offset = calculateOffset(row, column); final byte current = segment.get(ValueLayout.OfByte.JAVA_BYTE, offset); - //final byte bit = (byte) ((byte) 7 - (column - (column / 8))); - final byte bit = (byte) (column < 8 ? 7 - column : 7 - (column - ((column / 8) * 8))); + final byte bit = calculateBit(column); segment.set(ValueLayout.OfByte.JAVA_BYTE, offset, (byte) (current | (1 << bit))); } @@ -161,8 +210,11 @@ public class Main3 { } private static final void printAsPuzzle(MemorySegment segment) { + printAsPuzzle(segment, new StringBuilder()); + } + + private static final void printAsPuzzle(MemorySegment segment, StringBuilder sb) { final long size = segment.byteSize(); - final StringBuilder sb = new StringBuilder(); final byte[] bytes = new byte[(int) size]; final Map> rowMap = new HashMap<>(); @@ -178,17 +230,17 @@ public class Main3 { final Byte b = bytes[i]; rowMap.compute(row, (k, v) -> { - if(v == null) { - List value = new ArrayList<>(); + if(v == null) { + List value = new ArrayList<>(); - value.add(b); + value.add(b); - return value; - } + return value; + } - v.add(b); + v.add(b); - return v; + return v; }); if(row != previousRow) { @@ -205,6 +257,8 @@ public class Main3 { String str = s.toString(); + sb.append(String.format("%02d ", e.getKey())); + for(int i = 0; i < str.length(); i++) { boolean isSplitter = false; @@ -231,4 +285,4 @@ public class Main3 { System.out.println(sb); } -} +} \ No newline at end of file