introduce bitloops

This commit is contained in:
mike
2026-01-20 01:35:34 +01:00
parent 5678af332e
commit 7e5e363a3e
7 changed files with 74 additions and 51 deletions

View File

@@ -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;
}

View File

@@ -32,18 +32,18 @@ public record SwedishGenerator() {
public static final int BAR_LEN = 22; public static final int BAR_LEN = 22;
public static final int C = Config.PUZZLE_COLS; public static final int C = Config.PUZZLE_COLS;
public static final int R = Config.PUZZLE_ROWS; 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 int SIZE_MIN_1 = SIZE - 1;// ~18
public static final double SIZED = (double) SIZE;// ~18 public static final double SIZED = (double) SIZE;// ~18
public static final long MASK_LO = -1L; 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 = Config.PUZZLE_ROWS;
public static final int MAX_WORD_LENGTH_PLUS_ONE = MAX_WORD_LENGTH + 1; 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 MAX_TRIES_PER_SLOT = 700;//Config.MAX_TRIES_PER_SLOT;
public static final int STACK_SIZE = 128; 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_SIZE = Neighbors9x8.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_624 = Neighbors9x8.RANGE_0_624;//624L - 0L + 1L;
static final int PICK_NOT_DONE = -1; static final int PICK_NOT_DONE = -1;
static final int PICK_DONE = 0; static final int PICK_DONE = 0;
public static boolean isLo(int n) { return (n & 64) == 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) { } public static record DictEntry(long[] words, long[][] posBitsets, int length, int numlong) { }
//@formatter:on //@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_LO = Neighbors9x8.PATH_LO; public static final long[] PATH_HI = Neighbors9x8.PATH_HI;
public static final long[] PATH_HI = Neighbors9x8.PATH_HI;
public static final class Rng { public static final class Rng {
@@ -85,13 +84,10 @@ public record SwedishGenerator() {
x = y; x = y;
return y; return y;
} }
public byte randint2bitByte() { static final byte[] BYTE = new byte[]{ 0, 1, 2, 3/*,4, 5*/ };
int r = nextU32() & 7; public byte randomClueDir() { return rand(BYTE); }
if (r == 4) return (byte) 4;
return (byte) (r & 3);
}
public <T> T rand(T[] p) { return p[(int) (((nextU32() & 0xFFFFFFFFL) % ((long) p.length)))]; } public <T> 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_SIZE() { return (int) (((nextU32() & 0xFFFFFFFFL) % RANGE_0_SIZE)); }
public int randint0_624() { return (int) (((nextU32() & 0xFFFFFFFFL) % RANGE_0_624)); } public int randint0_624() { return (int) (((nextU32() & 0xFFFFFFFFL) % RANGE_0_624)); }
public double nextFloat() { return (nextU32() & 0xFFFFFFFFL) / 4294967295.0; } 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); } 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) { public static int wordCount(int k, Slotinfo[] arr) {
for (var n = 1; n < arr.length; n++) if (arr[n].assign.w != X) k++; 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 N = words.length;
var tries = Math.min(MAX_TRIES_PER_SLOT, N); for (var t = 0; t < s.minL; t++) {
for (var t = 0; t < tries; t++) {
var w = words[rng.biasedIndexPow3(N - 1)]; var w = words[rng.biasedIndexPow3(N - 1)];
var lemIdx = Lemma.unpackIndex(w); var lemIdx = Lemma.unpackIndex(w);
if (Bit1029.get(used, lemIdx)) continue; if (Bit1029.get(used, lemIdx)) continue;

View File

@@ -2,5 +2,5 @@
package puzzle; package puzzle;
import gen.GenerateNeighbors; 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 { } public final class Trigger { }

View File

@@ -48,4 +48,46 @@ public class CornerClueTest {
assertEquals(1, slots.length); assertEquals(1, slots.length);
assertEquals(4, Masker.Slot.dir(slots[0].key())); 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()));
}
} }

