introduce bitloops

This commit is contained in:
mike
2026-01-14 03:46:36 +01:00
parent 19f235ae59
commit eeae90a886
6 changed files with 19 additions and 22 deletions

View File

@@ -38,7 +38,7 @@ public record Export() {
}
}
public record Clued(Clues mask) {
public record Clued(@Delegate Clues mask) {
String gridToString() {
var sb = new StringBuilder();
@@ -190,7 +190,7 @@ public record Export() {
var g = filled().grid();
var placed = new ArrayList<Placed>();
var clueMap = filled().clueMap();
g.grid().forEachSlot((int key, long lo, long hi) -> {
mask.forEachSlot((int key, long lo, long hi) -> {
var word = clueMap[key];
if (word != 0L) {
placed.add(extractPlacedFromSlot(Slot.from(key, lo, hi), word));

View File

@@ -359,7 +359,7 @@ public class Main {
val stack = new int[STACK_SIZE];
var swe = new SwedishGenerator(rng, stack);
var mask = swe.generateMask(opts.pop, opts.gens, Math.max(opts.pop, (int) Math.floor(opts.pop * 1.5)));
var filled = fillMask(rng, mask.toGrid(), dict.index());
var filled = fillMask(rng, extractSlots(mask), mask.toGrid(), dict.index());
TOTAL_NODES.addAndGet(filled.stats().nodes);
TOTAL_BACKTRACKS.addAndGet(filled.stats().backtracks);

View File

@@ -272,6 +272,10 @@ public record SwedishGenerator(Rng rng, int[] stack) {
}
return grid;
}
public void forEachSlot(SlotVisitor visitor) {
for (var l = lo; l != X; l &= l - 1) processSlot(this, visitor, Long.numberOfTrailingZeros(l));
for (var h = hi; h != X; h &= h - 1) processSlot(this, visitor, 64 | Long.numberOfTrailingZeros(h));
}
}
static record Grid(byte[] g, long lo, long hi) {
@@ -291,10 +295,6 @@ public record SwedishGenerator(Rng rng, int[] stack) {
boolean notClue(int index) { return ((index & 64) == 0) ? ((lo >>> index) & 1L) == X : ((hi >>> (index & 63)) & 1L) == X; }
int clueCount() { return Long.bitCount(lo) + Long.bitCount(hi); }
void forEachSlot(SlotVisitor visitor) {
for (var l = lo; l != X; l &= l - 1) processSlot(this, visitor, Long.numberOfTrailingZeros(l));
for (var h = hi; h != X; h &= h - 1) processSlot(this, visitor, 64 | Long.numberOfTrailingZeros(h));
}
void undoPlace(long maskLo, long maskHi) {
for (long b = maskLo; b != 0; b &= b - 1) clearletter(Long.numberOfTrailingZeros(b));
for (long b = maskHi; b != 0; b &= b - 1) clearletter(64 | Long.numberOfTrailingZeros(b));
@@ -401,7 +401,7 @@ public record SwedishGenerator(Rng rng, int[] stack) {
public static int packSlotDir(int idx, int d) { return (idx << BIT_FOR_DIR) | d; }
}
private static void processSlot(Grid grid, SlotVisitor visitor, int idx) {
private static void processSlot(Clues grid, SlotVisitor visitor, int idx) {
int key = Slot.packSlotDir(idx, grid.digitAt(idx)); // 0..3
long rayLo = PATH_LO[key];
@@ -443,7 +443,7 @@ public record SwedishGenerator(Rng rng, int[] stack) {
//if ((rayLo | rayHi) == 0L) throw new RuntimeException()
}
static Slot[] extractSlots(Grid grid) {
static Slot[] extractSlots(Clues grid) {
var slots = new Slot[grid.clueCount()];
int[] N = new int[]{ 0 };
grid.forEachSlot((key, lo, hi) -> slots[N[0]++] = Slot.from(key, lo, hi));
@@ -910,7 +910,7 @@ public record SwedishGenerator(Rng rng, int[] stack) {
for (int i = 0; i < slots.length; i++) slotScores[i] = slotScore(count, slots[i]);
}
public static FillResult fillMask(Rng rng, Grid mask, DictEntry[] dictIndex) {
public static FillResult fillMask(Rng rng, Slot[] slots, Grid mask, DictEntry[] dictIndex) {
val multiThreaded = Thread.currentThread().getName().contains("pool");
val NO_LOG = (!Main.VERBOSE || multiThreaded);
val grid = mask;
@@ -919,7 +919,6 @@ public record SwedishGenerator(Rng rng, int[] stack) {
val bitset = new long[2500];
val undo = new long[64];
val slots = extractSlots(grid);
val TOTAL = slots.length;
val slotScores = new int[TOTAL];

View File

@@ -2,6 +2,7 @@ package puzzle;
import lombok.val;
import org.junit.jupiter.api.Test;
import puzzle.Export.Clued;
import puzzle.Export.Gridded;
import puzzle.Export.Placed;
import puzzle.Export.Rewards;
@@ -27,7 +28,7 @@ public class ExportFormatTest {
@Test
void testExportFormatFromFilled() {
var swe = new SwedishGenerator(new Rng(0), new int[STACK_SIZE]);
var swe = new SwedishGenerator(new Rng(0), new int[STACK_SIZE]);
val clues = Clues.createEmpty();
// Place a RIGHT clue at (0,0)
@@ -35,8 +36,7 @@ public class ExportFormatTest {
// 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.setClue(Grid.offset(0, 5), CLUE_LEFT);
var grid = clues.toGrid();
var grid = clues.toGrid();
var clueMap = new long[300];
// key = (cellIndex << 2) | (direction)
@@ -48,10 +48,9 @@ public class ExportFormatTest {
grid.setLetter(Grid.offset(0, 2), (byte) 'E');
grid.setLetter(Grid.offset(0, 3), (byte) 'S');
grid.setLetter(Grid.offset(0, 4), (byte) 'T');
var fillResult = new FillResult(true, new Gridded(grid), clueMap, new FillStats(0, 0, 0, 0));
var puzzleResult = new PuzzleResult(swe, null, null, fillResult);
var puzzleResult = new PuzzleResult(swe, null, new Clued(clues), fillResult);
var rewards = new Rewards(10, 5, 1);
var exported = puzzleResult.exportFormatFromFilled(2, rewards);
@@ -90,8 +89,9 @@ public class ExportFormatTest {
void testExportFormatEmpty() {
var swe = new SwedishGenerator(new Rng(0), new int[STACK_SIZE]);
var grid = Grid.createEmpty();
val clues = Clues.createEmpty();
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 puzzleResult = new PuzzleResult(swe, null, new Clued(clues), fillResult);
var exported = puzzleResult.exportFormatFromFilled(1, new Rewards(0, 0, 0));

View File

@@ -40,7 +40,7 @@ public class MainTest {
grid.setLetter(OFF_0_1, LETTER_A);
grid.setLetter(OFF_0_2, LETTER_B);
var slots = extractSlots(grid);
var slots = extractSlots(clues);
assertEquals(1, slots.length);
var s = slots[0];
assertEquals(8, s.length());
@@ -64,10 +64,8 @@ public class MainTest {
void testForEachSlot() {
var clues = Clues.createEmpty();
clues.setClue(OFF_0_0, CLUE_RIGHT);
var grid = clues.toGrid();
var count = new AtomicInteger(0);
grid.forEachSlot((key, lo, hi) -> {
clues.forEachSlot((key, lo, hi) -> {
count.incrementAndGet();
assertEquals(8, Long.bitCount(lo) + Long.bitCount(hi));
assertEquals(0, Grid.r(Long.numberOfTrailingZeros(lo)));

View File

@@ -258,7 +258,7 @@ public class SwedishGeneratorTest {
var grid = clues.toGrid();
var slots = extractSlots(grid);
var slots = extractSlots(clues);
assertEquals(1, slots.length);
var s = slots[0];