From 4109c51cbe3f830839f37a74cad3c221b5b81f29 Mon Sep 17 00:00:00 2001 From: mike Date: Fri, 23 Jan 2026 04:02:51 +0100 Subject: [PATCH] redo --- src/main/java/puzzle/Main.java | 26 +++++++++++++------ src/main/java/puzzle/Masker.java | 25 +++++++++++------- src/main/java/puzzle/SwedishGenerator.java | 14 +++------- src/main/java/puzzle/rci.java | 3 +++ src/test/java/puzzle/MainTest.java | 6 ++--- src/test/java/puzzle/PerformanceTest.java | 5 ++-- .../java/puzzle/SwedishGeneratorTest.java | 1 - src/test/java/puzzle/TestDuplication.java | 13 ++++++---- 8 files changed, 54 insertions(+), 39 deletions(-) create mode 100644 src/main/java/puzzle/rci.java diff --git a/src/main/java/puzzle/Main.java b/src/main/java/puzzle/Main.java index 505f987..f4efe0e 100644 --- a/src/main/java/puzzle/Main.java +++ b/src/main/java/puzzle/Main.java @@ -1,11 +1,15 @@ package puzzle; import module java.base; +import anno.ConstGen; import anno.DictGen; +import anno.GenerateNeighbor; +import anno.GenerateNeighbors; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import lombok.val; +import precomp.Neighbors9x8; import puzzle.SwedishGenerator.Rng; import static puzzle.Export.*; @@ -18,8 +22,14 @@ import static puzzle.SwedishGenerator.*; minLen = 2, maxLen = 8 ) +@ConstGen(C = 9, R = 8, packageName = "precomp", className = "Const9x8") +@GenerateNeighbors({ + @GenerateNeighbor(C = 9, R = 8, packageName = "precomp", className = "Neighbors9x8", MIN_LEN = 2), + @GenerateNeighbor(C = 4, R = 3, packageName = "precomp", className = "Neighbors4x3", MIN_LEN = 2) +}) public class Main { + final static rci RCI = Masker.IT[0]; final static String OUT_DIR = envOrDefault("OUT_DIR", "/data/puzzle"); final static Path PUZZLE_DIR = Paths.get(OUT_DIR, "puzzles"); static final Path INDEX_FILE = PUZZLE_DIR.resolve("index.json"); @@ -83,13 +93,13 @@ public class Main { } section("Mask"); - System.out.print(indentLines(res.clues().gridToString(), " ")); + System.out.print(indentLines(res.clues().gridToString())); section("Grid (raw)"); - System.out.print(indentLines(res.grid().gridToString(), " ")); + System.out.print(indentLines(res.grid().gridToString())); section("Grid (human)"); - System.out.print(indentLines(res.grid().renderHuman(), " ")); + System.out.print(indentLines(res.grid().renderHuman())); var exported = res.exportFormatFromFilled(new Rewards(50, 2, 1)); @@ -178,11 +188,11 @@ public class Main { return s.substring(0, Math.max(0, max - 1)) + "…"; } - static String indentLines(String s, String indent) { + static String indentLines(String s) { if (s == null || s.isEmpty()) return ""; var lines = s.split("\\R", -1); var sb = new StringBuilder(); - for (var line : lines) sb.append(indent).append(line).append('\n'); + for (var line : lines) sb.append(" ").append(line).append('\n'); return sb.toString(); } @@ -356,7 +366,7 @@ public class Main { } } static Clues generateNewClues(Rng rng, Opts opts) { - var masker = new Masker(rng, new int[Masker.STACK_SIZE], Clues.createEmpty()); + var masker = new Masker_Neighbors9x8(rng, new int[Masker_Neighbors9x8.STACK_SIZE], Clues.createEmpty()); return masker.generateMask(opts.clueSize, opts.pop, opts.gens, opts.offspring); } static PuzzleResult _attempt(Rng rng, Dict dict, Opts opts) { @@ -367,8 +377,8 @@ public class Main { //val mask = generateClues(); if (mask == null) return null; - val slotInfo = Masker.slots(mask, dict.index(), dict.reversed()); - var grid = Slotinfo.grid(slotInfo);// mask.toGrid(); + val slotInfo = Masker_Neighbors9x8.slots(mask, dict.index(), dict.reversed()); + var grid = Masker_Neighbors9x8.grid(slotInfo, Neighbors9x8.SIZE);// mask.toGrid(); var filled = fillMask(rng, slotInfo, grid.lo, grid.hi, grid.g); if (!multiThreaded) { diff --git a/src/main/java/puzzle/Masker.java b/src/main/java/puzzle/Masker.java index 1834557..0ea2be1 100644 --- a/src/main/java/puzzle/Masker.java +++ b/src/main/java/puzzle/Masker.java @@ -5,7 +5,6 @@ import anno.GenerateShapedCopies; import anno.Shaped; import lombok.val; import precomp.Neighbors9x8; -import gen.rci; import static java.lang.Long.*; import static puzzle.SwedishGenerator.*; @@ -53,6 +52,14 @@ public final class Masker { return (bitCount(matchLo & MASK_LO) + bitCount(matchHi & MASK_HI)) / SIZED; } + public static Grid grid(Slotinfo[] slots, int size) { + long lo = X, hi = X; + for (var slot : slots) { + lo |= slot.lo(); + hi |= slot.hi(); + } + return new Grid(new byte[size], ~lo & MASK_LO, ~hi & MASK_HI); + } public boolean isValid(Clues c) { return findOffendingClue(c) == -1; @@ -180,7 +187,7 @@ public final class Masker { if (Long.bitCount(rayLo) + Long.bitCount(rayHi) >= MIN_LEN) visitor.visit(key, rayLo, rayHi); } - public static void forEachSlot(Clues c,SlotVisitor visitor) { + public static void forEachSlot(Clues c, SlotVisitor visitor) { final long lo = c.lo, hi = c.hi, xlo = c.xlo, xhi = c.xhi, rlo = c.rlo, rhi = c.rhi, vlo = c.vlo, vhi = c.vhi; for (var l = lo & ~xlo & ~rlo & vlo; l != X; l &= l - 1) processSlot(c, visitor, Slot.packSlotKey(numberOfTrailingZeros(l), 1)); for (var l = lo & ~xlo & ~rlo & ~vlo; l != X; l &= l - 1) processSlot(c, visitor, Slot.packSlotKey(numberOfTrailingZeros(l), 0)); @@ -198,7 +205,7 @@ public final class Masker { } public static Slot[] extractSlots(Clues c, DictEntry[] index, DictEntry[] rev) { var slots = new ArrayList(c.clueCount()); - forEachSlot(c,(key, lo, hi) -> slots.add(Slot.from(key, lo, hi, Slotinfo.increasing(key) ? index[Slot.length(lo, hi)] : rev[Slot.length(lo, hi)]))); + forEachSlot(c, (key, lo, hi) -> slots.add(Slot.from(key, lo, hi, Slotinfo.increasing(key) ? index[Slot.length(lo, hi)] : rev[Slot.length(lo, hi)]))); return slots.toArray(Slot[]::new); } public static Slotinfo[] slots(Clues mask, Dict d) { return slots(mask, d.index(), d.reversed()); } @@ -455,7 +462,7 @@ public final class Masker { return penalty; } - public static boolean hasRoomForClue(Clues c,int key) { + public static boolean hasRoomForClue(Clues c, int key) { if (Slotinfo.increasing(key)) if (!validSlot(c.lo, c.hi, key)) return false; return validSlotRev(c.lo, c.hi, key); } @@ -468,7 +475,7 @@ public final class Masker { if (g.isClueLo(ri)) continue; var d_idx = rng.randomClueDir(); var key = Slot.packSlotKey(ri, d_idx); - if (hasRoomForClue(g,key)) { + if (hasRoomForClue(g, key)) { g.setClueLo(1L << ri, d_idx); if (isValid(g)) placed++; else g.clearClueLo(~(1L << ri)); @@ -477,7 +484,7 @@ public final class Masker { if (g.isClueHi(ri)) continue; var d_idx = rng.randomClueDir(); var key = Slot.packSlotKey(ri, d_idx); - if (hasRoomForClue(g,key)) { + if (hasRoomForClue(g, key)) { g.setClueHi(1L << (ri & 63), d_idx); if (isValid(g)) placed++; else g.clearClueHi(~(1L << (ri & 63))); @@ -495,7 +502,7 @@ public final class Masker { if (c.notClue(ri)) { // ADD var d = rng.randomClueDir(); var key = Slot.packSlotKey(ri, d); - if (hasRoomForClue(c,key)) { + if (hasRoomForClue(c, key)) { if (isLo(ri)) { c.setClueLo(1L << ri, d); if (!isValid(c)) c.clearClueLo(~(1L << ri)); @@ -523,7 +530,7 @@ public final class Masker { if (op < 4) { // CHANGE DIRECTION var d = rng.randomClueDir(); var key = Slot.packSlotKey(ri, d); - if (hasRoomForClue(c,key)) { + if (hasRoomForClue(c, key)) { var oldD = c.getDir(ri); if (isLo(ri)) { c.setClueLo(1L << ri, d); @@ -540,7 +547,7 @@ public final class Masker { if (c.notClue(nri)) { var d = c.getDir(ri); var nkey = Slot.packSlotKey(nri, d); - if (hasRoomForClue(c,nkey)) { + if (hasRoomForClue(c, nkey)) { if (isLo(ri)) c.clearClueLo(~(1L << ri)); else c.clearClueHi(~(1L << (ri & 63))); if (isLo(nri)) c.setClueLo(1L << nri, d); diff --git a/src/main/java/puzzle/SwedishGenerator.java b/src/main/java/puzzle/SwedishGenerator.java index ffc9c8a..85c6fc5 100644 --- a/src/main/java/puzzle/SwedishGenerator.java +++ b/src/main/java/puzzle/SwedishGenerator.java @@ -38,9 +38,9 @@ import static java.nio.charset.StandardCharsets.US_ASCII; public record SwedishGenerator() { public static final int MAX_TRIES_PER_SLOT = 500;// MAX_TRIES_PER_SLOT; - public static final long X = 0L; - @Shaped private static final int SIZE = Neighbors9x8.SIZE; - @Shaped private static final long RANGE_0_SIZE = Neighbors9x8.RANGE_0_SIZE; + public static final long X = 0L; + @Shaped static final int SIZE = Neighbors9x8.SIZE; + @Shaped private static final long RANGE_0_SIZE = Neighbors9x8.RANGE_0_SIZE; @Shaped private static final long RANGE_0_624 = Neighbors9x8.RANGE_0_624; interface Bit1029 { @@ -118,14 +118,6 @@ public record SwedishGenerator() { return k; } public static boolean increasing(int dir) { return (dir & 2) == 0; } - public static Grid grid(Slotinfo[] slots) { - long lo = X, hi = X; - for (var slot : slots) { - lo |= slot.lo; - hi |= slot.hi; - } - return new Grid(new byte[SIZE], ~lo, ~hi); - } } public static long patternForSlot(final long glo, final long ghi, final byte[] g, final long lo, final long hi) { diff --git a/src/main/java/puzzle/rci.java b/src/main/java/puzzle/rci.java new file mode 100644 index 0000000..949e3b2 --- /dev/null +++ b/src/main/java/puzzle/rci.java @@ -0,0 +1,3 @@ +package puzzle; + +public record rci(int r, int c, int i, long n1, long n2, int nbrCount, long n8_1, long n8_2, double cross_r, double cross_c) {} \ No newline at end of file diff --git a/src/test/java/puzzle/MainTest.java b/src/test/java/puzzle/MainTest.java index 4d50c27..9fa7f6e 100644 --- a/src/test/java/puzzle/MainTest.java +++ b/src/test/java/puzzle/MainTest.java @@ -5,7 +5,7 @@ import anno.DictGen; import lombok.val; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import gen.rci; +import precomp.Neighbors9x8; import puzzle.Export.Vestigium; import puzzle.Export.Signa; import puzzle.Export.Puzzle; @@ -180,13 +180,13 @@ public class MainTest { r7c0d2, r7c1d1, r7c4d2, r7c5d2, r7c8d3 ); var slotInfo = mask.slots(DictData950.DICT950); - var grid = Slotinfo.grid(slotInfo); + var grid = Masker.grid(slotInfo, Neighbors9x8.SIZE); var filled = fillMask(rng, slotInfo, grid.lo, grid.hi, grid.g); Assertions.assertTrue(filled.ok(), "Puzzle generation failed (not ok)"); Assertions.assertEquals(17, Slotinfo.wordCount(0, slotInfo), "Number of assigned words changed"); Assertions.assertEquals("BEADEMT", Lemma.asWord(slotInfo[0].assign().w, Export.BYTES.get())); Assertions.assertEquals(74732156493031040L, grid.lo); - Assertions.assertEquals(-63L, grid.hi); + Assertions.assertEquals(193L, grid.hi); var g = new Puzzle(grid, mask.c()); g.gridToString(); var aa = new PuzzleResult(mask, g, slotInfo, filled).exportFormatFromFilled(new Rewards(1, 1, 1)); diff --git a/src/test/java/puzzle/PerformanceTest.java b/src/test/java/puzzle/PerformanceTest.java index aba0b18..eaba85b 100644 --- a/src/test/java/puzzle/PerformanceTest.java +++ b/src/test/java/puzzle/PerformanceTest.java @@ -5,6 +5,7 @@ import anno.DictGen; import anno.Dictionaries; import lombok.val; import org.junit.jupiter.api.Test; +import precomp.Neighbors9x8; import puzzle.Export.Clue; import puzzle.Export.Signa; import puzzle.Export.Puzzle; @@ -72,7 +73,7 @@ public class PerformanceTest { for (var i = 0; i < iterations; i++) { val slotInfo = Masker.slots(arr[c], DICT800); - var grid = Slotinfo.grid(slotInfo); + var grid = Masker.grid(slotInfo, Neighbors9x8.SIZE); val result = fillMask(rng, slotInfo,grid.lo,grid.hi, grid.g); if (result.ok()) successCount++; totalNodes += result.nodes(); @@ -142,7 +143,7 @@ public class PerformanceTest { // Reset assignments for each iteration for (var s : slots) s.assign().w = 0; - var grid = Slotinfo.grid(slots); + var grid = Masker.grid(slots, Neighbors9x8.SIZE); val result = fillMask(rng, slots, grid.lo,grid.hi,grid.g); if (result.ok()) { successCount++; diff --git a/src/test/java/puzzle/SwedishGeneratorTest.java b/src/test/java/puzzle/SwedishGeneratorTest.java index 80b0962..e9bd98c 100644 --- a/src/test/java/puzzle/SwedishGeneratorTest.java +++ b/src/test/java/puzzle/SwedishGeneratorTest.java @@ -8,7 +8,6 @@ import lombok.val; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import precomp.Neighbors9x8; -import gen.rci; import puzzle.DictJavaGeneratorMulti.DictEntryDTO.IntListDTO; import puzzle.Export.Signa; import puzzle.Export.Puzzle; diff --git a/src/test/java/puzzle/TestDuplication.java b/src/test/java/puzzle/TestDuplication.java index bea52e9..e068e47 100644 --- a/src/test/java/puzzle/TestDuplication.java +++ b/src/test/java/puzzle/TestDuplication.java @@ -1,15 +1,17 @@ package puzzle; -import puzzle.Masker_Neighbors4x3; import gen.Test123X_Neighbors4x3; import gen.Test123X_Neighbors9x8; import lombok.val; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import puzzle.Export.Puzzle; +import puzzle.Export.PuzzleResult; +import puzzle.Export.Rewards; import puzzle.Export.Signa; import puzzle.Export.Vestigium; +import puzzle.SwedishGenerator.Rng; import puzzle.dict800.DictData800; -import puzzle.dict950.DictData950; import java.util.stream.Collectors; import static precomp.Const9x8.Cell.r0c0d1; import static precomp.Const9x8.Cell.r1c0d1; @@ -33,8 +35,9 @@ public class TestDuplication { Assertions.assertEquals(4, mask.clueCount()); val map = mask.stream().collect(Collectors.toMap(Vestigium::index, Vestigium::clue)); Assertions.assertEquals(4, map.size()); - var slots = Masker_Neighbors4x3.slots(mask.c(), DictData800.DICT800); - // var filled = fillMask(rng, slotInfo, grid, false); - // val res = new PuzzleResult(new Clued(mask), new Gridded(grid), slotInfo, filled).exportFormatFromFilled(0, new Rewards(0, 0, 0)); + var slots = Masker_Neighbors4x3.slots(mask.c(), DictData800.DICT800); + var grid = Masker_Neighbors4x3.grid(slots, Masker_Neighbors4x3.SIZE); + var filled = SwedishGenerator.fillMask(new Rng(1), slots, grid.lo, grid.hi, grid.g); + val res = new PuzzleResult(new Signa(mask.c()), new Puzzle(grid, mask.c()), slots, filled).exportFormatFromFilled(new Rewards(0, 0, 0)); } }