From 171ea60636ae93cfea4799bb2efc92d3c6a2900f Mon Sep 17 00:00:00 2001 From: mike Date: Fri, 9 Jan 2026 08:57:46 +0100 Subject: [PATCH] Gather data --- src/main/java/puzzle/ExportFormat.java | 2 +- src/main/java/puzzle/SwedishGenerator.java | 102 +++++++----------- .../java/puzzle/SwedishGeneratorTest.java | 14 +-- 3 files changed, 45 insertions(+), 73 deletions(-) diff --git a/src/main/java/puzzle/ExportFormat.java b/src/main/java/puzzle/ExportFormat.java index 73c1d0c..dd80e98 100644 --- a/src/main/java/puzzle/ExportFormat.java +++ b/src/main/java/puzzle/ExportFormat.java @@ -172,7 +172,7 @@ public record ExportFormat() { var d = s.dir(); var cells = new int[s.len()]; - for (var i = 0; i < s.len(); i++) cells[i] = s.pos(i); + for (int i = 0, len = s.len(); i < len; i++) cells[i] = s.pos(i); // Canonicalize: always output right/down String direction; diff --git a/src/main/java/puzzle/SwedishGenerator.java b/src/main/java/puzzle/SwedishGenerator.java index a153321..25e6a83 100644 --- a/src/main/java/puzzle/SwedishGenerator.java +++ b/src/main/java/puzzle/SwedishGenerator.java @@ -1,7 +1,7 @@ package puzzle; -import lombok.Data; import lombok.Getter; +import lombok.val; import puzzle.ExportFormat.Bit; import puzzle.ExportFormat.Bit1029; import puzzle.ExportFormat.Gridded; @@ -105,7 +105,7 @@ public record SwedishGenerator(int[] buff) { Bit seen, byte[] pattern, IntList[] intListBuffer, - int[] undoBuffer) { + int[] undo) { public Context() { this(new int[SIZE], new int[SIZE], new int[SIZE], new int[SIZE], new Bit(), new byte[MAX_WORD_LENGTH], new IntList[MAX_WORD_LENGTH], @@ -388,7 +388,7 @@ public record SwedishGenerator(int[] buff) { public static int offset(long packedPos, int i) { return (int) ((packedPos >> (i * 7)) & 127); } } static void undoPlace(Grid grid, Slot s, int mask) { - for (var i = 0; i < s.len(); i++) { + for (int i = 0, len = s.len(); i < len; i++) { if ((mask & (1L << i)) != 0) { grid.clear(s.pos(i)); } @@ -404,7 +404,7 @@ public record SwedishGenerator(int[] buff) { grid.forEachSetBit71(idx -> { var d = grid.digitAt(idx); var nbrs16 = OFFSETS[d]; - int r = Grid.r(idx), c = Grid.c(idx), rr = r + nbrs16.r, cc = c + nbrs16.c; + int r = Grid.r(idx), c = Grid.c(idx), rr = r + nbrs16.r, cc = c + nbrs16.c; if (rr < 0 || rr >= R || cc < 0 || cc >= C || grid.isDigitAt(rr, cc)) return; long packedPos = 0; var n = 0; @@ -419,26 +419,6 @@ public record SwedishGenerator(int[] buff) { visitor.visit((r << 8) | (c << 4) | d, packedPos, n); } }); - /* for (var rci : IT) { - if (!grid.isDigitAt(rci.i)) continue; - var d = grid.digitAt(rci.i); - var nbrs16 = OFFSETS[d]; - int rr = rci.r + nbrs16.r, cc = rci.c + nbrs16.c; - - if (rr < 0 || rr >= R || cc < 0 || cc >= C || grid.isDigitAt(rr, cc)) continue; - long packedPos = 0; - var n = 0; - - while (rr >= 0 && rr < R && cc >= 0 && cc < C && grid.isLettercell(rr, cc) && n < MAX_WORD_LENGTH) { - packedPos |= (long) Grid.offset(rr, cc) << (n * 7); - n++; - rr += nbrs16.dr; - cc += nbrs16.dc; - } - if (n > 0) { - visitor.visit((rci.r << 8) | (rci.c << 4) | d, packedPos, n); - } - }*/ } ArrayList extractSlots(Grid grid) { @@ -470,7 +450,7 @@ public record SwedishGenerator(int[] buff) { Arrays.fill(covH, 0, SIZE, 0); Arrays.fill(covV, 0, SIZE, 0); - boolean[] hasSlots = {false}; + boolean[] hasSlots = { false }; grid.forEachSetBit71(clueIdx -> { var d = grid.digitAt(clueIdx); var nbrs16 = OFFSETS[d]; @@ -704,6 +684,9 @@ public record SwedishGenerator(int[] buff) { record Pick(Slot slot, CandidateInfo info, boolean done) { } + static final Pick PICK_DONE = new Pick(null, null, true); + static final Pick PICK_NOT_DONE = new Pick(null, null, false); + public static record FillResult(boolean ok, Gridded grid, HashMap clueMap, @@ -721,21 +704,21 @@ public record SwedishGenerator(int[] buff) { } static void patternForSlot(Grid grid, Slot s, byte[] pat) { - for (var i = 0; i < s.len(); i++) { + for (int i = 0, len = s.len(); i < len; i++) { var ch = grid.byteAt(s.pos(i)); pat[i] = isLetter(ch) ? ch : DASH; } } - static int slotScore(int[] cellCount, Slot s) { - var cross = 0; - for (var i = 0; i < s.len(); i++) cross += (cellCount[s.pos(i)] - 1); - return cross * 10 + s.len(); + static int slotScore(int[] count, Slot s) { + int cross = 0, len = s.len(); + for (int i = 0; i < len; i++) cross += (count[s.pos(i)] - 1); + return cross * 10 + len; } - static int placeWord(Grid grid, Slot s, Lemma w, int[] undoBuffer, int offset) { - int mask = 0, idx; + static boolean placeWord(Grid grid, Slot s, Lemma w, int[] undoBuffer, int offset) { + int mask = 0; byte cur, ch; - for (var i = 0; i < s.len(); i++) { + for (int i = 0, leng = s.len(), idx; i < leng; i++) { idx = s.pos(i); cur = grid.byteAt(idx); ch = w.byteAt(i); @@ -748,11 +731,11 @@ public record SwedishGenerator(int[] buff) { grid.clear(s.pos(j)); } } - return -1; + return false; } } undoBuffer[offset] = mask; - return 1; + return true; } public FillResult fillMask(Rng rng, Grid mask, DictEntry[] dictIndex, @@ -764,10 +747,10 @@ public record SwedishGenerator(int[] buff) { var used = new Bit1029(); var assigned = new HashMap(); - var ctx = CTX.get(); - var cellCount = ctx.cellCount; - Arrays.fill(cellCount, 0, SIZE, 0); - for (var s : slots) for (var i = 0; i < s.len(); i++) cellCount[s.pos(i)]++; + var ctx = CTX.get(); + var count = ctx.cellCount; + Arrays.fill(count, 0, SIZE, 0); + for (var s : slots) for (int i = 0, len = s.len(); i < len; i++) count[s.pos(i)]++; var t0 = System.currentTimeMillis(); final var lastLog = new AtomicLong(t0); @@ -799,34 +782,29 @@ public record SwedishGenerator(int[] buff) { Supplier chooseMRV = () -> { Slot best = null; CandidateInfo bestInfo = null; - + int bestSlot = -1; for (var s : slots) { - var k = s.key(); - if (assigned.containsKey(k)) continue; + if (assigned.containsKey(s.key())) continue; var entry = dictIndex[s.len()]; - if (entry == null) { - return new Pick(null, null, false); - } - var patLen = s.len(); + if (entry == null) return PICK_NOT_DONE; patternForSlot(grid, s, ctx.pattern); - var info = candidateInfoForPattern(ctx, entry, patLen); - - if (info.count == 0) { - return new Pick(null, null, false); - } + var info = candidateInfoForPattern(ctx, entry, s.len()); + if (info.count == 0) return PICK_NOT_DONE; + var slotScore = -1; if (best == null || info.count < bestInfo.count - || (info.count == bestInfo.count && slotScore(cellCount, s) > slotScore(cellCount, best))) { + || (info.count == bestInfo.count && (slotScore = slotScore(count, s)) > bestSlot)) { best = s; + bestSlot = (slotScore != -1) ? slotScore : slotScore(count, s); bestInfo = info; if (info.count <= 1) break; } } if (best == null) { - return new Pick(null, null, true); + return PICK_DONE; } else { return new Pick(best, bestInfo, false); } @@ -846,8 +824,8 @@ public record SwedishGenerator(int[] buff) { stats.backtracks++; return false; } - - stats.lastMRV = pick.info.count; + val info = pick.info; + stats.lastMRV = info.count; renderProgress.run(); var s = pick.slot; @@ -856,8 +834,8 @@ public record SwedishGenerator(int[] buff) { var entry = dictIndex[patLen]; var pat = new byte[patLen]; patternForSlot(grid, s, pat); - if (pick.info.indices != null && pick.info.indices.length > 0) { - var idxs = pick.info.indices; + if (info.indices != null && info.indices.length > 0) { + var idxs = info.indices; var L = idxs.length; var tries = Math.min(MAX_TRIES_PER_SLOT, L); @@ -878,8 +856,7 @@ public record SwedishGenerator(int[] buff) { } if (!match) continue; - int nPlaced = placeWord(grid, s, w, ctx.undoBuffer, depth); - if (nPlaced < 0) continue; + if (!placeWord(grid, s, w, ctx.undo, depth)) continue; used.set(w.index()); assigned.put(k, w); @@ -888,7 +865,7 @@ public record SwedishGenerator(int[] buff) { assigned.remove(k); used.clear(w.index); - undoPlace(grid, s, ctx.undoBuffer[depth]); + undoPlace(grid, s, ctx.undo[depth]); } stats.backtracks++; return false; @@ -917,8 +894,7 @@ public record SwedishGenerator(int[] buff) { } if (!match) continue; - int nPlaced = placeWord(grid, s, w, ctx.undoBuffer, depth); - if (nPlaced < 0) continue; + if (!placeWord(grid, s, w, ctx.undo, depth)) continue; used.set(w.index()); assigned.put(k, w); @@ -927,7 +903,7 @@ public record SwedishGenerator(int[] buff) { assigned.remove(k); used.clear(w.index); - undoPlace(grid, s, ctx.undoBuffer[depth]); + undoPlace(grid, s, ctx.undo[depth]); } stats.backtracks++; diff --git a/src/test/java/puzzle/SwedishGeneratorTest.java b/src/test/java/puzzle/SwedishGeneratorTest.java index 85d187a..948ddf1 100644 --- a/src/test/java/puzzle/SwedishGeneratorTest.java +++ b/src/test/java/puzzle/SwedishGeneratorTest.java @@ -264,22 +264,19 @@ public class SwedishGeneratorTest { var undoBuffer = new int[10]; // 1. Successful placement in empty grid - int placed = SwedishGenerator.placeWord(grid, s, w1, undoBuffer, 0); - assertEquals(1, placed); + assertTrue(SwedishGenerator.placeWord(grid, s, w1, undoBuffer, 0)); assertEquals('A', grid.byteAt(0, 0)); assertEquals('B', grid.byteAt(0, 1)); assertEquals('C', grid.byteAt(0, 2)); assertEquals(0b111L, undoBuffer[0]); // 2. Successful placement with partial overlap (same characters) - placed = SwedishGenerator.placeWord(grid, s, w1, undoBuffer, 1); - assertEquals(1, placed); + assertTrue(SwedishGenerator.placeWord(grid, s, w1, undoBuffer, 1)); assertEquals(0L, undoBuffer[1]); // 0 new characters placed // 3. Conflict: place "ABD" where "ABC" is var w2 = new Lemma("ABD", 1, "conflict"); - placed = SwedishGenerator.placeWord(grid, s, w2, undoBuffer, 2); - assertEquals(-1, placed); + assertFalse(SwedishGenerator.placeWord(grid, s, w2, undoBuffer, 2)); // Verify grid is unchanged (still "ABC") assertEquals('A', grid.byteAt(0, 0)); assertEquals('B', grid.byteAt(0, 1)); @@ -288,8 +285,7 @@ public class SwedishGeneratorTest { // 4. Partial placement then conflict (rollback) grid = SwedishGenerator.makeEmptyGrid(); grid.setCharAt(0, 2, 'X'); // Conflict at the end - placed = SwedishGenerator.placeWord(grid, s, w1, undoBuffer, 3); - assertEquals(-1, placed); + assertFalse(SwedishGenerator.placeWord(grid, s, w1, undoBuffer, 3)); // Verify grid is still empty (except for 'X') assertEquals(SwedishGenerator.DASH, grid.byteAt(0, 0)); assertEquals(SwedishGenerator.DASH, grid.byteAt(0, 1)); @@ -306,7 +302,7 @@ public class SwedishGeneratorTest { var undoBuffer = new int[10]; var placed = SwedishGenerator.placeWord(grid, s, w, undoBuffer, 0); - assertEquals(1, placed); + assertTrue(placed); assertEquals('A', grid.byteAt(0, 1)); assertEquals('Z', grid.byteAt(0, 2)); assertEquals(0b11L, undoBuffer[0]);