introduce bitloops

This commit is contained in:
mike
2026-01-14 00:57:41 +01:00
parent 2430dbdfb9
commit 1d731334d9
6 changed files with 144 additions and 149 deletions

View File

@@ -35,7 +35,7 @@ public class ExportFormatTest {
var clueMap = new long[300];
// key = (cellIndex << 2) | (direction)
var key = (0 << 2) | (CLUE_RIGHT);
var key = (0) | (CLUE_RIGHT);
clueMap[key] = Lemma.from("TEST");
// Manually fill the grid letters for "TEST" at (0,1), (0,2), (0,3), (0,4)
@@ -44,9 +44,9 @@ public class ExportFormatTest {
grid.setLetter(Grid.offset(0, 3), (byte) 'S');
grid.setLetter(Grid.offset(0, 4), (byte) 'T');
// Terminate the slot at (0,5) with another digit to avoid it extending to MAX_WORD_LENGTH
grid.setClue(Grid.offset(0, 5), CLUE_UP);
grid.setClue(Grid.offset(0, 5), CLUE_LEFT);
var fillResult = new FillResult(true, new Gridded(grid), clueMap, new FillStats());
var fillResult = new FillResult(true, new Gridded(grid), clueMap, new FillStats(0, 0, 0, 0));
var puzzleResult = new PuzzleResult(swe, null, null, fillResult);
var rewards = new Rewards(10, 5, 1);
@@ -86,7 +86,7 @@ public class ExportFormatTest {
void testExportFormatEmpty() {
var swe = new SwedishGenerator(new Rng(0));
var grid = Grid.createEmpty();
var fillResult = new FillResult(true, new Gridded(grid), new long[300], new FillStats());
var fillResult = new FillResult(true, new Gridded(grid), new long[300], new FillStats(0, 0, 0, 0));
var puzzleResult = new PuzzleResult(swe, null, null, fillResult);
var exported = puzzleResult.exportFormatFromFilled(1, new Rewards(0, 0, 0));

View File

@@ -42,8 +42,8 @@ public class MainTest {
grid.setLetter(OFF_0_2, LETTER_B);
var slots = extractSlots(grid);
assertEquals(1, slots.size());
var s = slots.getFirst();
assertEquals(1, slots.length);
var s = slots[0];
assertEquals(8, s.length());
var cells = s.walk().toArray();
assertEquals(0, Grid.r(cells[0]));

View File

@@ -1,5 +1,6 @@
package puzzle;
import lombok.val;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import puzzle.Export.IntListDTO;
@@ -35,36 +36,36 @@ public class SwedishGeneratorTest {
static final byte D_BYTE_2 = CLUE_RIGHT;
@Test
void testPatternForSlotAllLetters() {
var grid = new Grid(new byte[]{ LETTER_A, LETTER_B, LETTER_C });
var slot = Slot.from(18 << Slot.BIT_FOR_DIR | (CLUE_RIGHT), 7L, 0L);
long pattern = patternForSlot(grid, slot);
var grid = new Grid(new byte[]{ LETTER_A, LETTER_B, LETTER_C });
var slot = Slot.from(18 << Slot.BIT_FOR_DIR | (CLUE_RIGHT), 7L, 0L);
var pattern = patternForSlot(grid, slot);
assertEquals(1L | (28L << 8) | (55L << 16), pattern);
}
@Test
void testPatternForSlotMixed() {
var grid = new Grid(new byte[]{ LETTER_A, DASH, LETTER_C });
var slot = Slot.from(1 << Slot.BIT_FOR_DIR | (CLUE_RIGHT), 7L, 0L);
long pattern = patternForSlot(grid, slot);
var grid = new Grid(new byte[]{ LETTER_A, DASH, LETTER_C });
var slot = Slot.from(1 << Slot.BIT_FOR_DIR | (CLUE_RIGHT), 7L, 0L);
var pattern = patternForSlot(grid, slot);
assertEquals(1L | (0L << 8) | (55L << 16), pattern);
}
@Test
void testPatternForSlotAllDashes() {
var grid = new Grid(new byte[]{ DASH, DASH, DASH }); // - - -
var slot = Slot.from(1 << Slot.BIT_FOR_DIR | (CLUE_RIGHT), 7L, 0L);
long pattern = patternForSlot(grid, slot);
var grid = new Grid(new byte[]{ DASH, DASH, DASH }); // - - -
var slot = Slot.from(1 << Slot.BIT_FOR_DIR | (CLUE_RIGHT), 7L, 0L);
var pattern = patternForSlot(grid, slot);
assertEquals(0L, pattern);
}
@Test
void testPatternForSlotSingleLetter() {
var grid = new Grid(new byte[]{ LETTER_A, DASH, DASH });
var slot = Slot.from(1 << Slot.BIT_FOR_DIR | (CLUE_RIGHT), 7L, 0L);
long pattern = patternForSlot(grid, slot);
var grid = new Grid(new byte[]{ LETTER_A, DASH, DASH });
var slot = Slot.from(1 << Slot.BIT_FOR_DIR | (CLUE_RIGHT), 7L, 0L);
var pattern = patternForSlot(grid, slot);
assertEquals(1L, pattern);
}
@@ -186,17 +187,17 @@ public class SwedishGeneratorTest {
static int intersectSorted(int[] a, int aLen, int[] b, int bLen, int[] out) {
if (aLen == 0 || bLen == 0) return 0;
if (aLen < bLen >>> 4) {
int k = 0;
for (int i = 0; i < aLen; i++) {
int x = a[i];
var k = 0;
for (var i = 0; i < aLen; i++) {
var x = a[i];
if (Arrays.binarySearch(b, 0, bLen, x) >= 0) out[k++] = x;
}
return k;
}
if (bLen < aLen >>> 4) {
int k = 0;
for (int i = 0; i < bLen; i++) {
int y = b[i];
var k = 0;
for (var i = 0; i < bLen; i++) {
var y = b[i];
if (Arrays.binarySearch(a, 0, aLen, y) >= 0) out[k++] = y;
}
return k;
@@ -233,10 +234,10 @@ public class SwedishGeneratorTest {
}
static long packPattern(String s) {
long p = 0;
byte[] b = s.getBytes(StandardCharsets.US_ASCII);
for (int i = 0; i < b.length; i++) {
int val = b[i] & 31;
long p = 0;
var b = s.getBytes(StandardCharsets.US_ASCII);
for (var i = 0; i < b.length; i++) {
var val = b[i] & 31;
if (val != 0) {
p |= (long) (i * 26 + val) << (i << 3);
}
@@ -258,7 +259,7 @@ public class SwedishGeneratorTest {
var dict = new Dict(new long[]{ l0, l1, l2, l3, l3a, l4a, l6a, l7a, l8a });
// Pattern "APP--" for length 5
var info = candidateInfoForPattern(Context.get(), packPattern("APP"), dict.index()[5], 5);
var info = candidateInfoForPattern(Context.get().bitset(), packPattern("APP"), dict.index()[5], 5);
assertEquals(2, info.count());
assertNotNull(info.indices());
@@ -274,8 +275,8 @@ public class SwedishGeneratorTest {
// This should detect a slot starting at 0,1 with length 2 (0,1 and 0,2)
var slots = extractSlots(grid);
assertEquals(1, slots.size());
var s = slots.getFirst();
assertEquals(1, slots.length);
var s = slots[0];
assertTrue(s.length() >= 2);
assertEquals(OFF_0_0, s.clueIndex());
@@ -284,19 +285,16 @@ public class SwedishGeneratorTest {
@Test
void testMaskFitnessBasic() {
var gen = new SwedishGenerator(new Rng(0));
var grid = Grid.createEmpty();
var lenCounts = new int[12];
lenCounts[2] = 10;
lenCounts[8] = 10; // In case MAX_WORD_LENGTH is 8
var gen = new SwedishGenerator(new Rng(0));
var grid = Grid.createEmpty();
var stack = new int[STACK_SIZE];
// Empty grid should have high penalty (no slots)
var f1 = gen.maskFitness(grid);
var f1 = gen.maskFitness(grid, stack);
assertTrue(f1 >= 1_000_000_000L);
// Add a slot
grid.setClue(OFF_0_0, D_BYTE_2);
var f2 = gen.maskFitness(grid);
var f2 = gen.maskFitness(grid, stack);
assertTrue(f2 < f1);
}
@@ -312,12 +310,10 @@ public class SwedishGeneratorTest {
assertNotNull(g2);
assertNotSame(g1, g2);
var g3 = gen.crossover(g1, g2);
assertNotNull(g3);
assertNotNull(gen.crossover(g1, g2));
var lenCounts = new int[12];
Arrays.fill(lenCounts, 10);
var g4 = gen.hillclimb(g1, 10);
val stack = new int[STACK_SIZE];
var g4 = gen.hillclimb(stack, g1, 10);
assertNotNull(g4);
}
@@ -395,7 +391,7 @@ public class SwedishGeneratorTest {
assertFalse(sDec.increasing());
// 2. Test slotScore
int[] counts = new int[SIZE];
val counts = new byte[SIZE];
counts[1] = 2;
counts[2] = 3;
var sScore = Slot.from(0, (1L << 1) | (1L << 2), 0L);
@@ -419,29 +415,29 @@ public class SwedishGeneratorTest {
var dict = new Dict(words);
var entry5 = dict.index()[5];
var ctx = Context.get();
long pattern = packPattern("APP");
assertEquals(2, candidateCountForPattern(ctx, pattern, entry5, 3));
var ctx = Context.get();
var pattern = packPattern("APP");
assertEquals(2, candidateCountForPattern(ctx.bitset(), pattern, entry5, 3));
pattern = packPattern("BAN");
assertEquals(1, candidateCountForPattern(ctx, pattern, entry5, 3));
assertEquals(1, candidateCountForPattern(ctx.bitset(), pattern, entry5, 3));
pattern = packPattern("CAT");
assertEquals(0, candidateCountForPattern(ctx, pattern, entry5, 3));
assertEquals(0, candidateCountForPattern(ctx.bitset(), pattern, entry5, 3));
}
@Test
void testMaskFitnessDetailed() {
var gen = new SwedishGenerator(new Rng(42));
var grid = Grid.createEmpty();
var gen = new SwedishGenerator(new Rng(42));
var grid = Grid.createEmpty();
val stack = new int[STACK_SIZE];
// Empty grid: huge penalty
long fitEmpty = gen.maskFitness(grid);
var fitEmpty = gen.maskFitness(grid, stack);
assertTrue(fitEmpty >= 1_000_000_000L);
// Grid with one short slot: still high penalty but less than empty
grid.setClue(0, D_BYTE_2); // Right from 0,0. Len 2 if 3x3.
long fitOne = gen.maskFitness(grid);
var fitOne = gen.maskFitness(grid, stack);
assertTrue(fitOne < fitEmpty);
// Test penalty for TARGET_CLUES