View File

@@ -50,7 +50,7 @@ public class ExportFormatTest {
var fillResult = new FillResult(true, 0, 0, 0, 0, new FillStats()); var fillResult = new FillResult(true, 0, 0, 0, 0, new FillStats());
var puzzleResult = new PuzzleResult(new Clued(clues), grid, new Slotinfo[]{ 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); }, fillResult);
var rewards = new Rewards(10, 5, 1); var rewards = new Rewards(10, 5, 1);

View File

@@ -107,6 +107,8 @@ public class MainTest {
assertTrue(Masker.Slot.horiz(3)); // Left assertTrue(Masker.Slot.horiz(3)); // Left
assertFalse(Masker.Slot.horiz(0)); // Down assertFalse(Masker.Slot.horiz(0)); // Down
assertFalse(Masker.Slot.horiz(2)); // Up assertFalse(Masker.Slot.horiz(2)); // Up
assertFalse(Masker.Slot.horiz(4)); //
assertFalse(Masker.Slot.horiz(5)); //
} }
@Test @Test
public void testGridBasics() { public void testGridBasics() {

View File

@@ -18,8 +18,8 @@ import static puzzle.SwedishGeneratorTest.Idx.IDX_0_0;
public class SwedishGeneratorTest { public class SwedishGeneratorTest {
public static final char C_DASH = '\0'; public static final char C_DASH = '\0';
public static final byte DASH = (byte) C_DASH; public static final byte DASH = (byte) C_DASH;
static Grid createEmpty() { return new Grid(new byte[SIZE], X, X); } static Grid createEmpty() { return new Grid(new byte[SIZE], X, X); }
record Context(long[] bitset) { record Context(long[] bitset) {
@@ -29,19 +29,19 @@ public class SwedishGeneratorTest {
public static Context get() { return CTX.get(); } public static Context get() { return CTX.get(); }
} }
static final long TEST = Lemma.from("TEST"); static final long TEST = Lemma.from("TEST");
static final long IN = Lemma.from("IN"); static final long IN = Lemma.from("IN");
static final long INER = Lemma.from("INER"); static final long INER = Lemma.from("INER");
static final long INEREN = Lemma.from("INEREN"); static final long INEREN = Lemma.from("INEREN");
static final long INERENA = Lemma.from("INERENA"); static final long INERENA = Lemma.from("INERENA");
static final long INERENAE = Lemma.from("INERENAE"); static final long INERENAE = Lemma.from("INERENAE");
static final long APPLE = Lemma.from("APPLE"); static final long APPLE = Lemma.from("APPLE");
static final long EXE = Lemma.from("AXE"); static final long EXE = Lemma.from("AXE");
static final long ABC = Lemma.from("ABC"); static final long ABC = Lemma.from("ABC");
static final long ABD = Lemma.from("ABD"); static final long ABD = Lemma.from("ABD");
static final long AZ = Lemma.from("AZ"); static final long AZ = Lemma.from("AZ");
static final long AB = Lemma.from("AB"); static final long AB = Lemma.from("AB");
static final long[] WORDS = new long[]{ static final long[] WORDS = new long[]{
Lemma.from("AT"), Lemma.from("AT"),
Lemma.from("CAT"), Lemma.from("CAT"),
Lemma.from("DOGS"), Lemma.from("DOGS"),
@@ -196,7 +196,7 @@ public class SwedishGeneratorTest {
assertEquals(val1, rng2.nextU32()); assertEquals(val1, rng2.nextU32());
for (var i = 0; i < 100; i++) { for (var i = 0; i < 100; i++) {
var r = rng.randint(6); var r = rng.randomClueDir();
assertTrue(r >= 0 && r <= 5); assertTrue(r >= 0 && r <= 5);
var f = rng.nextFloat(); var f = rng.nextFloat();
assertTrue(f >= 0.0 && f <= 1.0); assertTrue(f >= 0.0 && f <= 1.0);