From 7e5e363a3eb0760e55b895c956f9c724c763659a Mon Sep 17 00:00:00 2001 From: mike Date: Tue, 20 Jan 2026 01:35:34 +0100 Subject: [PATCH] introduce bitloops --- src/main/generated-sources/puzzle/Config.java | 16 ------- src/main/java/puzzle/SwedishGenerator.java | 29 ++++++------- src/main/java/puzzle/Trigger.java | 2 +- src/test/java/puzzle/CornerClueTest.java | 42 +++++++++++++++++++ src/test/java/puzzle/ExportFormatTest.java | 2 +- src/test/java/puzzle/MainTest.java | 2 + .../java/puzzle/SwedishGeneratorTest.java | 32 +++++++------- 7 files changed, 74 insertions(+), 51 deletions(-) delete mode 100644 src/main/generated-sources/puzzle/Config.java diff --git a/src/main/generated-sources/puzzle/Config.java b/src/main/generated-sources/puzzle/Config.java deleted file mode 100644 index d10450e..0000000 --- a/src/main/generated-sources/puzzle/Config.java +++ /dev/null @@ -1,16 +0,0 @@ -package puzzle; - -/** - * Generated constants from pom.xml during build via templating-maven-plugin. - */ -public final class Config { - public static final int CLUE_SIZE = 4; - public static final int MIN_LEN = 2; - public static final int MAX_TRIES_PER_SLOT = 1000; - public static final int MAX_LEN = 8; - public static final int PUZZLE_ROWS = 8; - public static final int PUZZLE_COLS = 9; - public static final int PUZZLE_SIZE = PUZZLE_ROWS*PUZZLE_COLS; - public static final int MAX_WORD_LENGTH = PUZZLE_ROWS; - public static final int MAX_WORD_LENGTH_MIN_1 = PUZZLE_ROWS-1; -} diff --git a/src/main/java/puzzle/SwedishGenerator.java b/src/main/java/puzzle/SwedishGenerator.java index 0d09771..c4420a4 100644 --- a/src/main/java/puzzle/SwedishGenerator.java +++ b/src/main/java/puzzle/SwedishGenerator.java @@ -32,18 +32,18 @@ public record SwedishGenerator() { public static final int BAR_LEN = 22; public static final int C = Config.PUZZLE_COLS; public static final int R = Config.PUZZLE_ROWS; - public static final int SIZE = C * R;// ~18 + public static final int SIZE = Neighbors9x8.SIZE;// ~18 public static final int SIZE_MIN_1 = SIZE - 1;// ~18 public static final double SIZED = (double) SIZE;// ~18 public static final long MASK_LO = -1L; - public static final long MASK_HI = (1L << (SIZE - 64)) - 1; + public static final long MASK_HI = Neighbors9x8.MASK_HI;//(1L << (SIZE - 64)) - 1; public static final int MAX_WORD_LENGTH = Config.PUZZLE_ROWS; public static final int MAX_WORD_LENGTH_PLUS_ONE = MAX_WORD_LENGTH + 1; - public static final int MIN_LEN = 3;//Config.MIN_LEN; + public static final int MIN_LEN = 2;//Neighbors9x8.MIN_LEN;//Config.MIN_LEN; public static final int MAX_TRIES_PER_SLOT = 700;//Config.MAX_TRIES_PER_SLOT; public static final int STACK_SIZE = 128; - public static final long RANGE_0_SIZE = (long) SIZE_MIN_1 - 0L + 1L; - public static final long RANGE_0_624 = 624L - 0L + 1L; + public static final long RANGE_0_SIZE = Neighbors9x8.RANGE_0_SIZE;// (long) SIZE_MIN_1 - 0L + 1L + public static final long RANGE_0_624 = Neighbors9x8.RANGE_0_624;//624L - 0L + 1L; static final int PICK_NOT_DONE = -1; static final int PICK_DONE = 0; public static boolean isLo(int n) { return (n & 64) == 0; } @@ -65,9 +65,8 @@ public record SwedishGenerator() { public static record DictEntry(long[] words, long[][] posBitsets, int length, int numlong) { } //@formatter:on - public static final long[] OFFSETS_D_IDX = Neighbors9x8.OFFSETS_D_IDX; - public static final long[] PATH_LO = Neighbors9x8.PATH_LO; - public static final long[] PATH_HI = Neighbors9x8.PATH_HI; + public static final long[] PATH_LO = Neighbors9x8.PATH_LO; + public static final long[] PATH_HI = Neighbors9x8.PATH_HI; public static final class Rng { @@ -85,13 +84,10 @@ public record SwedishGenerator() { x = y; return y; } - public byte randint2bitByte() { - int r = nextU32() & 7; - if (r == 4) return (byte) 4; - return (byte) (r & 3); - } + static final byte[] BYTE = new byte[]{ 0, 1, 2, 3/*,4, 5*/ }; + public byte randomClueDir() { return rand(BYTE); } public T rand(T[] p) { return p[(int) (((nextU32() & 0xFFFFFFFFL) % ((long) p.length)))]; } - public int randint(int max) { return (int) (((nextU32() & 0xFFFFFFFFL) % ((long) max))); } + public byte rand(byte[] p) { return p[(int) (((nextU32() & 0xFFFFFFFFL) % ((long) p.length)))]; } public int randint0_SIZE() { return (int) (((nextU32() & 0xFFFFFFFFL) % RANGE_0_SIZE)); } public int randint0_624() { return (int) (((nextU32() & 0xFFFFFFFFL) % RANGE_0_624)); } public double nextFloat() { return (nextU32() & 0xFFFFFFFFL) / 4294967295.0; } @@ -124,7 +120,7 @@ public record SwedishGenerator() { static int unpackLetters(long w) { return (int) (w & LETTER_MASK); } } - public static record Slotinfo(int key, long lo, long hi, int score, Assign assign, DictEntry entry) { + public static record Slotinfo(int key, long lo, long hi, int score, Assign assign, DictEntry entry, int minL) { public static int wordCount(int k, Slotinfo[] arr) { for (var n = 1; n < arr.length; n++) if (arr[n].assign.w != X) k++; @@ -322,8 +318,7 @@ public record SwedishGenerator() { var N = words.length; - var tries = Math.min(MAX_TRIES_PER_SLOT, N); - for (var t = 0; t < tries; t++) { + for (var t = 0; t < s.minL; t++) { var w = words[rng.biasedIndexPow3(N - 1)]; var lemIdx = Lemma.unpackIndex(w); if (Bit1029.get(used, lemIdx)) continue; diff --git a/src/main/java/puzzle/Trigger.java b/src/main/java/puzzle/Trigger.java index 4b04aed..460e38b 100644 --- a/src/main/java/puzzle/Trigger.java +++ b/src/main/java/puzzle/Trigger.java @@ -2,5 +2,5 @@ package puzzle; import gen.GenerateNeighbors; -@GenerateNeighbors(C = 9, R = 8, packageName = "precomp", className = "Neighbors9x8") +@GenerateNeighbors(C = 9, R = 8, packageName = "precomp", className = "Neighbors9x8", MIN_LEN = 3) public final class Trigger { } diff --git a/src/test/java/puzzle/CornerClueTest.java b/src/test/java/puzzle/CornerClueTest.java index 6dd1624..c79f1f2 100644 --- a/src/test/java/puzzle/CornerClueTest.java +++ b/src/test/java/puzzle/CornerClueTest.java @@ -48,4 +48,46 @@ public class CornerClueTest { assertEquals(1, slots.length); assertEquals(4, Masker.Slot.dir(slots[0].key())); } + + @Test + void testCornerDownLeftSlot() { + Clues clues = Clues.createEmpty(); + // Clue op (0,1), type 5 (Corner Down Left) + // Should result in word starting at (0,0) going down. + int idx = Masker.offset(0, 1); + clues.setClueLo(1L << idx, (byte)5); + + assertEquals(5, clues.getDir(idx)); + + // Controleer of forEachSlot het slot vindt + final boolean[] found = {false}; + clues.forEachSlot((key, lo, hi) -> { + if (Masker.Slot.dir(key) == 5) { + found[0] = true; + // Woord zou moeten starten op (0,0) + int startIdx = Masker.offset(0, 0); + assertTrue((lo & (1L << startIdx)) != 0, "Slot should start at (0,0)"); + // En omlaag gaan + int secondIdx = Masker.offset(1, 0); + assertTrue((lo & (1L << secondIdx)) != 0, "Slot should continue to (1,0)"); + + // Lengte van het slot zou 8 moeten zijn (van rij 0 t/m 7 in kolom 0) + assertEquals(8, Masker.Slot.length(lo, hi)); + } + }); + assertTrue(found[0], "Corner Down Left slot should be found"); + } + + @Test + void testCornerDownLeftExtraction() { + Clues clues = Clues.createEmpty(); + int idx = Masker.offset(0, 1); + clues.setClueLo(1L << idx, (byte)5); + + DictEntry[] dict = DictData.DICT.index(); + Slotinfo[] slots = Masker.slots(clues, dict); + + assertEquals(1, slots.length); + assertEquals(5, Masker.Slot.dir(slots[0].key())); + } } diff --git a/src/test/java/puzzle/ExportFormatTest.java b/src/test/java/puzzle/ExportFormatTest.java index 2f8ee5b..7607ecb 100644 --- a/src/test/java/puzzle/ExportFormatTest.java +++ b/src/test/java/puzzle/ExportFormatTest.java @@ -50,7 +50,7 @@ public class ExportFormatTest { var fillResult = new FillResult(true, 0, 0, 0, 0, new FillStats()); var puzzleResult = new PuzzleResult(new Clued(clues), grid, new Slotinfo[]{ - new Slotinfo(key, lo, 0L, 0, new Assign(TEST), null) + new Slotinfo(key, lo, 0L, 0, new Assign(TEST), null, 0) }, fillResult); var rewards = new Rewards(10, 5, 1); diff --git a/src/test/java/puzzle/MainTest.java b/src/test/java/puzzle/MainTest.java index 2d88237..b9b98b6 100644 --- a/src/test/java/puzzle/MainTest.java +++ b/src/test/java/puzzle/MainTest.java @@ -107,6 +107,8 @@ public class MainTest { assertTrue(Masker.Slot.horiz(3)); // Left assertFalse(Masker.Slot.horiz(0)); // Down assertFalse(Masker.Slot.horiz(2)); // Up + assertFalse(Masker.Slot.horiz(4)); // + assertFalse(Masker.Slot.horiz(5)); // } @Test public void testGridBasics() { diff --git a/src/test/java/puzzle/SwedishGeneratorTest.java b/src/test/java/puzzle/SwedishGeneratorTest.java index c8f1a6f..c15108e 100644 --- a/src/test/java/puzzle/SwedishGeneratorTest.java +++ b/src/test/java/puzzle/SwedishGeneratorTest.java @@ -18,8 +18,8 @@ import static puzzle.SwedishGeneratorTest.Idx.IDX_0_0; public class SwedishGeneratorTest { - public static final char C_DASH = '\0'; - public static final byte DASH = (byte) C_DASH; + public static final char C_DASH = '\0'; + public static final byte DASH = (byte) C_DASH; static Grid createEmpty() { return new Grid(new byte[SIZE], X, X); } record Context(long[] bitset) { @@ -29,19 +29,19 @@ public class SwedishGeneratorTest { public static Context get() { return CTX.get(); } } - static final long TEST = Lemma.from("TEST"); - static final long IN = Lemma.from("IN"); - static final long INER = Lemma.from("INER"); - static final long INEREN = Lemma.from("INEREN"); - static final long INERENA = Lemma.from("INERENA"); - static final long INERENAE = Lemma.from("INERENAE"); - static final long APPLE = Lemma.from("APPLE"); - static final long EXE = Lemma.from("AXE"); - static final long ABC = Lemma.from("ABC"); - static final long ABD = Lemma.from("ABD"); - static final long AZ = Lemma.from("AZ"); - static final long AB = Lemma.from("AB"); - static final long[] WORDS = new long[]{ + static final long TEST = Lemma.from("TEST"); + static final long IN = Lemma.from("IN"); + static final long INER = Lemma.from("INER"); + static final long INEREN = Lemma.from("INEREN"); + static final long INERENA = Lemma.from("INERENA"); + static final long INERENAE = Lemma.from("INERENAE"); + static final long APPLE = Lemma.from("APPLE"); + static final long EXE = Lemma.from("AXE"); + static final long ABC = Lemma.from("ABC"); + static final long ABD = Lemma.from("ABD"); + static final long AZ = Lemma.from("AZ"); + static final long AB = Lemma.from("AB"); + static final long[] WORDS = new long[]{ Lemma.from("AT"), Lemma.from("CAT"), Lemma.from("DOGS"), @@ -196,7 +196,7 @@ public class SwedishGeneratorTest { assertEquals(val1, rng2.nextU32()); for (var i = 0; i < 100; i++) { - var r = rng.randint(6); + var r = rng.randomClueDir(); assertTrue(r >= 0 && r <= 5); var f = rng.nextFloat(); assertTrue(f >= 0.0 && f <= 1.0);