introduce bitloops
This commit is contained in:
@@ -58,7 +58,11 @@ public record Export() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
record Gridded(@Delegate Grid grid) {
|
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) {
|
public static IntStream walk(byte base, long lo, long hi) {
|
||||||
if (Slot.increasing(base)) {
|
if (Slot.increasing(base)) {
|
||||||
return IntStream.concat(
|
return IntStream.concat(
|
||||||
@@ -119,7 +123,7 @@ public record Export() {
|
|||||||
var offset = Grid.offset(r, c);
|
var offset = Grid.offset(r, c);
|
||||||
if (clues.isClue(offset))
|
if (clues.isClue(offset))
|
||||||
sb.append((char) (48 | clues.digitAt(offset)));
|
sb.append((char) (48 | clues.digitAt(offset)));
|
||||||
else if (grid.lisLetterAt(offset))
|
else if (lisLetterAt(offset))
|
||||||
sb.append((char) (64 | grid.letter32At(offset)));
|
sb.append((char) (64 | grid.letter32At(offset)));
|
||||||
else
|
else
|
||||||
sb.append(' ');
|
sb.append(' ');
|
||||||
@@ -144,7 +148,7 @@ public record Export() {
|
|||||||
var offset = Grid.offset(r, c);
|
var offset = Grid.offset(r, c);
|
||||||
if (clues.isClue(offset)) {
|
if (clues.isClue(offset)) {
|
||||||
sb.append(clueChar.replace(new Cell(grid, clues, offset, clues.digitAt(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)));
|
sb.append(NOT_CLUE_NOT_LETTER_TO(grid.letter32At(offset)));
|
||||||
} else {
|
} else {
|
||||||
sb.append(emptyFallback);
|
sb.append(emptyFallback);
|
||||||
@@ -192,7 +196,6 @@ public record Export() {
|
|||||||
|
|
||||||
public record PuzzleResult(Clued mask, FillResult filled) {
|
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()); }
|
Placed extractPlacedFromSlot(Slot s, long lemma) { return new Placed(lemma, s.key(), s.walk().toArray()); }
|
||||||
public ExportedPuzzle exportFormatFromFilled(int difficulty, Rewards rewards) {
|
public ExportedPuzzle exportFormatFromFilled(int difficulty, Rewards rewards) {
|
||||||
var g = filled().grid();
|
var g = filled().grid();
|
||||||
@@ -236,7 +239,6 @@ public record Export() {
|
|||||||
var letterAt = new HashMap<Integer, Character>();
|
var letterAt = new HashMap<Integer, Character>();
|
||||||
for (var p : placed) {
|
for (var p : placed) {
|
||||||
for (var c : p.cells) {
|
for (var c : p.cells) {
|
||||||
if (!inBounds(c)) throw new RuntimeException();
|
|
||||||
if (mask.notClue(c) && g.lisLetterAt(c)) {
|
if (mask.notClue(c) && g.lisLetterAt(c)) {
|
||||||
letterAt.put(c, (char) (64 | g.letter32At(c)));
|
letterAt.put(c, (char) (64 | g.letter32At(c)));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -277,12 +277,6 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
|||||||
static int offset(int r, int c) { return r | (c << 3); }
|
static int offset(int r, int c) { return r | (c << 3); }
|
||||||
/// the pos will never target a clue
|
/// the pos will never target a clue
|
||||||
public byte letter32At(int pos) { return g[pos]; }
|
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 lisLetterAtLo(int pos) { return (lo & (1L << pos)) != X; }
|
||||||
public boolean lisLetterAtHi(int pos) { return (hi & (1L << (pos & 63))) != X; }
|
public boolean lisLetterAtHi(int pos) { return (hi & (1L << (pos & 63))) != X; }
|
||||||
void setLetterLo(int idx, byte ch) {
|
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 static boolean increasing(int dir) { return (dir & 2) == 0; }
|
||||||
public IntStream walk() { return Gridded.walk((byte) key, lo, hi); }
|
public IntStream walk() { return Gridded.walk((byte) key, lo, hi); }
|
||||||
public static boolean horiz(int d) { return (d & 1) != 0; }
|
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) {
|
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 rayLo = PATH_LO[key];
|
||||||
long rayHi = PATH_HI[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 clueIdx = Long.numberOfTrailingZeros(lsb);
|
||||||
int v = (grid.vlo & lsb) != 0 ? 1 : 0;
|
int v = (grid.vlo & lsb) != 0 ? 1 : 0;
|
||||||
int r = (grid.rlo & 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 rLo = PATH_LO[key], rHi = PATH_HI[key];
|
||||||
long hLo = rLo & lo_cl, hHi = rHi & hi_cl;
|
long hLo = rLo & lo_cl, hHi = rHi & hi_cl;
|
||||||
if (Slot.increasing(key)) {
|
if (Slot.increasing(key)) {
|
||||||
@@ -488,7 +482,7 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
|||||||
int clueIdx = Long.numberOfTrailingZeros(lsb);
|
int clueIdx = Long.numberOfTrailingZeros(lsb);
|
||||||
int v = (grid.vhi & lsb) != 0 ? 1 : 0;
|
int v = (grid.vhi & lsb) != 0 ? 1 : 0;
|
||||||
int r = (grid.rhi & 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 rLo = PATH_LO[key], rHi = PATH_HI[key];
|
||||||
long hLo = rLo & lo_cl, hHi = rHi & hi_cl;
|
long hLo = rLo & lo_cl, hHi = rHi & hi_cl;
|
||||||
if (Slot.increasing(key)) {
|
if (Slot.increasing(key)) {
|
||||||
@@ -612,7 +606,7 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
|||||||
idx = rng.randint(0, SIZE_MIN_1);
|
idx = rng.randint(0, SIZE_MIN_1);
|
||||||
if (g.isClue(idx)) continue;
|
if (g.isClue(idx)) continue;
|
||||||
var d_idx = rng.randint2bitByte();
|
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);
|
g.setClue(idx, d_idx);
|
||||||
placed++;
|
placed++;
|
||||||
}
|
}
|
||||||
@@ -626,7 +620,7 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
|||||||
ri = bytes[rng.randint(0, 624)];
|
ri = bytes[rng.randint(0, 624)];
|
||||||
if (!c.clueless(ri)) {
|
if (!c.clueless(ri)) {
|
||||||
var d_idx = rng.randint2bitByte();
|
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;
|
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));
|
for (var hi = out.hi; hi != X; hi &= hi - 1L) clearClues(out, 64 | Long.numberOfTrailingZeros(hi));
|
||||||
return out;
|
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) {
|
Clues hillclimb(Clues start, int limit) {
|
||||||
var best = start;
|
var best = start;
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ public class SwedishGeneratorTest {
|
|||||||
grid.setLetterLo(0, LETTER_A);
|
grid.setLetterLo(0, LETTER_A);
|
||||||
grid.setLetterLo(1, LETTER_B);
|
grid.setLetterLo(1, LETTER_B);
|
||||||
grid.setLetterLo(2, LETTER_C);
|
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);
|
var pattern = patternForSlot(grid, key, 7L, 0L);
|
||||||
assertEquals(1L | (28L << 8) | (55L << 16), pattern);
|
assertEquals(1L | (28L << 8) | (55L << 16), pattern);
|
||||||
}
|
}
|
||||||
@@ -92,7 +92,7 @@ public class SwedishGeneratorTest {
|
|||||||
var grid = createEmpty();
|
var grid = createEmpty();
|
||||||
grid.setLetterLo(OFF_0_0, LETTER_A);
|
grid.setLetterLo(OFF_0_0, LETTER_A);
|
||||||
grid.setLetterLo(2, LETTER_C);
|
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);
|
var pattern = patternForSlot(grid, key, 7L, 0L);
|
||||||
assertEquals(1L | (0L) | (55L << 16), pattern);
|
assertEquals(1L | (0L) | (55L << 16), pattern);
|
||||||
}
|
}
|
||||||
@@ -100,7 +100,7 @@ public class SwedishGeneratorTest {
|
|||||||
@Test
|
@Test
|
||||||
void testPatternForSlotAllDashes() {
|
void testPatternForSlotAllDashes() {
|
||||||
var grid = createEmpty();
|
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);
|
var pattern = patternForSlot(grid, key, 7L, 0L);
|
||||||
assertEquals(0L, pattern);
|
assertEquals(0L, pattern);
|
||||||
}
|
}
|
||||||
@@ -109,7 +109,7 @@ public class SwedishGeneratorTest {
|
|||||||
void testPatternForSlotSingleLetter() {
|
void testPatternForSlotSingleLetter() {
|
||||||
var grid = createEmpty();
|
var grid = createEmpty();
|
||||||
grid.setLetterLo(OFF_0_0, LETTER_A);
|
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);
|
var pattern = patternForSlot(grid, key, 7L, 0L);
|
||||||
assertEquals(1L, pattern);
|
assertEquals(1L, pattern);
|
||||||
}
|
}
|
||||||
@@ -164,12 +164,6 @@ public class SwedishGeneratorTest {
|
|||||||
var entry3 = dict.index()[3];
|
var entry3 = dict.index()[3];
|
||||||
assertEquals(1, entry3.words().length);
|
assertEquals(1, entry3.words().length);
|
||||||
assertEquals(Lemma.pack("AXE".getBytes(StandardCharsets.US_ASCII)), Lemma.unpackLetters(entry3.words()[0]));
|
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
|
@Test
|
||||||
@@ -178,7 +172,7 @@ public class SwedishGeneratorTest {
|
|||||||
// key = (r << 8) | (c << 4) | d
|
// key = (r << 8) | (c << 4) | d
|
||||||
var offset = OFF_2_3;
|
var offset = OFF_2_3;
|
||||||
System.out.println("[DEBUG_LOG] Grid.offset(2, 3) = " + offset);
|
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);
|
System.out.println("[DEBUG_LOG] key = " + key);
|
||||||
long lo = 0;
|
long lo = 0;
|
||||||
// pos 0: (2, 5)
|
// pos 0: (2, 5)
|
||||||
@@ -203,54 +197,6 @@ public class SwedishGeneratorTest {
|
|||||||
assertTrue(Slot.horiz(CLUE_RIGHT)); // right
|
assertTrue(Slot.horiz(CLUE_RIGHT)); // right
|
||||||
assertFalse(Slot.horiz(CLUE_DOWN)); // down
|
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) {
|
static long packPattern(String s) {
|
||||||
long p = 0;
|
long p = 0;
|
||||||
@@ -258,7 +204,7 @@ public class SwedishGeneratorTest {
|
|||||||
for (var i = 0; i < b.length; i++) {
|
for (var i = 0; i < b.length; i++) {
|
||||||
var val = b[i] & 31;
|
var val = b[i] & 31;
|
||||||
if (val != 0) {
|
if (val != 0) {
|
||||||
p |= (long) (i * 26 + val) << (i << 3);
|
p |= (i * 26L + val) << (i << 3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return p;
|
return p;
|
||||||
@@ -326,7 +272,7 @@ public class SwedishGeneratorTest {
|
|||||||
void testPlaceWord() {
|
void testPlaceWord() {
|
||||||
var grid = createEmpty();
|
var grid = createEmpty();
|
||||||
// Slot at OFF_0_0 length 3, horizontal (right)
|
// 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);
|
var lo = (1L << OFF_0_0) | (1L << OFF_0_1) | (1L << OFF_0_2);
|
||||||
val hi = 0L;
|
val hi = 0L;
|
||||||
var w1 = ABC;
|
var w1 = ABC;
|
||||||
@@ -362,7 +308,7 @@ public class SwedishGeneratorTest {
|
|||||||
void testBacktrackingHelpers() {
|
void testBacktrackingHelpers() {
|
||||||
var grid = createEmpty();
|
var grid = createEmpty();
|
||||||
// Slot at 0,1 length 2
|
// 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 lo = (1L << OFF_0_1) | (1L << OFF_0_2);
|
||||||
var w = AZ;
|
var w = AZ;
|
||||||
val low = grid.lo;
|
val low = grid.lo;
|
||||||
@@ -387,8 +333,8 @@ public class SwedishGeneratorTest {
|
|||||||
assertTrue(Slot.increasing(CLUE_DOWN)); // Down
|
assertTrue(Slot.increasing(CLUE_DOWN)); // Down
|
||||||
assertFalse(Slot.increasing(CLUE_UP)); // Up
|
assertFalse(Slot.increasing(CLUE_UP)); // Up
|
||||||
|
|
||||||
assertTrue(Slot.increasing((0) | CLUE_RIGHT));
|
assertTrue(Slot.increasing(Slot.packSlotKey(0, CLUE_RIGHT)));
|
||||||
assertFalse(Slot.increasing((0) | CLUE_LEFT));
|
assertFalse(Slot.increasing(Slot.packSlotKey(0, CLUE_LEFT)));
|
||||||
|
|
||||||
// 2. Test slotScore
|
// 2. Test slotScore
|
||||||
val counts = new byte[SIZE];
|
val counts = new byte[SIZE];
|
||||||
|
|||||||
Reference in New Issue
Block a user