introduce bitloops

This commit is contained in:
mike
2026-01-14 13:43:02 +01:00
parent b1f54c2cae
commit b29831859b
3 changed files with 24 additions and 82 deletions

View File

@@ -58,7 +58,11 @@ public record Export() {
}
record Gridded(@Delegate Grid grid) {
public boolean lisLetterAt(int pos) {
if ((pos & 64) == 0)
return lisLetterAtLo(pos);
return lisLetterAtHi(pos);
}
public static IntStream walk(byte base, long lo, long hi) {
if (Slot.increasing(base)) {
return IntStream.concat(
@@ -119,7 +123,7 @@ public record Export() {
var offset = Grid.offset(r, c);
if (clues.isClue(offset))
sb.append((char) (48 | clues.digitAt(offset)));
else if (grid.lisLetterAt(offset))
else if (lisLetterAt(offset))
sb.append((char) (64 | grid.letter32At(offset)));
else
sb.append(' ');
@@ -144,7 +148,7 @@ public record Export() {
var offset = Grid.offset(r, c);
if (clues.isClue(offset)) {
sb.append(clueChar.replace(new Cell(grid, clues, offset, clues.digitAt(offset))));
} else if (grid.lisLetterAt(offset)) {
} else if (lisLetterAt(offset)) {
sb.append(NOT_CLUE_NOT_LETTER_TO(grid.letter32At(offset)));
} else {
sb.append(emptyFallback);
@@ -192,7 +196,6 @@ public record Export() {
public record PuzzleResult(Clued mask, FillResult filled) {
boolean inBounds(int idx) { return idx >= 0 && idx < SwedishGenerator.SIZE; }
Placed extractPlacedFromSlot(Slot s, long lemma) { return new Placed(lemma, s.key(), s.walk().toArray()); }
public ExportedPuzzle exportFormatFromFilled(int difficulty, Rewards rewards) {
var g = filled().grid();
@@ -236,7 +239,6 @@ public record Export() {
var letterAt = new HashMap<Integer, Character>();
for (var p : placed) {
for (var c : p.cells) {
if (!inBounds(c)) throw new RuntimeException();
if (mask.notClue(c) && g.lisLetterAt(c)) {
letterAt.put(c, (char) (64 | g.letter32At(c)));
}

View File

@@ -277,12 +277,6 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
static int offset(int r, int c) { return r | (c << 3); }
/// the pos will never target a clue
public byte letter32At(int pos) { return g[pos]; }
public boolean lisLetterAt(int pos) {
if ((pos & 64) == 0)
return lisLetterAtLo(pos);
return lisLetterAtHi(pos);
}
public boolean lisLetterAtLo(int pos) { return (lo & (1L << pos)) != X; }
public boolean lisLetterAtHi(int pos) { return (hi & (1L << (pos & 63))) != X; }
void setLetterLo(int idx, byte ch) {
@@ -387,11 +381,11 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
public static boolean increasing(int dir) { return (dir & 2) == 0; }
public IntStream walk() { return Gridded.walk((byte) key, lo, hi); }
public static boolean horiz(int d) { return (d & 1) != 0; }
public static int packSlotDir(int idx, int d) { return (idx << BIT_FOR_DIR) | d; }
public static int packSlotKey(int idx, int d) { return (idx << BIT_FOR_DIR) | d; }
}
private static void processSlot(Clues grid, SlotVisitor visitor, int idx) {
int key = Slot.packSlotDir(idx, grid.digitAt(idx)); // 0..3
int key = Slot.packSlotKey(idx, grid.digitAt(idx)); // 0..3
long rayLo = PATH_LO[key];
long rayHi = PATH_HI[key];
@@ -451,7 +445,7 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
int clueIdx = Long.numberOfTrailingZeros(lsb);
int v = (grid.vlo & lsb) != 0 ? 1 : 0;
int r = (grid.rlo & lsb) != 0 ? 1 : 0;
int key = Slot.packSlotDir(clueIdx, (r << 1) | v);
int key = Slot.packSlotKey(clueIdx, (r << 1) | v);
long rLo = PATH_LO[key], rHi = PATH_HI[key];
long hLo = rLo & lo_cl, hHi = rHi & hi_cl;
if (Slot.increasing(key)) {
@@ -488,7 +482,7 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
int clueIdx = Long.numberOfTrailingZeros(lsb);
int v = (grid.vhi & lsb) != 0 ? 1 : 0;
int r = (grid.rhi & lsb) != 0 ? 1 : 0;
int key = Slot.packSlotDir(64 | clueIdx, (r << 1) | v);
int key = Slot.packSlotKey(64 | clueIdx, (r << 1) | v);
long rLo = PATH_LO[key], rHi = PATH_HI[key];
long hLo = rLo & lo_cl, hHi = rHi & hi_cl;
if (Slot.increasing(key)) {
@@ -612,7 +606,7 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
idx = rng.randint(0, SIZE_MIN_1);
if (g.isClue(idx)) continue;
var d_idx = rng.randint2bitByte();
if (g.hasRoomForClue(OFFSETS_D_IDX[Slot.packSlotDir(idx, d_idx)])) {
if (g.hasRoomForClue(OFFSETS_D_IDX[Slot.packSlotKey(idx, d_idx)])) {
g.setClue(idx, d_idx);
placed++;
}
@@ -626,7 +620,7 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
ri = bytes[rng.randint(0, 624)];
if (!c.clueless(ri)) {
var d_idx = rng.randint2bitByte();
if (c.hasRoomForClue(OFFSETS_D_IDX[Slot.packSlotDir(ri, d_idx)])) c.setClue(ri, d_idx);
if (c.hasRoomForClue(OFFSETS_D_IDX[Slot.packSlotKey(ri, d_idx)])) c.setClue(ri, d_idx);
}
}
return c;
@@ -657,7 +651,7 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
for (var hi = out.hi; hi != X; hi &= hi - 1L) clearClues(out, 64 | Long.numberOfTrailingZeros(hi));
return out;
}
public static void clearClues(Clues out, int idx) { if (!out.hasRoomForClue(OFFSETS_D_IDX[Slot.packSlotDir(idx, out.digitAt(idx))])) out.clearClue(idx); }
public static void clearClues(Clues out, int idx) { if (!out.hasRoomForClue(OFFSETS_D_IDX[Slot.packSlotKey(idx, out.digitAt(idx))])) out.clearClue(idx); }
Clues hillclimb(Clues start, int limit) {
var best = start;

View File

@@ -82,7 +82,7 @@ public class SwedishGeneratorTest {
grid.setLetterLo(0, LETTER_A);
grid.setLetterLo(1, LETTER_B);
grid.setLetterLo(2, LETTER_C);
var key = 18 << Slot.BIT_FOR_DIR | (CLUE_RIGHT);
var key = Slot.packSlotKey(18, CLUE_RIGHT);
var pattern = patternForSlot(grid, key, 7L, 0L);
assertEquals(1L | (28L << 8) | (55L << 16), pattern);
}
@@ -92,7 +92,7 @@ public class SwedishGeneratorTest {
var grid = createEmpty();
grid.setLetterLo(OFF_0_0, LETTER_A);
grid.setLetterLo(2, LETTER_C);
var key = 1 << Slot.BIT_FOR_DIR | (CLUE_RIGHT);
var key = Slot.packSlotKey(1, CLUE_RIGHT);
var pattern = patternForSlot(grid, key, 7L, 0L);
assertEquals(1L | (0L) | (55L << 16), pattern);
}
@@ -100,7 +100,7 @@ public class SwedishGeneratorTest {
@Test
void testPatternForSlotAllDashes() {
var grid = createEmpty();
var key = 1 << Slot.BIT_FOR_DIR | (CLUE_RIGHT);
var key = Slot.packSlotKey(1 << Slot.BIT_FOR_DIR, CLUE_RIGHT);
var pattern = patternForSlot(grid, key, 7L, 0L);
assertEquals(0L, pattern);
}
@@ -109,7 +109,7 @@ public class SwedishGeneratorTest {
void testPatternForSlotSingleLetter() {
var grid = createEmpty();
grid.setLetterLo(OFF_0_0, LETTER_A);
var key = 1 << Slot.BIT_FOR_DIR | (CLUE_RIGHT);
var key = Slot.packSlotKey(1, CLUE_RIGHT);
var pattern = patternForSlot(grid, key, 7L, 0L);
assertEquals(1L, pattern);
}
@@ -164,12 +164,6 @@ public class SwedishGeneratorTest {
var entry3 = dict.index()[3];
assertEquals(1, entry3.words().length);
assertEquals(Lemma.pack("AXE".getBytes(StandardCharsets.US_ASCII)), Lemma.unpackLetters(entry3.words()[0]));
// Check pos indexing
// AXE: A at 0, X at 1, E at 2
/* assertTrue(entry3.pos()[0][0].size() > 0);
assertTrue(entry3.pos()[1]['X' - 'A'].size() > 0);
assertTrue(entry3.pos()[2]['E' - 'A'].size() > 0);*/
}
@Test
@@ -178,7 +172,7 @@ public class SwedishGeneratorTest {
// key = (r << 8) | (c << 4) | d
var offset = OFF_2_3;
System.out.println("[DEBUG_LOG] Grid.offset(2, 3) = " + offset);
var key = (offset << Slot.BIT_FOR_DIR) | (CLUE_DOWN);
var key = Slot.packSlotKey(offset, CLUE_DOWN);
System.out.println("[DEBUG_LOG] key = " + key);
long lo = 0;
// pos 0: (2, 5)
@@ -203,54 +197,6 @@ public class SwedishGeneratorTest {
assertTrue(Slot.horiz(CLUE_RIGHT)); // right
assertFalse(Slot.horiz(CLUE_DOWN)); // down
}
static int intersectSorted(int[] a, int aLen, int[] b, int bLen, int[] out) {
if (aLen == 0 || bLen == 0) return 0;
if (aLen < bLen >>> 4) {
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) {
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;
}
int i = 0, j = 0, k = 0, x, y;
while (i < aLen && j < bLen) {
x = a[i];
y = b[j];
if (x == y) {
out[k++] = x;
i++;
j++;
} else if (x < y) i++;
else j++;
}
return k;
}
@Test
void testIntersectSorted() {
var buff = new int[10];
var a = new int[]{ 1, 3, 5, 7, 9 };
var b = new int[]{ 2, 3, 6, 7, 10 };
var count = intersectSorted(a, a.length, b, b.length, buff);
assertEquals(2, count);
assertEquals(3, buff[0]);
assertEquals(7, buff[1]);
var c = new int[]{ 1, 2, 3 };
var d = new int[]{ 4, 5, 6 };
count = intersectSorted(c, c.length, d, d.length, buff);
assertEquals(0, count);
}
static long packPattern(String s) {
long p = 0;
@@ -258,7 +204,7 @@ public class SwedishGeneratorTest {
for (var i = 0; i < b.length; i++) {
var val = b[i] & 31;
if (val != 0) {
p |= (long) (i * 26 + val) << (i << 3);
p |= (i * 26L + val) << (i << 3);
}
}
return p;
@@ -326,7 +272,7 @@ public class SwedishGeneratorTest {
void testPlaceWord() {
var grid = createEmpty();
// Slot at OFF_0_0 length 3, horizontal (right)
var key = (OFF_0_0 << Slot.BIT_FOR_DIR) | (CLUE_RIGHT);
var key = Slot.packSlotKey(0, CLUE_RIGHT);
var lo = (1L << OFF_0_0) | (1L << OFF_0_1) | (1L << OFF_0_2);
val hi = 0L;
var w1 = ABC;
@@ -362,7 +308,7 @@ public class SwedishGeneratorTest {
void testBacktrackingHelpers() {
var grid = createEmpty();
// Slot at 0,1 length 2
var key = (OFF_0_0 << Slot.BIT_FOR_DIR) | (CLUE_RIGHT);
var key = Slot.packSlotKey(0, CLUE_RIGHT);
var lo = (1L << OFF_0_1) | (1L << OFF_0_2);
var w = AZ;
val low = grid.lo;
@@ -387,8 +333,8 @@ public class SwedishGeneratorTest {
assertTrue(Slot.increasing(CLUE_DOWN)); // Down
assertFalse(Slot.increasing(CLUE_UP)); // Up
assertTrue(Slot.increasing((0) | CLUE_RIGHT));
assertFalse(Slot.increasing((0) | CLUE_LEFT));
assertTrue(Slot.increasing(Slot.packSlotKey(0, CLUE_RIGHT)));
assertFalse(Slot.increasing(Slot.packSlotKey(0, CLUE_LEFT)));
// 2. Test slotScore
val counts = new byte[SIZE];