introduce bitloops

This commit is contained in:
mike
2026-01-14 07:25:46 +01:00
parent 5d34893ef1
commit c529ce90c7
7 changed files with 144 additions and 144 deletions

View File

@@ -12,15 +12,55 @@ import static puzzle.SwedishGenerator.*;
public class SwedishGeneratorTest {
static final byte LETTER_A = (byte) 'A';
static final byte LETTER_B = (byte) 'B';
static final byte LETTER_C = (byte) 'C';
static final byte LETTER_X = (byte) 'X';
static final byte LETTER_Z = (byte) 'Z';
static final byte CLUE_DOWN = 0;
static final byte CLUE_RIGHT = 1;
static final byte CLUE_UP = 2;
static final byte CLUE_LEFT = 3;
record Context(long[] bitset) {
public Context() { this(new long[2500]); }
private static final ThreadLocal<Context> CTX = ThreadLocal.withInitial(Context::new);
public static Context get() { return CTX.get(); }
}
static final long TEST = Lemma.from(0, "TEST");
static final long[] WORDS = new long[]{
Lemma.from(1, "AT"),
Lemma.from(2, "CAT"),
Lemma.from(3, "DOGS"),
Lemma.from(4, "APPLE"),
Lemma.from(5, "APPLY"),
Lemma.from(6, "BANAN"),
Lemma.from(7, "BANANA"),
Lemma.from(8, "BANANAS"),
Lemma.from(9, "BANANASS") // length 8
};
static final long l2a = Lemma.from(10, "IN");
static final long l4a = Lemma.from(11, "INER");
static final long l6a = Lemma.from(12, "INEREN");
static final long l7a = Lemma.from(13, "INERENA");
static final long l8a = Lemma.from(14, "INERENAE");
static final long l1 = Lemma.from(15, "APPLE");
static final long l2 = Lemma.from(16, "AXE");
static final long[] WORDS2 = new long[]{ Lemma.from(17, "IN"),
Lemma.from(18, "APPLE"),
Lemma.from(19, "APPLY"),
Lemma.from(20, "BANAN"),
Lemma.from(21, "INE"),
Lemma.from(22, "INER"),
Lemma.from(23, "INEREN"),
Lemma.from(24, "INERENA"),
Lemma.from(25, "INERENAE") };
static final long ABC = Lemma.from(26, "ABC");
static final long ABD = Lemma.from(27, "ABD");
static final long AZ = Lemma.from(28, "AZ");
static final byte LETTER_A = (byte) 'A';
static final byte LETTER_B = (byte) 'B';
static final byte LETTER_C = (byte) 'C';
static final byte LETTER_X = (byte) 'X';
static final byte LETTER_Z = (byte) 'Z';
static final byte CLUE_DOWN = 0;
static final byte CLUE_RIGHT = 1;
static final byte CLUE_UP = 2;
static final byte CLUE_LEFT = 3;
static final int OFF_0_0 = Grid.offset(0, 0);
static final int OFF_0_1 = Grid.offset(0, 1);
@@ -108,19 +148,11 @@ public class SwedishGeneratorTest {
@Test
void testLemmaAndDict() {
var l2a = Lemma.from("IN");
var l4a = Lemma.from("INER");
var l6a = Lemma.from("INEREN");
var l7a = Lemma.from("INERENA");
var l8a = Lemma.from("INERENAE");
var l1 = Lemma.from("APPLE");
Assertions.assertEquals(Lemma.pack("APPLE".getBytes(StandardCharsets.US_ASCII)), Lemma.unpackLetters(l1));
assertEquals(5, Lemma.length(l1));
assertEquals((byte) 'A', Lemma.byteAt(l1, 0));
assertEquals(1, Lemma.intAt(l1, 0));
var l2 = Lemma.from("AXE");
var dict = new Dict(new long[]{ l1, l2, l2a, l4a, l6a, l7a, l8a });
assertEquals(1, dict.index()[3].words().length);
@@ -232,19 +264,10 @@ public class SwedishGeneratorTest {
@Test
void testCandidateInfoForPattern() {
var l0 = Lemma.from("IN");
var l3a = Lemma.from("INE");
var l4a = Lemma.from("INER");
var l6a = Lemma.from("INEREN");
var l7a = Lemma.from("INERENA");
var l8a = Lemma.from("INERENAE");
var l1 = Lemma.from("APPLE");
var l2 = Lemma.from("APPLY");
var l3 = Lemma.from("BANAN");
var dict = new Dict(new long[]{ l0, l1, l2, l3, l3a, l4a, l6a, l7a, l8a });
var dict = new Dict(WORDS2);
// Pattern "APP--" for length 5
var info = candidateInfoForPattern(Context.get().bitset(), packPattern("APP"), dict.index()[5], 5);
var info = candidateInfoForPattern(Context.get().bitset(), packPattern("APP"), dict.index()[5].posBitsets(), dict.index()[5].numlong());
assertEquals(2, info.length);
assertNotNull(info);
@@ -255,7 +278,6 @@ public class SwedishGeneratorTest {
// This should detect a slot starting at 0,1 with length 2 (0,1 and 0,2)
var clues = Clues.createEmpty();
clues.setClue(OFF_0_0, CLUE_RIGHT);
var grid = clues.toGrid();
var slots = extractSlots(clues);
assertEquals(1, slots.length);
@@ -305,7 +327,7 @@ public class SwedishGeneratorTest {
var key = (OFF_0_0 << Slot.BIT_FOR_DIR) | (CLUE_RIGHT);
var lo = (1L << OFF_0_0) | (1L << OFF_0_1) | (1L << OFF_0_2);
var s = Slot.from(key, lo, 0L);
var w1 = Lemma.from("ABC");
var w1 = ABC;
var undoBuffer = new long[10];
// 1. Successful placement in empty grid
@@ -320,7 +342,7 @@ public class SwedishGeneratorTest {
assertEquals(0L, undoBuffer[2]); // 0 new characters placed
// 3. Conflict: place "ABD" where "ABC" is
var w2 = Lemma.from("ABD");
var w2 = ABD;
assertFalse(placeWord(grid, s, w2, undoBuffer, 2));
// Verify grid is unchanged (still "ABC")
assertEquals('A', grid.letter32At(OFF_0_0));
@@ -344,7 +366,7 @@ public class SwedishGeneratorTest {
var key = (OFF_0_0 << Slot.BIT_FOR_DIR) | (CLUE_RIGHT);
var lo = (1L << OFF_0_1) | (1L << OFF_0_2);
var s = Slot.from(key, lo, 0L);
var w = Lemma.from("AZ");
var w = AZ;
var undoBuffer = new long[10];
var placed = placeWord(grid, s, w, undoBuffer, 0);
@@ -381,30 +403,19 @@ public class SwedishGeneratorTest {
assertEquals(32, slotScore(counts, sScore));
// 3. Test candidateCountForPattern
var words = new long[]{
Lemma.from("AT"),
Lemma.from("CAT"),
Lemma.from("DOGS"),
Lemma.from("APPLE"),
Lemma.from("APPLY"),
Lemma.from("BANAN"),
Lemma.from("BANANA"),
Lemma.from("BANANAS"),
Lemma.from("BANANASS") // length 8
};
var dict = new Dict(words);
var dict = new Dict(WORDS);
var entry5 = dict.index()[5];
var ctx = Context.get();
var pattern = packPattern("APP");
assertEquals(2, candidateCountForPattern(ctx.bitset(), pattern, entry5, 3));
assertEquals(2, candidateCountForPattern(ctx.bitset(), pattern, entry5, entry5.numlong()));
pattern = packPattern("BAN");
assertEquals(1, candidateCountForPattern(ctx.bitset(), pattern, entry5, 3));
assertEquals(1, candidateCountForPattern(ctx.bitset(), pattern, entry5, entry5.numlong()));
pattern = packPattern("CAT");
assertEquals(0, candidateCountForPattern(ctx.bitset(), pattern, entry5, 3));
assertEquals(0, candidateCountForPattern(ctx.bitset(), pattern, entry5, entry5.numlong()));
}
@Test