introduce bitloops

This commit is contained in:
mike
2026-01-18 03:32:34 +01:00
parent 6daab5ef4e
commit b026ebfbd2
6 changed files with 194 additions and 74 deletions

View File

@@ -14,7 +14,23 @@ import java.util.stream.IntStream;
import static java.lang.Long.*;
import static puzzle.SwedishGenerator.*;
public record Masker(Rng rng, int[] stack, Clues cache) {
public final class Masker {
private final Rng rng;
private final int[] stack;
private final Clues cache;
private final int[] activeCIdx = new int[SwedishGenerator.SIZE];
private final long[] activeSLo = new long[SwedishGenerator.SIZE];
private final long[] activeSHi = new long[SwedishGenerator.SIZE];
private final long[] adjLo = new long[SwedishGenerator.SIZE];
private final long[] adjHi = new long[SwedishGenerator.SIZE];
public Masker(Rng rng, int[] stack, Clues cache) {
this.rng = rng;
this.stack = stack;
this.cache = cache;
}
public static final int[][] MUTATE_RI = new int[SwedishGenerator.SIZE][625];
@@ -109,6 +125,8 @@ public record Masker(Rng rng, int[] stack, Clues cache) {
long penalty = (((long) Math.abs(grid.clueCount() - clueSize)) * 16000L);
boolean hasSlots = false;
if (!grid.isValid(2)) return 1_000_000_000L;
int numClues = 0;
for (long bits = lo_cl; bits != X; bits &= bits - 1) {
long lsb = bits & -bits;
int clueIdx = numberOfTrailingZeros(lsb);
@@ -130,6 +148,12 @@ public record Masker(Rng rng, int[] stack, Clues cache) {
int msb = 63 - numberOfLeadingZeros(hLo);
rLo &= -(1L << msb << 1);
}
activeCIdx[numClues] = clueIdx;
activeSLo[numClues] = rLo;
activeSHi[numClues] = rHi;
numClues++;
if ((rLo | rHi) != X) {
hasSlots = true;
if (Slot.horiz(key)) {
@@ -167,6 +191,12 @@ public record Masker(Rng rng, int[] stack, Clues cache) {
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)) {
@@ -185,63 +215,64 @@ public record Masker(Rng rng, int[] stack, Clues cache) {
}
if (!hasSlots) return 1_000_000_000L;
long seenLo = X, seenHi = X;
// loop over beide helften
for (int base = 0, size, sp, cur; base <= 64; base += 64) {
long clueMask = (base == 0) ? lo_cl : hi_cl;
long seenMask = (base == 0) ? seenLo : seenHi;
// "unseen clues" in deze helft
for (long bits = clueMask & ~seenMask, nLo, nHi; bits != X; bits &= bits - 1) {
int clueIdx = base | numberOfTrailingZeros(bits);
// start nieuwe component
size = 0;
stack[0] = clueIdx;
sp = 1;
// mark seen
if ((clueIdx & 64) == 0) seenLo |= 1L << clueIdx;
else seenHi |= 1L << (clueIdx & 63);
// flood fill / bfs
while (sp > 0) {
cur = stack[--sp];
size++;
// neighbors als 2x long masks
nLo = NBR8_PACKED_LO[cur];
nHi = NBR8_PACKED_HI[cur];
// filter: alleen clues, en nog niet seen
nLo &= lo_cl & ~seenLo;
nHi &= hi_cl & ~seenHi;
// push lo-neighbors
while (nLo != X) {
long lsb = nLo & -nLo;
int nidx = numberOfTrailingZeros(nLo); // 0..63
seenLo |= lsb;
stack[sp++] = nidx;
nLo &= nLo - 1;
}
// push hi-neighbors
while (nHi != X) {
long lsb = nHi & -nHi;
int nidx = 64 | numberOfTrailingZeros(nHi); // 64..127
seenHi |= lsb;
stack[sp++] = nidx;
nHi &= nHi - 1;
// Connectiviteitscheck
for (int i = 0; i < numClues; i++) {
adjLo[i] = 0; adjHi[i] = 0;
}
for (int i = 0; i < numClues; i++) {
for (int j = i + 1; j < numClues; j++) {
boolean connected = false;
// 1. Intersectie
if (((activeSLo[i] & activeSLo[j]) | (activeSHi[i] & activeSHi[j])) != 0) {
connected = true;
} else {
// 2. 8-naburigheid van clue cells
int ci = activeCIdx[i];
int cj = activeCIdx[j];
if (cj < 64) {
if ((NBR8_PACKED_LO[ci] & (1L << cj)) != 0) connected = true;
} else {
if ((NBR8_PACKED_HI[ci] & (1L << (cj & 63))) != 0) connected = true;
}
}
if (size >= 2) penalty += (size - 1L) * 120L;
if (connected) {
if (j < 64) adjLo[i] |= (1L << j);
else adjHi[i] |= (1L << (j - 64));
if (i < 64) adjLo[j] |= (1L << i);
else adjHi[j] |= (1L << (i - 64));
}
}
}
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 count = bitCount(reachedLo) + bitCount(reachedHi);
if (count < numClues) {
penalty += (numClues - count) * 4000;
penalty += 20000;
}
}
@@ -251,7 +282,7 @@ public record Masker(Rng rng, int[] stack, Clues cache) {
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 += 1500;
if (!h && !v) penalty += 15000;
else if (h && v) { /* ok */ } else if (((h ? cHLo2 : cVLo2) & (1L << clueIdx)) != X) penalty += 600;
else penalty += 200;
}
@@ -261,7 +292,8 @@ public record Masker(Rng rng, int[] stack, Clues cache) {
if ((4 - rci.nbrCount()) + bitCount(rci.n1() & lo_cl) + bitCount(rci.n2() & hi_cl) >= 3) penalty += 400;
boolean h = (cHHi & (1L << clueIdx)) != X;
boolean v = (cVHi & (1L << clueIdx)) != X;
if (!h && !v) penalty += 1500;
if (!h && !v)
penalty += 15000;
else if (h && v) { /* ok */ } else if (((h ? cHHi2 : cVHi2) & (1L << clueIdx)) != X) penalty += 600;
else penalty += 200;
}