introduce bitloops
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user