introduce bitloops
This commit is contained in:
@@ -120,7 +120,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.lisLetterAtLo(offset))
|
else if (grid.lisLetterAt(offset))
|
||||||
sb.append((char) (64 | grid.letter32At(offset)));
|
sb.append((char) (64 | grid.letter32At(offset)));
|
||||||
else
|
else
|
||||||
sb.append(' ');
|
sb.append(' ');
|
||||||
|
|||||||
@@ -303,30 +303,6 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
|||||||
|
|
||||||
g[idx] = ch;
|
g[idx] = ch;
|
||||||
}
|
}
|
||||||
void setLetter(int idx, byte ch) {
|
|
||||||
if ((idx & 64) == 0)
|
|
||||||
setLetterLo(idx, ch);
|
|
||||||
else
|
|
||||||
setLetterHi(idx, ch);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void clearletterLo(int idx) {
|
|
||||||
g[idx] = DASH;
|
|
||||||
|
|
||||||
lo &= ~(1L << idx);
|
|
||||||
}
|
|
||||||
private void clearletterHi(int idx) {
|
|
||||||
g[idx] = DASH;
|
|
||||||
|
|
||||||
hi &= ~(1L << (idx & 63));
|
|
||||||
}
|
|
||||||
void undoPlace(long maskLo, long maskHi) {
|
|
||||||
lo &= ~maskLo;
|
|
||||||
hi &= ~maskHi;
|
|
||||||
|
|
||||||
/*for (long b = maskLo; b != 0; b &= b - 1) clearletterLo(Long.numberOfTrailingZeros(b));
|
|
||||||
for (long b = maskHi; b != 0; b &= b - 1) clearletterHi(64 | Long.numberOfTrailingZeros(b));*/
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static record DictEntry(long[] words, long[][] posBitsets, int length, int numlong) { }
|
static record DictEntry(long[] words, long[][] posBitsets, int length, int numlong) { }
|
||||||
@@ -799,7 +775,7 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
|||||||
for (long b = s.hi; b != 0; b &= b - 1) cross += (count[64 | Long.numberOfTrailingZeros(b)] - 1);
|
for (long b = s.hi; b != 0; b &= b - 1) cross += (count[64 | Long.numberOfTrailingZeros(b)] - 1);
|
||||||
return cross * 10 + s.length();
|
return cross * 10 + s.length();
|
||||||
}
|
}
|
||||||
static boolean placeWord(Grid grid, Slot s, long w, long[] undoBuffer, int offset) {
|
static boolean placeWord(Grid grid, Slot s, long w) {
|
||||||
if (s.increasing()) {
|
if (s.increasing()) {
|
||||||
for (long b = s.lo & grid.lo; b != 0; b &= b - 1) {
|
for (long b = s.lo & grid.lo; b != 0; b &= b - 1) {
|
||||||
int idx = Long.numberOfTrailingZeros(b);
|
int idx = Long.numberOfTrailingZeros(b);
|
||||||
@@ -824,8 +800,6 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
|||||||
grid.lo |= maskLo;
|
grid.lo |= maskLo;
|
||||||
grid.hi |= maskHi;
|
grid.hi |= maskHi;
|
||||||
}
|
}
|
||||||
undoBuffer[offset << 1] = maskLo;
|
|
||||||
undoBuffer[(offset << 1) | 1] = maskHi;
|
|
||||||
} else {
|
} else {
|
||||||
int bcHi = Long.bitCount(s.hi);
|
int bcHi = Long.bitCount(s.hi);
|
||||||
for (long b = s.hi & grid.hi; b != 0; b &= b - 1) {
|
for (long b = s.hi & grid.hi; b != 0; b &= b - 1) {
|
||||||
@@ -850,8 +824,6 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
|||||||
grid.lo |= maskLo;
|
grid.lo |= maskLo;
|
||||||
grid.hi |= maskHi;
|
grid.hi |= maskHi;
|
||||||
}
|
}
|
||||||
undoBuffer[offset << 1] = maskLo;
|
|
||||||
undoBuffer[(offset << 1) | 1] = maskHi;
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -932,7 +904,6 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
|||||||
val used = new Bit1029();
|
val used = new Bit1029();
|
||||||
val assigned = new long[CLUE_INDEX_MAX_SIZE];
|
val assigned = new long[CLUE_INDEX_MAX_SIZE];
|
||||||
val bitset = new long[2500];
|
val bitset = new long[2500];
|
||||||
val undo = new long[64];
|
|
||||||
|
|
||||||
val TOTAL = slots.length;
|
val TOTAL = slots.length;
|
||||||
val slotScores = new int[TOTAL];
|
val slotScores = new int[TOTAL];
|
||||||
@@ -1042,8 +1013,9 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
|||||||
var w = entry.words[idx];
|
var w = entry.words[idx];
|
||||||
var lemIdx = Lemma.unpackIndex(w);
|
var lemIdx = Lemma.unpackIndex(w);
|
||||||
if (used.get(lemIdx)) continue;
|
if (used.get(lemIdx)) continue;
|
||||||
|
val low = grid.lo;
|
||||||
if (!placeWord(grid, s, w, undo, depth)) continue;
|
val top = grid.hi;
|
||||||
|
if (!placeWord(grid, s, w)) continue;
|
||||||
|
|
||||||
used.set(lemIdx);
|
used.set(lemIdx);
|
||||||
assigned[k] = w;
|
assigned[k] = w;
|
||||||
@@ -1052,7 +1024,9 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
|||||||
|
|
||||||
assigned[k] = X;
|
assigned[k] = X;
|
||||||
used.clear(lemIdx);
|
used.clear(lemIdx);
|
||||||
grid.undoPlace(undo[depth << 1], undo[(depth << 1) | 1]);
|
//grid.undoPlace(undo[depth << 1], undo[(depth << 1) | 1]);
|
||||||
|
grid.lo = low;
|
||||||
|
grid.hi = top;
|
||||||
}
|
}
|
||||||
backtracks++;
|
backtracks++;
|
||||||
return false;
|
return false;
|
||||||
@@ -1067,8 +1041,9 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
|||||||
var w = entry.words[idxInArray];
|
var w = entry.words[idxInArray];
|
||||||
var lemIdx = Lemma.unpackIndex(w);
|
var lemIdx = Lemma.unpackIndex(w);
|
||||||
if (used.get(lemIdx)) continue;
|
if (used.get(lemIdx)) continue;
|
||||||
|
val low = grid.lo;
|
||||||
if (!placeWord(grid, s, w, undo, depth)) continue;
|
val top = grid.hi;
|
||||||
|
if (!placeWord(grid, s, w)) continue;
|
||||||
|
|
||||||
used.set(lemIdx);
|
used.set(lemIdx);
|
||||||
assigned[k] = w;
|
assigned[k] = w;
|
||||||
@@ -1077,7 +1052,9 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
|||||||
|
|
||||||
assigned[k] = X;
|
assigned[k] = X;
|
||||||
used.clear(lemIdx);
|
used.clear(lemIdx);
|
||||||
grid.undoPlace(undo[depth << 1], undo[(depth << 1) | 1]);
|
grid.lo = low;
|
||||||
|
grid.hi = top;
|
||||||
|
//grid.undoPlace(undo[depth << 1], undo[(depth << 1) | 1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
backtracks++;
|
backtracks++;
|
||||||
|
|||||||
@@ -45,10 +45,10 @@ public class ExportFormatTest {
|
|||||||
clueMap[key] = SwedishGeneratorTest.TEST;
|
clueMap[key] = SwedishGeneratorTest.TEST;
|
||||||
|
|
||||||
// Manually fill the grid letters for "TEST" at (0,1), (0,2), (0,3), (0,4)
|
// Manually fill the grid letters for "TEST" at (0,1), (0,2), (0,3), (0,4)
|
||||||
grid.setLetter(Grid.offset(0, 1), LETTER_T);
|
grid.setLetterLo(OFF_0_1, LETTER_T);
|
||||||
grid.setLetter(Grid.offset(0, 2), LETTER_E);
|
grid.setLetterLo(OFF_0_2, LETTER_E);
|
||||||
grid.setLetter(Grid.offset(0, 3), LETTER_S);
|
grid.setLetterLo(OFF_0_3, LETTER_S);
|
||||||
grid.setLetter(Grid.offset(0, 4), LETTER_T);
|
grid.setLetterLo(OFF_0_4, LETTER_T);
|
||||||
|
|
||||||
var fillResult = new FillResult(true, new Gridded(grid), clueMap, new FillStats(0, 0, 0, 0));
|
var fillResult = new FillResult(true, new Gridded(grid), clueMap, new FillStats(0, 0, 0, 0));
|
||||||
var puzzleResult = new PuzzleResult(new Clued(clues), fillResult);
|
var puzzleResult = new PuzzleResult(new Clued(clues), fillResult);
|
||||||
|
|||||||
@@ -31,6 +31,8 @@ public class MainTest {
|
|||||||
static final int OFF_0_0 = Grid.offset(0, 0);
|
static final int OFF_0_0 = Grid.offset(0, 0);
|
||||||
static final int OFF_0_1 = Grid.offset(0, 1);
|
static final int OFF_0_1 = Grid.offset(0, 1);
|
||||||
static final int OFF_0_2 = Grid.offset(0, 2);
|
static final int OFF_0_2 = Grid.offset(0, 2);
|
||||||
|
static final int OFF_0_3 = Grid.offset(0, 3);
|
||||||
|
static final int OFF_0_4 = Grid.offset(0, 4);
|
||||||
static final int OFF_1_1 = Grid.offset(1, 1);
|
static final int OFF_1_1 = Grid.offset(1, 1);
|
||||||
static final int OFF_1_2 = Grid.offset(1, 2);
|
static final int OFF_1_2 = Grid.offset(1, 2);
|
||||||
static final int OFF_2_3 = Grid.offset(2, 3);
|
static final int OFF_2_3 = Grid.offset(2, 3);
|
||||||
@@ -50,8 +52,8 @@ public class MainTest {
|
|||||||
var clues = Clues.createEmpty();
|
var clues = Clues.createEmpty();
|
||||||
clues.setClue(OFF_0_0, CLUE_RIGHT);
|
clues.setClue(OFF_0_0, CLUE_RIGHT);
|
||||||
var grid = clues.toGrid();
|
var grid = clues.toGrid();
|
||||||
grid.setLetter(OFF_0_1, LETTER_A);
|
grid.setLetterLo(OFF_0_1, LETTER_A);
|
||||||
grid.setLetter(OFF_0_2, LETTER_B);
|
grid.setLetterLo(OFF_0_2, LETTER_B);
|
||||||
|
|
||||||
var slots = extractSlots(clues);
|
var slots = extractSlots(clues);
|
||||||
assertEquals(1, slots.length);
|
assertEquals(1, slots.length);
|
||||||
@@ -100,8 +102,8 @@ public class MainTest {
|
|||||||
var grid = clues.toGrid();
|
var grid = clues.toGrid();
|
||||||
|
|
||||||
// Test set/get
|
// Test set/get
|
||||||
grid.setLetter(OFF_0_0, LETTER_A);
|
grid.setLetterLo(OFF_0_0, LETTER_A);
|
||||||
grid.setLetter(OFF_2_3, LETTER_Z);
|
grid.setLetterLo(OFF_2_3, LETTER_Z);
|
||||||
|
|
||||||
Assertions.assertEquals(LETTER_A, grid.letter32At(OFF_0_0));
|
Assertions.assertEquals(LETTER_A, grid.letter32At(OFF_0_0));
|
||||||
Assertions.assertEquals(CLUE_UP, clues.digitAt(OFF_1_2));
|
Assertions.assertEquals(CLUE_UP, clues.digitAt(OFF_1_2));
|
||||||
|
|||||||
@@ -78,9 +78,9 @@ public class SwedishGeneratorTest {
|
|||||||
@Test
|
@Test
|
||||||
void testPatternForSlotAllLetters() {
|
void testPatternForSlotAllLetters() {
|
||||||
var grid = createEmpty();
|
var grid = createEmpty();
|
||||||
grid.setLetter(0, LETTER_A);
|
grid.setLetterLo(0, LETTER_A);
|
||||||
grid.setLetter(1, LETTER_B);
|
grid.setLetterLo(1, LETTER_B);
|
||||||
grid.setLetter(2, LETTER_C);
|
grid.setLetterLo(2, LETTER_C);
|
||||||
var slot = Slot.from(18 << Slot.BIT_FOR_DIR | (CLUE_RIGHT), 7L, 0L);
|
var slot = Slot.from(18 << Slot.BIT_FOR_DIR | (CLUE_RIGHT), 7L, 0L);
|
||||||
var pattern = patternForSlot(grid, slot);
|
var pattern = patternForSlot(grid, slot);
|
||||||
|
|
||||||
@@ -90,8 +90,8 @@ public class SwedishGeneratorTest {
|
|||||||
@Test
|
@Test
|
||||||
void testPatternForSlotMixed() {
|
void testPatternForSlotMixed() {
|
||||||
var grid = createEmpty();
|
var grid = createEmpty();
|
||||||
grid.setLetter(0, LETTER_A);
|
grid.setLetterLo(OFF_0_0, LETTER_A);
|
||||||
grid.setLetter(2, LETTER_C);
|
grid.setLetterLo(2, LETTER_C);
|
||||||
var slot = Slot.from(1 << Slot.BIT_FOR_DIR | (CLUE_RIGHT), 7L, 0L);
|
var slot = Slot.from(1 << Slot.BIT_FOR_DIR | (CLUE_RIGHT), 7L, 0L);
|
||||||
var pattern = patternForSlot(grid, slot);
|
var pattern = patternForSlot(grid, slot);
|
||||||
|
|
||||||
@@ -110,7 +110,7 @@ public class SwedishGeneratorTest {
|
|||||||
@Test
|
@Test
|
||||||
void testPatternForSlotSingleLetter() {
|
void testPatternForSlotSingleLetter() {
|
||||||
var grid = createEmpty();
|
var grid = createEmpty();
|
||||||
grid.setLetter(0, LETTER_A);
|
grid.setLetterLo(OFF_0_0, LETTER_A);
|
||||||
var slot = Slot.from(1 << Slot.BIT_FOR_DIR | (CLUE_RIGHT), 7L, 0L);
|
var slot = Slot.from(1 << Slot.BIT_FOR_DIR | (CLUE_RIGHT), 7L, 0L);
|
||||||
var pattern = patternForSlot(grid, slot);
|
var pattern = patternForSlot(grid, slot);
|
||||||
|
|
||||||
@@ -137,7 +137,7 @@ public class SwedishGeneratorTest {
|
|||||||
@Test
|
@Test
|
||||||
void testGrid() {
|
void testGrid() {
|
||||||
var grid = createEmpty();
|
var grid = createEmpty();
|
||||||
grid.setLetter(OFF_0_0, LETTER_A);
|
grid.setLetterLo(OFF_0_0, LETTER_A);
|
||||||
assertEquals(LETTER_A, grid.letter32At(OFF_0_0));
|
assertEquals(LETTER_A, grid.letter32At(OFF_0_0));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -334,22 +334,19 @@ public class SwedishGeneratorTest {
|
|||||||
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);
|
||||||
var s = Slot.from(key, lo, 0L);
|
var s = Slot.from(key, lo, 0L);
|
||||||
var w1 = ABC;
|
var w1 = ABC;
|
||||||
var undoBuffer = new long[10];
|
|
||||||
|
|
||||||
// 1. Successful placement in empty grid
|
// 1. Successful placement in empty grid
|
||||||
assertTrue(placeWord(grid, s, w1, undoBuffer, 0));
|
assertTrue(placeWord(grid, s, w1));
|
||||||
assertEquals(LETTER_A, grid.letter32At(OFF_0_0));
|
assertEquals(LETTER_A, grid.letter32At(OFF_0_0));
|
||||||
assertEquals(LETTER_B, grid.letter32At(OFF_0_1));
|
assertEquals(LETTER_B, grid.letter32At(OFF_0_1));
|
||||||
assertEquals(LETTER_C, grid.letter32At(OFF_0_2));
|
assertEquals(LETTER_C, grid.letter32At(OFF_0_2));
|
||||||
assertEquals(lo, undoBuffer[0]);
|
|
||||||
|
|
||||||
// 2. Successful placement with partial overlap (same characters)
|
// 2. Successful placement with partial overlap (same characters)
|
||||||
assertTrue(placeWord(grid, s, w1, undoBuffer, 1));
|
assertTrue(placeWord(grid, s, w1));
|
||||||
assertEquals(0L, undoBuffer[2]); // 0 new characters placed
|
|
||||||
|
|
||||||
// 3. Conflict: place "ABD" where "ABC" is
|
// 3. Conflict: place "ABD" where "ABC" is
|
||||||
var w2 = ABD;
|
var w2 = ABD;
|
||||||
assertFalse(placeWord(grid, s, w2, undoBuffer, 2));
|
assertFalse(placeWord(grid, s, w2));
|
||||||
// Verify grid is unchanged (still "ABC")
|
// Verify grid is unchanged (still "ABC")
|
||||||
assertEquals(LETTER_A, grid.letter32At(OFF_0_0));
|
assertEquals(LETTER_A, grid.letter32At(OFF_0_0));
|
||||||
assertEquals(LETTER_B, grid.letter32At(OFF_0_1));
|
assertEquals(LETTER_B, grid.letter32At(OFF_0_1));
|
||||||
@@ -357,8 +354,8 @@ public class SwedishGeneratorTest {
|
|||||||
|
|
||||||
// 4. Partial placement then conflict (rollback)
|
// 4. Partial placement then conflict (rollback)
|
||||||
grid = createEmpty();
|
grid = createEmpty();
|
||||||
grid.setLetter(OFF_0_2, LETTER_X); // Conflict at the end
|
grid.setLetterLo(OFF_0_2, LETTER_X); // Conflict at the end
|
||||||
assertFalse(placeWord(grid, s, w1, undoBuffer, 3));
|
assertFalse(placeWord(grid, s, w1));
|
||||||
// Verify grid is still empty (except for 'X')
|
// Verify grid is still empty (except for 'X')
|
||||||
assertFalse(grid.lisLetterAtLo(OFF_0_0));
|
assertFalse(grid.lisLetterAtLo(OFF_0_0));
|
||||||
assertFalse(grid.lisLetterAtLo(OFF_0_1));
|
assertFalse(grid.lisLetterAtLo(OFF_0_1));
|
||||||
@@ -373,15 +370,16 @@ public class SwedishGeneratorTest {
|
|||||||
var lo = (1L << OFF_0_1) | (1L << OFF_0_2);
|
var lo = (1L << OFF_0_1) | (1L << OFF_0_2);
|
||||||
var s = Slot.from(key, lo, 0L);
|
var s = Slot.from(key, lo, 0L);
|
||||||
var w = AZ;
|
var w = AZ;
|
||||||
var undoBuffer = new long[10];
|
val low = grid.lo;
|
||||||
|
val top = grid.hi;
|
||||||
var placed = placeWord(grid, s, w, undoBuffer, 0);
|
var placed = placeWord(grid, s, w);
|
||||||
assertTrue(placed);
|
assertTrue(placed);
|
||||||
assertEquals(LETTER_A, grid.letter32At(OFF_0_1));
|
assertEquals(LETTER_A, grid.letter32At(OFF_0_1));
|
||||||
assertEquals(LETTER_Z, grid.letter32At(OFF_0_2));
|
assertEquals(LETTER_Z, grid.letter32At(OFF_0_2));
|
||||||
assertEquals(lo, undoBuffer[0]);
|
|
||||||
|
|
||||||
grid.undoPlace(undoBuffer[0], undoBuffer[1]);
|
grid.hi = top;
|
||||||
|
grid.lo = low;
|
||||||
|
//grid.undoPlace(undoBuffer[0], undoBuffer[1]);
|
||||||
assertFalse(grid.lisLetterAtLo(OFF_0_1));
|
assertFalse(grid.lisLetterAtLo(OFF_0_1));
|
||||||
assertFalse(grid.lisLetterAtLo(OFF_0_2));
|
assertFalse(grid.lisLetterAtLo(OFF_0_2));
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user