introduce bitloops

This commit is contained in:
mike
2026-01-22 18:47:04 +01:00
parent a659bd5162
commit 2295a7d97c
71 changed files with 254 additions and 205151 deletions

View File

@@ -2,8 +2,8 @@ package puzzle;
import lombok.val;
import org.junit.jupiter.api.Test;
import puzzle.Export.Clued;
import puzzle.Export.Gridded;
import puzzle.Export.Signa;
import puzzle.Export.Puzzle;
import puzzle.Export.Placed;
import puzzle.Export.PuzzleResult;
import puzzle.Export.Rewards;
@@ -36,7 +36,7 @@ public class MarkerTest {
for (var i = 0; i < 200; i++) {
for (var j = 19; j < 24; j++) {
var clues = masker.randomMask(j);
assertTrue(masker.isValid(clues), "Mask should be valid for length \n" + new Clued(clues).gridToString());
assertTrue(masker.isValid(clues), "Mask should be valid for length \n" + new Signa(clues).gridToString());
}
}
}
@@ -54,7 +54,7 @@ public class MarkerTest {
simCount++;
masker.mutate(clues);
sim += orig.similarity(clues);
assertTrue(masker.isValid(clues), "Mask should be valid for length \n" + new Clued(clues).gridToString());
assertTrue(masker.isValid(clues), "Mask should be valid for length \n" + new Signa(clues).gridToString());
}
}
System.out.println("Average similarity: " + sim / simCount);
@@ -73,21 +73,21 @@ public class MarkerTest {
simCount++;
var cross = masker.crossover(clues, clues2);
sim += Math.max(cross.similarity(clues), cross.similarity(clues2));
assertTrue(masker.isValid(cross), "Mask should be valid for length \n" + new Clued(cross).gridToString());
assertTrue(masker.isValid(cross), "Mask should be valid for length \n" + new Signa(cross).gridToString());
}
}
System.out.println("Average similarity: " + sim / simCount);
}
@Test
void testSimilarity() {
var a = Clued.of(r0c0d1, r2c1d0).c();
var b = Clued.of(r0c0d1, r2c1d0).c();
var a = Signa.of(r0c0d1, r2c1d0).c();
var b = Signa.of(r0c0d1, r2c1d0).c();
// Identity
assertEquals(1.0, a.similarity(b), 0.001);
// Different direction
var c = Clued.of(r0c0d0, r2c1d0);
var c = Signa.of(r0c0d0, r2c1d0);
assertTrue(a.similarity(c.c()) < 1.0);
// Completely different
@@ -103,10 +103,10 @@ public class MarkerTest {
assertTrue(masker.isValid(Clues.createEmpty()));
// Valid clue: Right from (0,0) in 9x8 grid. Length is 8.
assertTrue(masker.isValid(Clued.of(r0c0d1).c()));
assertTrue(masker.isValid(Signa.of(r0c0d1).c()));
// Invalid clue: Right from (0,7) in 9x8 grid. Length is 1 (too short if MIN_LEN >= 2).
assertFalse(masker.isValid(Clued.of(r0c7d1).c()));
assertFalse(masker.isValid(Signa.of(r0c7d1).c()));
}
@Test
@@ -138,18 +138,18 @@ public class MarkerTest {
// Clue 1: (0,0) Right. Slot cells: (0,1), (0,2), (0,3), (0,4), (0,5), (0,6), (0,7), (0,8)
// Clue 2: (1,2) Up. Slot cells: (0,2)
// Intersection is exactly 1 cell (0,2). Valid.
assertTrue(masker.isValid(Clued.of(r0c0d1, r2c2d2).c()));
assertTrue(masker.isValid(Signa.of(r0c0d1, r2c2d2).c()));
// Clue 3: (1,1) Right. Slot cells: (1,2), (1,3), ...
// No intersection with Clue 1 or 2. Valid.
assertTrue(masker.isValid(Clued.of(r0c0d1, r2c2d2, r1c1d1).c()));
assertTrue(masker.isValid(Signa.of(r0c0d1, r2c2d2, r1c1d1).c()));
// Now create a violation: two slots sharing 2 cells.
// We can do this with Corner Down and another clue.
// Clue A: (0,0) Corner Down. Starts at (0,1) goes down: (0,1), (1,1), (2,1), (3,1), ...
// Clue B: (0,2) Corner Down Left. Starts at (0,1) goes down: (0,1), (1,1), (2,1), ...
// They share MANY cells starting from (0,1).
assertFalse(masker.isValid(Clued.of(r0c0d4, r0c2d5).c()));
assertFalse(masker.isValid(Signa.of(r0c0d4, r0c2d5).c()));
}
@Test
@@ -233,7 +233,7 @@ public class MarkerTest {
}
@Test
void testCornerDownSlot() {
var clues = Clued.of(r0c0d4);
var clues = Signa.of(r0c0d4);
// Clue op (0,0), type 4 (Corner Down)
assertEquals(r0c0d4.d, clues.getDir(r0c0d4.index));
@@ -257,14 +257,14 @@ public class MarkerTest {
@Test
void testCornerDownExtraction() {
var slots = Masker.slots(Clued.of(r0c0d4).c(), DictData950.DICT950.index());
var slots = Masker.slots(Signa.of(r0c0d4).c(), DictData950.DICT950.index());
assertEquals(1, slots.length);
assertEquals(r0c0d4.d, Masker.Slot.dir(slots[0].key()));
}
@Test
void testCornerDownLeftSlot() {
var clues = Clued.of(r0c1d5);
var clues = Signa.of(r0c1d5);
assertEquals(r0c1d5.d, clues.getDir(r0c1d5.index));
@@ -287,15 +287,15 @@ public class MarkerTest {
@Test
void testCornerDownLeftExtraction() {
var slots = Clued.of(r0c1d5).slots(DictData950.DICT950);
var slots = Signa.of(r0c1d5).slots(DictData950.DICT950);
assertEquals(1, slots.length);
assertEquals(r0c1d5.d, Masker.Slot.dir(slots[0].key()));
}
@Test
void testExportFormatFromFilled() {
val clues = Clued.of(r0c0d1, r0c5d3);
var grid = new Gridded(clues);
val clues = Signa.of(r0c0d1, r0c5d3);
var grid = new Puzzle(clues);
// key = (cellIndex << 2) | (direction)
var key = r0c0d1.slotKey;
@@ -346,7 +346,7 @@ public class MarkerTest {
var grid = SwedishGeneratorTest.createEmpty();
val clues = Clues.createEmpty();
var fillResult = new FillResult(true, 0, 0, 0, 0, new FillStats());
var puzzleResult = new PuzzleResult(new Clued(clues), new Gridded(grid, clues), new Slotinfo[0], fillResult);
var puzzleResult = new PuzzleResult(new Signa(clues), new Puzzle(grid, clues), new Slotinfo[0], fillResult);
var exported = puzzleResult.exportFormatFromFilled(new Rewards(0, 0, 0));
@@ -362,19 +362,20 @@ public class MarkerTest {
@Test
void testShardToClue() {
var bytes = Export.BYTES.get();
for (var length = 2; length <= 8; length++) {
val entry = DictData950.DICT950.index()[length];
if (entry == null) continue;
val words = entry.words();
for (var i = 0; i < Math.min(words.length, 5); i++) {
val wordVal = words[i];
val word = Lemma.asWord(wordVal, Export.BYTES.get());
val clueRec = Meta.lookup(wordVal);
assertNotNull(clueRec);
assertEquals(word, Lemma.asWord(clueRec.w(), Export.BYTES.get()));
assertTrue(clueRec.simpel() >= 0);
assertTrue(clueRec.clues().length > 0);
val rec = Meta.lookupSilent(wordVal);
assertNotNull(rec);
assertEquals(Lemma.asWord(wordVal, bytes), Lemma.asWord(rec.w(), bytes));
assertTrue(rec.simpel() >= 0);
assertTrue(rec.clues().length > 0);
}
}
}
@@ -382,13 +383,14 @@ public class MarkerTest {
@Test
void testSpecificWords() {
// These words are known to be in the CSV and likely in the dictionary
var bytes = Export.BYTES.get();
var testWords = new String[]{ "EEN", "NAAR", "IEDEREEN" };
for (var wStr : testWords) {
var w = Lemma.from(wStr);
val clueRec = Meta.lookup(w);
val clueRec = Meta.lookupSilent(w);
assertNotNull(clueRec);
assertEquals(wStr, Lemma.asWord(clueRec.w(), Export.BYTES.get()));
assertEquals(wStr, Lemma.asWord(clueRec.w(), bytes));
// Check some expected complexity values (from CSV head output, column 3)
if (wStr.equals("EEN")) {
assertEquals(451, clueRec.simpel());