introduce bitloops

This commit is contained in:
mike
2026-01-20 02:45:16 +01:00
parent d1c448e1cb
commit 28f448d178
4 changed files with 124 additions and 38 deletions

View File

@@ -0,0 +1,16 @@
package puzzle;
/**
* Generated constants from pom.xml during build via templating-maven-plugin.
*/
public final class Config {
public static final int CLUE_SIZE = 4;
public static final int MIN_LEN = 2;
public static final int MAX_TRIES_PER_SLOT = 1000;
public static final int MAX_LEN = 8;
public static final int PUZZLE_ROWS = 8;
public static final int PUZZLE_COLS = 9;
public static final int PUZZLE_SIZE = PUZZLE_ROWS*PUZZLE_COLS;
public static final int MAX_WORD_LENGTH = PUZZLE_ROWS;
public static final int MAX_WORD_LENGTH_MIN_1 = PUZZLE_ROWS-1;
}

View File

@@ -34,7 +34,7 @@ public class Main {
@NoArgsConstructor
public static class Opts {
static int SSIZE = 23;
static int SSIZE = 20;
public int seed = (int) (System.nanoTime() ^ System.currentTimeMillis());
public int clueSize = SSIZE;
public int pop = SSIZE * 2;

View File

@@ -28,13 +28,45 @@ public final class Masker {
}
public boolean isValid(Clues c, int minLen) {
return c.isValid(minLen, activeSLo, activeSHi);
return findOffendingClue(c, minLen) == -1;
}
public int findOffendingClue(Clues grid, int minLen) {
if (((grid.xlo & grid.rlo) & grid.lo) != X) return numberOfTrailingZeros((grid.xlo & grid.rlo) & grid.lo);
if (((grid.xhi & grid.rhi) & grid.hi) != X) return 64 | numberOfTrailingZeros((grid.xhi & grid.rhi) & grid.hi);
int num = 0;
for (long bits = grid.lo; bits != X; bits &= bits - 1) activeCIdx[num++] = numberOfTrailingZeros(bits);
for (long bits = grid.hi; bits != X; bits &= bits - 1) activeCIdx[num++] = 64 | numberOfTrailingZeros(bits);
if (num == 0) return -1;
int start = rng.randint0_SIZE() % num;
int n = 0;
for (int i = 0; i < num; i++) {
int idx = activeCIdx[(start + i) % num];
int dir = grid.getDir(idx);
int key = Slot.packSlotKey(idx, dir);
long sLo = PATH_LO[key], sHi = PATH_HI[key];
long hLo = sLo & grid.lo, hHi = sHi & grid.hi;
if (Slotinfo.increasing(key)) {
if (hLo != X) { sLo &= (1L << numberOfTrailingZeros(hLo)) - 1; sHi = 0; }
else if (hHi != X) { sHi &= (1L << numberOfTrailingZeros(hHi)) - 1; }
} else {
if (hHi != X) { sHi &= -(1L << (63 - numberOfLeadingZeros(hHi)) << 1); sLo = 0; }
else if (hLo != X) { sLo &= -(1L << (63 - numberOfLeadingZeros(hLo)) << 1); }
}
if (bitCount(sLo) + bitCount(sHi) < minLen) return idx;
for (int j = 0; j < n; j++) if (bitCount(sLo & activeSLo[j]) + bitCount(sHi & activeSHi[j]) > 1) return idx;
activeSLo[n] = sLo; activeSHi[n] = sHi; n++;
}
return -1;
}
public void cleanup(Clues c, int minLen) {
int guard = 0;
while (guard++ < 50) {
int offending = c.findOffendingClue(minLen, activeSLo, activeSHi);
int offending = findOffendingClue(c, minLen);
if (offending == -1) break;
if ((offending & 64) == 0) c.clearClueLo(~(1L << offending));
else c.clearClueHi(~(1L << (offending & 63)));
@@ -199,6 +231,8 @@ public final class Masker {
cVHi |= rHi;
}
if ((bitCount(rLo) + bitCount(rHi)) < MIN_LEN) penalty += 8000;
int wordLen = bitCount(rLo) + bitCount(rHi);
if (wordLen > 5) penalty += (wordLen - 5) * 2000;
} else penalty += 25000;
}
for (long bits = hi_cl; bits != X; bits &= bits - 1) {
@@ -221,12 +255,12 @@ public final class Masker {
int msb = 63 - numberOfLeadingZeros(hLo);
rLo &= -(1L << msb << 1);
}
activeCIdx[numClues] = 64 | clueIdx;
activeSLo[numClues] = rLo;
activeSHi[numClues] = rHi;
numClues++;
if ((rLo | rHi) != X) {
hasSlots = true;
if (Slot.horiz(key)) {
@@ -241,10 +275,22 @@ public final class Masker {
cVHi |= rHi;
}
if ((bitCount(rLo) + bitCount(rHi)) < MIN_LEN) penalty += 8000;
int wordLen = bitCount(rLo) + bitCount(rHi);
if (wordLen > 5) penalty += (wordLen - 5) * 2000;
} else penalty += 25000;
}
if (!hasSlots) return 1_000_000_000L;
int[] rCount = new int[8];
int[] cCount = new int[9];
for (int i = 0; i < numClues; i++) {
int idx = activeCIdx[i];
rCount[idx & 7]++;
cCount[idx >> 3]++;
}
for (int rc : rCount) if (rc < 2) penalty += (2 - rc) * 4000;
for (int cc : cCount) if (cc < 2) penalty += (2 - cc) * 4000;
// Connectiviteitscheck
for (int i = 0; i < numClues; i++) {
@@ -269,44 +315,56 @@ public final class Masker {
}
if (numClues > 0) {
long reachedLo = 1L, reachedHi = 0L;
stack[0] = 0;
int sp = 1;
while (sp > 0) {
int cur = stack[--sp];
long nLo = adjLo[cur] & ~reachedLo;
long nHi = adjHi[cur] & ~reachedHi;
while (nLo != 0) {
long lsb = nLo & -nLo;
int idx = numberOfTrailingZeros(lsb);
reachedLo |= lsb;
stack[sp++] = idx;
nLo &= ~lsb;
}
while (nHi != 0) {
long lsb = nHi & -nHi;
int idx = 64 | numberOfTrailingZeros(lsb);
reachedHi |= lsb;
stack[sp++] = idx;
nHi &= ~lsb;
int maxReached = 0;
long totalReachedLo = 0, totalReachedHi = 0;
for (int i = 0; i < numClues; i++) {
if (i < 64) { if ((totalReachedLo & (1L << i)) != 0) continue; }
else { if ((totalReachedHi & (1L << (i - 64))) != 0) continue; }
long currentReachedLo = (i < 64) ? (1L << i) : 0;
long currentReachedHi = (i >= 64) ? (1L << (i - 64)) : 0;
stack[0] = i;
int sp = 1;
int count = 0;
while (sp > 0) {
int cur = stack[--sp];
count++;
long nLo = adjLo[cur] & ~currentReachedLo;
long nHi = adjHi[cur] & ~currentReachedHi;
while (nLo != 0) {
long lsb = nLo & -nLo;
int idx = numberOfTrailingZeros(lsb);
currentReachedLo |= lsb;
stack[sp++] = idx;
nLo &= ~lsb;
}
while (nHi != 0) {
long lsb = nHi & -nHi;
int idx = 64 | numberOfTrailingZeros(lsb);
currentReachedHi |= lsb;
stack[sp++] = idx;
nHi &= ~lsb;
}
}
if (count > maxReached) maxReached = count;
totalReachedLo |= currentReachedLo;
totalReachedHi |= currentReachedHi;
}
int count = bitCount(reachedLo) + bitCount(reachedHi);
if (count < numClues) {
penalty += (numClues - count) * 4000;
if (maxReached < numClues) {
penalty += (numClues - maxReached) * 4000;
penalty += 20000;
}
}
for (long bits = ~lo_cl & MASK_LO; bits != X; bits &= bits - 1) {
int clueIdx = numberOfTrailingZeros(bits);
var rci = IT[clueIdx];
if ((4 - rci.nbrCount()) + bitCount(rci.n1() & lo_cl) + bitCount(rci.n2() & hi_cl) >= 3) penalty += 400;
boolean h = (cHLo & (1L << clueIdx)) != X;
boolean v = (cVLo & (1L << clueIdx)) != X;
if (!h && !v) penalty += 5000;
else if (h && v) { /* ok */ } else if (((h ? cHLo2 : cVLo2) & (1L << clueIdx)) != X) penalty += 600;
else penalty += 200;
if (!h && !v) penalty += 2000;
else if (h && v) { /* ok */ } else if (((h ? cHLo2 : cVLo2) & (1L << clueIdx)) != X) penalty += 1000;
else penalty += 1000;
}
for (long bits = ~hi_cl & MASK_HI; bits != X; bits &= bits - 1) {
int clueIdx = numberOfTrailingZeros(bits);
@@ -315,11 +373,23 @@ public final class Masker {
boolean h = (cHHi & (1L << clueIdx)) != X;
boolean v = (cVHi & (1L << clueIdx)) != X;
if (!h && !v)
penalty += 5000;
else if (h && v) { /* ok */ } else if (((h ? cHHi2 : cVHi2) & (1L << clueIdx)) != X) penalty += 600;
else penalty += 200;
penalty += 2000;
else if (h && v) { /* ok */ } else if (((h ? cHHi2 : cVHi2) & (1L << clueIdx)) != X) penalty += 1000;
else penalty += 1000;
}
long nclLo = ~lo_cl & MASK_LO;
long nclHi = ~hi_cl & MASK_HI;
long hNbrLo = (nclLo >> 8) | (nclLo << 8) | (nclHi << 56);
long hNbrHi = (nclHi >> 8) | (nclLo >> 56);
long vNbrLo = ((nclLo & ~0x0101010101010101L) >> 1) | ((nclLo & ~0x8080808080808080L) << 1);
long vNbrHi = ((nclHi & ~0x01L) >> 1) | ((nclHi & ~0x80L) << 1);
penalty += bitCount(nclLo & ~cHLo & hNbrLo) * 800;
penalty += bitCount(nclLo & ~cVLo & vNbrLo) * 800;
penalty += bitCount(nclHi & ~cHHi & hNbrHi) * 800;
penalty += bitCount(nclHi & ~cVHi & vNbrHi) * 800;
return penalty;
}

View File

@@ -40,7 +40,7 @@ public record SwedishGenerator() {
public static final int MAX_WORD_LENGTH = Config.PUZZLE_ROWS;
public static final int MAX_WORD_LENGTH_PLUS_ONE = MAX_WORD_LENGTH + 1;
public static final int MIN_LEN = 2;//Neighbors9x8.MIN_LEN;//Config.MIN_LEN;
public static final int MAX_TRIES_PER_SLOT = 700;//Config.MAX_TRIES_PER_SLOT;
public static final int MAX_TRIES_PER_SLOT = 1200;//Config.MAX_TRIES_PER_SLOT;
public static final int STACK_SIZE = 128;
public static final long RANGE_0_SIZE = Neighbors9x8.RANGE_0_SIZE;// (long) SIZE_MIN_1 - 0L + 1L
public static final long RANGE_0_624 = Neighbors9x8.RANGE_0_624;//624L - 0L + 1L;