introduce bitloops

This commit is contained in:
mike
2026-01-20 22:48:38 +01:00
parent b66437bb70
commit 85fa317eec
6 changed files with 95 additions and 88 deletions

View File

@@ -1,6 +1,9 @@
package puzzle;
import lombok.AccessLevel;
import lombok.experimental.FieldDefaults;
import org.junit.jupiter.api.Test;
import puzzle.Export.Clue;
import puzzle.Masker.Clues;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -8,17 +11,36 @@ import static precomp.Const9x8.OFF_0_0;
import static precomp.Const9x8.OFF_0_1;
import static precomp.Const9x8.OFF_1_0;
import static precomp.Const9x8.OFF_1_1;
import static puzzle.CornerClueTest.Cell.r0c1d5;
import static puzzle.CornerClueTest.Cell.r0c0d4;
public class CornerClueTest {
enum Cell {
r0c0d4(Clue.LEFT_TOP4, OFF_0_0),
r0c1d5(Clue.RIGHT_TOP5, OFF_0_1);
final public byte d;
final public long mask;
final public int index;
Cell(Clue d, int off) {
this.d = d.dir;
this.mask = 1L << off;
this.index = off;
}
public Clues attach(Clues c) {
c.setClueLo(mask, d);
return c;
}
public Clues attach() { return attach(Clues.createEmpty()); }
public int dir(Clues clues) { return clues.getDir(index); }
}
@Test
void testCornerDownSlot() {
var clues = Clues.createEmpty();
// Clue op (0,0), type 4 (Corner Down)
var idx = OFF_0_0;
clues.setClueLo(1L << idx, (byte) 4);
assertEquals(4, clues.getDir(idx));
var clues = r0c0d4.attach();
// Clue op (0,0), type 4 (Corner Down)
assertEquals(Clue.LEFT_TOP4.dir, r0c0d4.dir(clues));
// Controleer of forEachSlot het slot vindt
final var found = new boolean[]{ false };
@@ -39,25 +61,16 @@ public class CornerClueTest {
@Test
void testCornerDownExtraction() {
var clues = Clues.createEmpty();
clues.setClueLo(1L << OFF_0_0, (byte) 4);
var dict = DictData.DICT.index();
var slots = Masker.slots(clues, dict);
var slots = Masker.slots(r0c0d4.attach(), DictData.DICT.index());
assertEquals(1, slots.length);
assertEquals(4, Masker.Slot.dir(slots[0].key()));
}
@Test
void testCornerDownLeftSlot() {
var clues = Clues.createEmpty();
// Clue op (0,1), type 5 (Corner Down Left)
// Should result in word starting at (0,0) going down.
var idx = OFF_0_1;
clues.setClueLo(1L << idx, (byte) 5);
var clues = r0c1d5.attach();
assertEquals(5, clues.getDir(idx));
assertEquals(Clue.RIGHT_TOP5.dir, r0c1d5.dir(clues));
// Controleer of forEachSlot het slot vindt
final var found = new boolean[]{ false };
@@ -78,13 +91,9 @@ public class CornerClueTest {
@Test
void testCornerDownLeftExtraction() {
var clues = Clues.createEmpty();
clues.setClueLo(1L << OFF_0_1, (byte) 5);
var dict = DictData.DICT.index();
var slots = Masker.slots(clues, dict);
var slots = Masker.slots(r0c1d5.attach(), DictData.DICT.index());
assertEquals(1, slots.length);
assertEquals(5, Masker.Slot.dir(slots[0].key()));
assertEquals(Clue.RIGHT_TOP5.dir, Masker.Slot.dir(slots[0].key()));
}
}

View File

@@ -2,7 +2,6 @@ package puzzle;
import module java.base;
import lombok.val;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import puzzle.Export.Clued;
import puzzle.Export.Gridded;
@@ -21,8 +20,8 @@ import static precomp.Const9x8.OFF_0_1;
import static precomp.Const9x8.OFF_0_2;
import static precomp.Const9x8.OFF_0_3;
import static precomp.Const9x8.OFF_0_4;
import static puzzle.Export.Clue.LEFT;
import static puzzle.Export.Clue.RIGHT;
import static puzzle.Export.Clue.LEFT3;
import static puzzle.Export.Clue.RIGHT1;
import static puzzle.SwedishGenerator.C;
import static puzzle.Masker.Clues;
import static puzzle.SwedishGenerator.FillStats;
@@ -37,14 +36,14 @@ public class ExportFormatTest {
void testExportFormatFromFilled() {
val clues = Clues.createEmpty();
// Place a RIGHT clue at (0,0)
clues.setClueLo(Idx.IDX_0_0.lo, RIGHT.dir);
clues.setClueLo(Idx.IDX_0_0.lo, RIGHT1.dir);
// This creates a slot starting at (0,1)
// Terminate the slot at (0,5) with another digit to avoid it extending to MAX_WORD_LENGTH
clues.setClueLo(Idx.IDX_0_5.lo, LEFT.dir);
clues.setClueLo(Idx.IDX_0_5.lo, LEFT3.dir);
var grid = new Gridded(clues);
// key = (cellIndex << 2) | (direction)
var key = Slot.packSlotKey(0, RIGHT.dir);
var key = Slot.packSlotKey(0, RIGHT1.dir);
var lo = (1L << OFF_0_1) | (1L << OFF_0_2) | (1L << OFF_0_3) | (1L << OFF_0_4);
assertTrue(placeWord(grid.grid(), grid.grid().g, key, lo, 0L, TEST));

View File

@@ -4,6 +4,7 @@ import module java.base;
import lombok.val;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import precomp.Neighbors9x8.rci;
import puzzle.Export.ClueAt;
import puzzle.Export.Clued;
import puzzle.Export.Gridded;
@@ -23,10 +24,10 @@ import static precomp.Const9x8.OFF_1_1;
import static precomp.Const9x8.OFF_1_2;
import static precomp.Const9x8.OFF_2_1;
import static precomp.Const9x8.OFF_2_3;
import static puzzle.Export.Clue.DOWN;
import static puzzle.Export.Clue.LEFT;
import static puzzle.Export.Clue.RIGHT;
import static puzzle.Export.Clue.UP;
import static puzzle.Export.Clue.DOWN0;
import static puzzle.Export.Clue.LEFT3;
import static puzzle.Export.Clue.RIGHT1;
import static puzzle.Export.Clue.UP2;
import static puzzle.SwedishGenerator.Lemma;
import static puzzle.SwedishGenerator.Slotinfo;
import static puzzle.SwedishGenerator.fillMask;
@@ -70,11 +71,11 @@ public class MainTest {
assertEquals(1, slots.length);
var s = slots[0];
assertEquals(8, Masker.Slot.length(s.lo(), s.hi()));
var cells = Gridded.cellWalk((byte) s.key(), s.lo(), s.hi()).toArray();
assertEquals(0, Masker.IT[cells[0]].r());
assertEquals(1, Masker.IT[cells[0]].c());
assertEquals(0, Masker.IT[cells[1]].r());
assertEquals(2, Masker.IT[cells[1]].c());
var cells = Gridded.cellWalk((byte) s.key(), s.lo(), s.hi()).mapToObj(c-> Masker.IT[c]).toArray(rci[]::new);
assertEquals(0, cells[0].r());
assertEquals(1, cells[0].c());
assertEquals(0, cells[1].r());
assertEquals(2, cells[1].c());
}
@Test
@@ -125,10 +126,10 @@ public class MainTest {
Assertions.assertEquals(CLUE_UP, clueMap.get(OFF_2_1));
// Test isLetterAt
Assertions.assertTrue(clues.notClue(OFF_0_0));
Assertions.assertTrue(clues.notClue(OFF_1_2));
Assertions.assertTrue(clues.notClue(OFF_2_3));
Assertions.assertFalse(clues.isClueLo(OFF_1_1));
Assertions.assertFalse(clueMap.containsKey(OFF_0_0));
Assertions.assertFalse(clueMap.containsKey(OFF_1_2));
Assertions.assertFalse(clueMap.containsKey(OFF_2_3));
Assertions.assertFalse(clueMap.containsKey(OFF_1_1));
// Test isDigitAt
Assertions.assertFalse(clues.isClueLo(OFF_0_0));
@@ -146,19 +147,19 @@ public class MainTest {
@Test
public void testCluesDeepCopy() {
var clues = new Clued(Masker.Clues.createEmpty());
clues.setClueLo(IDX_0_0.lo, RIGHT.dir);
clues.setClueLo(IDX_0_1.lo, UP.dir);
clues.setClueLo(IDX_1_0.lo, LEFT.dir);
clues.setClueLo(IDX_1_1.lo, DOWN.dir);
clues.setClueLo(IDX_0_0.lo, RIGHT1.dir);
clues.setClueLo(IDX_0_1.lo, UP2.dir);
clues.setClueLo(IDX_1_0.lo, LEFT3.dir);
clues.setClueLo(IDX_1_1.lo, DOWN0.dir);
var copy = clues.deepCopyGrid();
var clueMap = clues.stream().collect(Collectors.toMap(ClueAt::index, ClueAt::clue));
Assertions.assertEquals(CLUE_RIGHT, clueMap.get(OFF_0_0));
copy.setClueLo(IDX_0_0.lo, DOWN.dir);
copy.setClueLo(IDX_0_0.lo, DOWN0.dir);
var copied = copy.stream().collect(Collectors.toMap(ClueAt::index, ClueAt::clue));
Assertions.assertEquals(DOWN.dir, copied.get(OFF_0_0));
Assertions.assertEquals(RIGHT.dir, clueMap.get(OFF_0_0));
Assertions.assertEquals(DOWN0.dir, copied.get(OFF_0_0));
Assertions.assertEquals(RIGHT1.dir, clueMap.get(OFF_0_0));
}
@Test
public void testMini() {

View File

@@ -13,13 +13,12 @@ import puzzle.Masker.Slot;
import static org.junit.jupiter.api.Assertions.*;
import static precomp.Const9x8.*;
import static precomp.Const9x8.Cell.r0c0d1;
import static puzzle.SwedishGenerator.*;
import static puzzle.SwedishGeneratorTest.Idx.IDX_0_0;
public class SwedishGeneratorTest {
public static final char C_DASH = '\0';
public static final byte DASH = (byte) C_DASH;
static Grid createEmpty() { return new Grid(new byte[SIZE], X, X); }
record Context(long[] bitset) {
@@ -137,8 +136,8 @@ public class SwedishGeneratorTest {
@Test
void testPatternForSlotMixed() {
var grid = createEmpty();
GridBuilder.placeWord(grid, grid.g, Slot.packSlotKey(0, CLUE_RIGHT), 1L << OFF_0_0, 0, Lemma.from("A"));
GridBuilder.placeWord(grid, grid.g, Slot.packSlotKey(0, CLUE_RIGHT), 1L << OFF_2_0, 0, Lemma.from("C"));
GridBuilder.placeWord(grid, grid.g, r0c0d1.slotKey, 1L << OFF_0_0, 0, Lemma.from("A"));
GridBuilder.placeWord(grid, grid.g, r0c0d1.slotKey, 1L << OFF_2_0, 0, Lemma.from("C"));
var key = Slot.packSlotKey(OFF_1_0, CLUE_RIGHT);
var pattern = patternForSlot(grid.lo, grid.hi, grid.g, key, 7L, 0L);
assertEquals(14081L, pattern);
@@ -155,7 +154,8 @@ public class SwedishGeneratorTest {
@Test
void testPatternForSlotSingleLetter() {
var grid = createEmpty();
GridBuilder.placeWord(grid, grid.g, Slot.packSlotKey(0, CLUE_RIGHT), 1L << OFF_0_0, 0, Lemma.from("A"));
//Slot.packSlotKey(0, CLUE_RIGHT)
GridBuilder.placeWord(grid, grid.g, r0c0d1.slotKey, 1L << OFF_0_0, 0, Lemma.from("A"));
var key = Slot.packSlotKey(1, CLUE_RIGHT);
var pattern = patternForSlot(grid.lo, grid.hi, grid.g, key, 7L, 0L);
assertEquals(1L, pattern);
@@ -189,7 +189,7 @@ public class SwedishGeneratorTest {
void testGrid() {
var empty = Clues.createEmpty();
var grid = new Gridded(empty);
GridBuilder.placeWord(grid.grid(), grid.grid().g, Slot.packSlotKey(0, CLUE_RIGHT), 1L << OFF_0_0, 0, Lemma.from("A"));
GridBuilder.placeWord(grid.grid(), grid.grid().g, r0c0d1.slotKey, 1L << OFF_0_0, 0, Lemma.from("A"));
val arr = grid.stream(empty).collect(Collectors.toMap(LetterAt::index, LetterAt::letter));
assertEquals(1, arr.size());
assertEquals(LETTER_A, arr.get(OFF_0_0));
@@ -393,8 +393,8 @@ public class SwedishGeneratorTest {
grid.grid().lo = low;
map = grid.stream(Masker.Clues.createEmpty()).collect(Collectors.toMap(LetterAt::index, LetterAt::letter));
assertEquals(0, map.size());
assertEquals(DASH, map.getOrDefault(OFF_0_1, DASH));
assertEquals(DASH, map.getOrDefault(OFF_0_2, DASH));
assertFalse(map.containsKey(OFF_0_1));
assertFalse(map.containsKey(OFF_0_2));
}
@Test