From 2c39e82b0030e9948df7de22f432fa9074e8a97d Mon Sep 17 00:00:00 2001 From: mike Date: Fri, 23 Jan 2026 05:23:11 +0100 Subject: [PATCH] redo --- src/main/java/puzzle/Export.java | 18 +++++++++--------- src/main/java/puzzle/Main.java | 8 ++++---- src/main/java/puzzle/Masker.java | 6 +++--- src/test/java/puzzle/MainTest.java | 5 ++--- src/test/java/puzzle/MarkerTest.java | 12 ++++++------ src/test/java/puzzle/PerformanceTest.java | 5 ++--- src/test/java/puzzle/TestDuplication.java | 14 +++++++++++--- 7 files changed, 37 insertions(+), 31 deletions(-) diff --git a/src/main/java/puzzle/Export.java b/src/main/java/puzzle/Export.java index 1170dbd..81974fa 100644 --- a/src/main/java/puzzle/Export.java +++ b/src/main/java/puzzle/Export.java @@ -195,16 +195,16 @@ public record Export() { } - record Placed(long lemma, int slotKey, int[] cells) { + record Placed(rci[] rcis, long lemma, int slotKey, int[] cells) { public static final char HORIZONTAL = 'h'; static final char VERTICAL = 'v'; static final char[] DIRECTION = { Placed.VERTICAL, Placed.HORIZONTAL, Placed.VERTICAL, Placed.HORIZONTAL, Placed.VERTICAL, Placed.VERTICAL }; - public int arrowCol() { return Masker.IT[Slot.clueIndex(slotKey)].c(); } - public int arrowRow() { return Masker.IT[Slot.clueIndex(slotKey)].r(); } - public int startRow() { return Masker.IT[cells[0]].r(); } - public int startCol() { return Masker.IT[cells[0]].c(); } + public int arrowCol() { return rcis[Slot.clueIndex(slotKey)].c(); } + public int arrowRow() { return rcis[Slot.clueIndex(slotKey)].r(); } + public int startRow() { return rcis[cells[0]].r(); } + public int startCol() { return rcis[cells[0]].c(); } public boolean isReversed() { return !Slotinfo.increasing(slotKey); } public char direction() { return DIRECTION[Slot.dir(slotKey)]; } } @@ -247,13 +247,13 @@ public record Export() { public record PuzzleResult(Signa clues, Puzzle grid, Slotinfo[] slots, FillResult filled) { - public ExportedPuzzle exportFormatFromFilled(Rewards rewards) { + public ExportedPuzzle exportFormatFromFilled(Rewards rewards, rci[] rcis, int bits) { // If nothing placed: return full grid mapped to letters/# only if (slots.length == 0) { return new ExportedPuzzle(grid.exportGrid(_ -> '#', '#'), new WordOut[0], 1, rewards); } - var placed = Arrays.stream(slots).map(slot -> new Placed(slot.assign().w, slot.key(), Puzzle.cellWalk((byte) slot.key(), slot.lo(), slot.hi()).toArray())).toArray( + var placed = Arrays.stream(slots).map(slot -> new Placed(rcis, slot.assign().w, slot.key(), Puzzle.cellWalk((byte) slot.key(), slot.lo(), slot.hi()).toArray())).toArray( Placed[]::new); // 2) bounding box around all word cells + arrow cells, with 1-cell margin @@ -262,7 +262,7 @@ public record Export() { for (var rc : placed) { for (var c : rc.cells) { - val it = Masker.IT[c]; + val it = rcis[c]; minR = Math.min(minR, it.r()); minC = Math.min(minC, it.c()); maxR = Math.max(maxR, it.r()); @@ -280,7 +280,7 @@ public record Export() { var gridv2 = new String[Math.max(0, maxR - minR + 1)]; for (int r = minR, i = 0; r <= maxR; r++, i++) { var row = new StringBuilder(Math.max(0, maxC - minC + 1)); - for (var c = minC; c <= maxC; c++) row.append(map.getOrDefault(Masker.offset(r, c), '#')); + for (var c = minC; c <= maxC; c++) row.append(map.getOrDefault(r | (c << bits), '#')); gridv2[i] = row.toString(); } diff --git a/src/main/java/puzzle/Main.java b/src/main/java/puzzle/Main.java index f4efe0e..e8b52ff 100644 --- a/src/main/java/puzzle/Main.java +++ b/src/main/java/puzzle/Main.java @@ -9,7 +9,6 @@ import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import lombok.val; -import precomp.Neighbors9x8; import puzzle.SwedishGenerator.Rng; import static puzzle.Export.*; @@ -25,7 +24,8 @@ import static puzzle.SwedishGenerator.*; @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) + @GenerateNeighbor(C = 4, R = 3, packageName = "precomp", className = "Neighbors4x3", MIN_LEN = 2), + @GenerateNeighbor(C = 3, R = 4, packageName = "precomp", className = "Neighbors3x4", MIN_LEN = 2) }) public class Main { @@ -101,7 +101,7 @@ public class Main { section("Grid (human)"); System.out.print(indentLines(res.grid().renderHuman())); - var exported = res.exportFormatFromFilled(new Rewards(50, 2, 1)); + var exported = res.exportFormatFromFilled(new Rewards(50, 2, 1), Masker.IT, 3); section("Clues"); info("status : generating..."); @@ -378,7 +378,7 @@ public class Main { if (mask == null) return null; val slotInfo = Masker_Neighbors9x8.slots(mask, dict.index(), dict.reversed()); - var grid = Masker_Neighbors9x8.grid(slotInfo, Neighbors9x8.SIZE);// mask.toGrid(); + var grid = Masker_Neighbors9x8.grid(slotInfo);// 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 0ea2be1..f2dbf0c 100644 --- a/src/main/java/puzzle/Masker.java +++ b/src/main/java/puzzle/Masker.java @@ -11,7 +11,7 @@ import static puzzle.SwedishGenerator.*; @GenerateShapedCopies( packageName = "puzzle", className = "Masker", - shapes = { "precomp.Neighbors9x8", "precomp.Neighbors4x3" } + shapes = { "precomp.Neighbors9x8", "precomp.Neighbors4x3" , "precomp.Neighbors3x4" } ) public final class Masker { @@ -52,13 +52,13 @@ public final class Masker { return (bitCount(matchLo & MASK_LO) + bitCount(matchHi & MASK_HI)) / SIZED; } - public static Grid grid(Slotinfo[] slots, int size) { + 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 & MASK_LO, ~hi & MASK_HI); + return new Grid(new byte[SIZE], ~lo & MASK_LO, ~hi & MASK_HI); } public boolean isValid(Clues c) { diff --git a/src/test/java/puzzle/MainTest.java b/src/test/java/puzzle/MainTest.java index 9fa7f6e..0d99dde 100644 --- a/src/test/java/puzzle/MainTest.java +++ b/src/test/java/puzzle/MainTest.java @@ -5,7 +5,6 @@ import anno.DictGen; import lombok.val; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import precomp.Neighbors9x8; import puzzle.Export.Vestigium; import puzzle.Export.Signa; import puzzle.Export.Puzzle; @@ -180,7 +179,7 @@ public class MainTest { r7c0d2, r7c1d1, r7c4d2, r7c5d2, r7c8d3 ); var slotInfo = mask.slots(DictData950.DICT950); - var grid = Masker.grid(slotInfo, Neighbors9x8.SIZE); + var grid = Masker.grid(slotInfo); 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"); @@ -189,7 +188,7 @@ public class MainTest { 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)); + var aa = new PuzzleResult(mask, g, slotInfo, filled).exportFormatFromFilled(new Rewards(1, 1, 1), Masker.IT, 3); System.out.println(String.join("\n", aa.grid())); } diff --git a/src/test/java/puzzle/MarkerTest.java b/src/test/java/puzzle/MarkerTest.java index 0b59c68..ad91f38 100644 --- a/src/test/java/puzzle/MarkerTest.java +++ b/src/test/java/puzzle/MarkerTest.java @@ -112,22 +112,22 @@ public class MarkerTest { var g = Clues.createEmpty(); // Room for Right clue at (0,0) (length 8) - assertTrue(Masker.hasRoomForClue(g,r0c0d1.slotKey)); + assertTrue(Masker.hasRoomForClue(g, r0c0d1.slotKey)); // No room for Right clue at (0,8) (length 0 < MIN_LEN) - assertFalse(Masker.hasRoomForClue(g,r0c8d1.slotKey)); + assertFalse(Masker.hasRoomForClue(g, r0c8d1.slotKey)); // Blocked room // Let's place a clue that leaves only 1 cell for another clue. g.setClue(r0c2d1); // Now Right at (0,0) only has (0,1) available -> length 1 < MIN_LEN (which is 2) - assertFalse(Masker.hasRoomForClue(g,r0c0d1.slotKey)); + assertFalse(Masker.hasRoomForClue(g, r0c0d1.slotKey)); // But enough room g.clearClueLo(0L); g.setClue(r0c3d1); // Now Right at (0,0) has (0,1), (0,2) -> length 2 == MIN_LEN - assertTrue(Masker.hasRoomForClue(g,r0c0d1.slotKey)); + assertTrue(Masker.hasRoomForClue(g, r0c0d1.slotKey)); } @Test @@ -307,7 +307,7 @@ public class MarkerTest { }, fillResult); var rewards = new Rewards(10, 5, 1); - var exported = puzzleResult.exportFormatFromFilled(rewards); + var exported = puzzleResult.exportFormatFromFilled(rewards, Masker.IT, 3); assertNotNull(exported); assertEquals(709, exported.difficulty()); @@ -346,7 +346,7 @@ public class MarkerTest { var fillResult = new FillResult(true, 0, 0, 0, 0); var puzzleResult = new PuzzleResult(new Signa(clues), new Puzzle(grid, clues), new Slotinfo[0], fillResult); - var exported = puzzleResult.exportFormatFromFilled(new Rewards(0, 0, 0)); + var exported = puzzleResult.exportFormatFromFilled(new Rewards(0, 0, 0), Masker.IT, 3); assertNotNull(exported); assertEquals(0, exported.words().length); diff --git a/src/test/java/puzzle/PerformanceTest.java b/src/test/java/puzzle/PerformanceTest.java index eaba85b..39efaa0 100644 --- a/src/test/java/puzzle/PerformanceTest.java +++ b/src/test/java/puzzle/PerformanceTest.java @@ -5,7 +5,6 @@ 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; @@ -73,7 +72,7 @@ public class PerformanceTest { for (var i = 0; i < iterations; i++) { val slotInfo = Masker.slots(arr[c], DICT800); - var grid = Masker.grid(slotInfo, Neighbors9x8.SIZE); + var grid = Masker.grid(slotInfo); val result = fillMask(rng, slotInfo,grid.lo,grid.hi, grid.g); if (result.ok()) successCount++; totalNodes += result.nodes(); @@ -143,7 +142,7 @@ public class PerformanceTest { // Reset assignments for each iteration for (var s : slots) s.assign().w = 0; - var grid = Masker.grid(slots, Neighbors9x8.SIZE); + var grid = Masker.grid(slots); val result = fillMask(rng, slots, grid.lo,grid.hi,grid.g); if (result.ok()) { successCount++; diff --git a/src/test/java/puzzle/TestDuplication.java b/src/test/java/puzzle/TestDuplication.java index e068e47..57329c5 100644 --- a/src/test/java/puzzle/TestDuplication.java +++ b/src/test/java/puzzle/TestDuplication.java @@ -12,6 +12,7 @@ import puzzle.Export.Signa; import puzzle.Export.Vestigium; import puzzle.SwedishGenerator.Rng; import puzzle.dict800.DictData800; +import java.util.Arrays; import java.util.stream.Collectors; import static precomp.Const9x8.Cell.r0c0d1; import static precomp.Const9x8.Cell.r1c0d1; @@ -35,9 +36,16 @@ 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 grid = Masker_Neighbors4x3.grid(slots, Masker_Neighbors4x3.SIZE); + var slots = Masker_Neighbors3x4.slots(mask.c(), DictData800.DICT800); + var grid = Masker_Neighbors3x4.grid(slots); 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)); + grid.lo = Masker_Neighbors3x4.MASK_LO & ~mask.c().lo; + grid.hi = Masker_Neighbors3x4.MASK_HI & ~mask.c().hi; + var grid1 = new Puzzle(grid, mask.c()); + var result = new PuzzleResult(new Signa(mask.c()), grid1, slots, filled); + if (filled.ok()) { + val res = result.exportFormatFromFilled(new Rewards(0, 0, 0), Masker_Neighbors3x4.IT, 2); + System.out.println(String.join("\n", res.grid())); + } } }