introduce bitloops
This commit is contained in:
@@ -388,8 +388,8 @@ public class Main {
|
||||
var swe = new SwedishGenerator(rng, new int[STACK_SIZE], Clues.createEmpty());
|
||||
var mask = swe.generateMask(opts.clueSize, opts.pop, opts.gens, opts.offspring);
|
||||
if (mask == null) return null;
|
||||
|
||||
var filled = fillMask(rng, extractSlots(mask, dict.index()), mask.toGrid());
|
||||
val multiThreaded = Thread.currentThread().getName().contains("pool");
|
||||
var filled = fillMask(rng, extractSlots(mask, dict.index()), mask.toGrid(), multiThreaded);
|
||||
|
||||
TOTAL_NODES.addAndGet(filled.stats().nodes);
|
||||
TOTAL_BACKTRACKS.addAndGet(filled.stats().backtracks);
|
||||
|
||||
@@ -22,6 +22,8 @@ import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.Locale;
|
||||
import java.util.stream.IntStream;
|
||||
import static java.lang.Long.*;
|
||||
import static java.lang.Long.numberOfTrailingZeros;
|
||||
import static java.nio.charset.StandardCharsets.US_ASCII;
|
||||
|
||||
/**
|
||||
@@ -142,8 +144,7 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
||||
stats.simplicity = k == 0 ? 0 : stats.simplicity / k;
|
||||
}
|
||||
}
|
||||
public int wordCount() {
|
||||
int k = 0;
|
||||
public int wordCount(int k) {
|
||||
for (var n = 1; n < clueMap.length; n++) if (clueMap[n] != X) k++;
|
||||
return k;
|
||||
}
|
||||
@@ -220,23 +221,23 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
||||
public boolean notClue(long index) { return ((index & 64) == 0) ? ((lo >>> index) & 1L) == X : ((hi >>> (index & 63)) & 1L) == X; }
|
||||
public boolean notClue(int index) { return ((index & 64) == 0) ? ((lo >>> index) & 1L) == X : ((hi >>> (index & 63)) & 1L) == X; }
|
||||
|
||||
public int clueCount() { return Long.bitCount(lo) + Long.bitCount(hi); }
|
||||
public int clueCount() { return bitCount(lo) + bitCount(hi); }
|
||||
public double similarity(Clues b) {
|
||||
long matchLo = (~(lo ^ b.lo)) & (~lo | (~(vlo ^ b.vlo) & ~(rlo ^ b.rlo)));
|
||||
long matchHi = (~(hi ^ b.hi)) & (~hi | (~(vhi ^ b.vhi) & ~(rhi ^ b.rhi)));
|
||||
|
||||
return (Long.bitCount(matchLo & MASK_LO) + Long.bitCount(matchHi & MASK_HI)) / SIZED;
|
||||
return (bitCount(matchLo & MASK_LO) + bitCount(matchHi & MASK_HI)) / SIZED;
|
||||
}
|
||||
public Grid toGrid() { return new Grid(new byte[SIZE], lo, hi); }
|
||||
public void forEachSlot(SlotVisitor visitor) {
|
||||
for (var l = lo & ~rlo & vlo; l != X; l &= l - 1) processSlot(this, visitor, Slot.packSlotKey(Long.numberOfTrailingZeros(l), 1));
|
||||
for (var l = lo & ~rlo & ~vlo; l != X; l &= l - 1) processSlot(this, visitor, Slot.packSlotKey(Long.numberOfTrailingZeros(l), 0));
|
||||
for (var l = lo & rlo & ~vlo; l != X; l &= l - 1) processSlotRev(this, visitor, Slot.packSlotKey(Long.numberOfTrailingZeros(l), 2));
|
||||
for (var l = lo & rlo & vlo; l != X; l &= l - 1) processSlotRev(this, visitor, Slot.packSlotKey(Long.numberOfTrailingZeros(l), 3));
|
||||
for (var h = hi & ~rhi & vhi; h != X; h &= h - 1) processSlot(this, visitor, Slot.packSlotKey(64 | Long.numberOfTrailingZeros(h), 1));
|
||||
for (var h = hi & ~rhi & ~vhi; h != X; h &= h - 1) processSlot(this, visitor, Slot.packSlotKey(64 | Long.numberOfTrailingZeros(h), 0));
|
||||
for (var h = hi & rhi & ~vhi; h != X; h &= h - 1) processSlotRev(this, visitor, Slot.packSlotKey((64 | Long.numberOfTrailingZeros(h)), 2));
|
||||
for (var h = hi & rhi & vhi; h != X; h &= h - 1) processSlotRev(this, visitor, Slot.packSlotKey((64 | Long.numberOfTrailingZeros(h)), 3));
|
||||
for (var l = lo & ~rlo & vlo; l != X; l &= l - 1) processSlot(this, visitor, Slot.packSlotKey(numberOfTrailingZeros(l), 1));
|
||||
for (var l = lo & ~rlo & ~vlo; l != X; l &= l - 1) processSlot(this, visitor, Slot.packSlotKey(numberOfTrailingZeros(l), 0));
|
||||
for (var l = lo & rlo & ~vlo; l != X; l &= l - 1) processSlotRev(this, visitor, Slot.packSlotKey(numberOfTrailingZeros(l), 2));
|
||||
for (var l = lo & rlo & vlo; l != X; l &= l - 1) processSlotRev(this, visitor, Slot.packSlotKey(numberOfTrailingZeros(l), 3));
|
||||
for (var h = hi & ~rhi & vhi; h != X; h &= h - 1) processSlot(this, visitor, Slot.packSlotKey(64 | numberOfTrailingZeros(h), 1));
|
||||
for (var h = hi & ~rhi & ~vhi; h != X; h &= h - 1) processSlot(this, visitor, Slot.packSlotKey(64 | numberOfTrailingZeros(h), 0));
|
||||
for (var h = hi & rhi & ~vhi; h != X; h &= h - 1) processSlotRev(this, visitor, Slot.packSlotKey((64 | numberOfTrailingZeros(h)), 2));
|
||||
for (var h = hi & rhi & vhi; h != X; h &= h - 1) processSlotRev(this, visitor, Slot.packSlotKey((64 | numberOfTrailingZeros(h)), 3));
|
||||
}
|
||||
public Clues from(Clues best) {
|
||||
lo = best.lo;
|
||||
@@ -275,7 +276,7 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
||||
static byte byteAt(long word, int idx) { return (byte) ((word >>> (idx * 5)) & 0b11111); }
|
||||
static String[] clue(long w) { return CsvIndexService.clues(unpackIndex(w)); }
|
||||
static int simpel(long w) { return CsvIndexService.simpel(unpackIndex(w)); }
|
||||
static int length(long word) { return ((63 - Long.numberOfLeadingZeros(word & LETTER_MASK)) / 5) + 1; }
|
||||
static int length(long word) { return ((63 - numberOfLeadingZeros(word & LETTER_MASK)) / 5) + 1; }
|
||||
static ThreadLocal<byte[]> BYTES = ThreadLocal.withInitial(() -> new byte[MAX_WORD_LENGTH]);
|
||||
public static String asWord(long word) {
|
||||
val len = Lemma.length(word);
|
||||
@@ -338,7 +339,7 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
||||
|
||||
static final int BIT_FOR_DIR = 2;
|
||||
static Slot from(int key, long lo, long hi, DictEntry entry) { return new Slot(key, lo, hi, entry); }
|
||||
public static int length(long lo, long hi) { return Long.bitCount(lo) + Long.bitCount(hi); }
|
||||
public static int length(long lo, long hi) { return bitCount(lo) + bitCount(hi); }
|
||||
public static int clueIndex(int key) { return key >>> BIT_FOR_DIR; }
|
||||
public static int dir(int key) { return key & 3; }
|
||||
public static boolean increasing(int dir) { return (dir & 2) == 0; }
|
||||
@@ -357,12 +358,12 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
||||
long hitsHi = rayHi & c.hi;
|
||||
|
||||
if (hitsHi != X) {
|
||||
int msb = 63 - Long.numberOfLeadingZeros(hitsHi);
|
||||
int msb = 63 - numberOfLeadingZeros(hitsHi);
|
||||
long stop = 1L << msb;
|
||||
rayHi &= ~((stop << 1) - 1); // keep bits > stop
|
||||
rayLo = 0; // lo indices are below stop
|
||||
} else if (hitsLo != X) {
|
||||
int msb = 63 - Long.numberOfLeadingZeros(hitsLo);
|
||||
int msb = 63 - numberOfLeadingZeros(hitsLo);
|
||||
long stop = 1L << msb;
|
||||
rayLo &= ~((stop << 1) - 1);
|
||||
}
|
||||
@@ -376,11 +377,11 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
||||
long hitsHi = rayHi & c.hi;
|
||||
|
||||
if (hitsLo != X) {
|
||||
long stop = 1L << Long.numberOfTrailingZeros(hitsLo);
|
||||
long stop = 1L << numberOfTrailingZeros(hitsLo);
|
||||
rayLo &= (stop - 1);
|
||||
rayHi = 0; // any hi is beyond the stop
|
||||
} else if (hitsHi != X) {
|
||||
long stop = 1L << Long.numberOfTrailingZeros(hitsHi);
|
||||
long stop = 1L << numberOfTrailingZeros(hitsHi);
|
||||
// keep all lo (lo indices are < any hi index), but cut hi below stop
|
||||
rayHi &= (stop - 1);
|
||||
}
|
||||
@@ -405,7 +406,7 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
||||
|
||||
for (long bits = lo_cl; bits != X; bits &= bits - 1) {
|
||||
long lsb = bits & -bits;
|
||||
int clueIdx = Long.numberOfTrailingZeros(lsb);
|
||||
int clueIdx = numberOfTrailingZeros(lsb);
|
||||
int v = (grid.vlo & lsb) != 0 ? 1 : 0;
|
||||
int r = (grid.rlo & lsb) != 0 ? 1 : 0;
|
||||
int key = Slot.packSlotKey(clueIdx, (r << 1) | v);
|
||||
@@ -413,16 +414,16 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
||||
long hLo = rLo & lo_cl, hHi = rHi & hi_cl;
|
||||
if (Slot.increasing(key)) {
|
||||
if (hLo != X) {
|
||||
rLo &= ((1L << Long.numberOfTrailingZeros(hLo)) - 1);
|
||||
rLo &= ((1L << numberOfTrailingZeros(hLo)) - 1);
|
||||
rHi = 0;
|
||||
} else if (hHi != X) { rHi &= ((1L << Long.numberOfTrailingZeros(hHi)) - 1); }
|
||||
} else if (hHi != X) { rHi &= ((1L << numberOfTrailingZeros(hHi)) - 1); }
|
||||
} else {
|
||||
if (hHi != X) {
|
||||
int msb = 63 - Long.numberOfLeadingZeros(hHi);
|
||||
int msb = 63 - numberOfLeadingZeros(hHi);
|
||||
rHi &= ~((1L << msb << 1) - 1);
|
||||
rLo = 0;
|
||||
} else if (hLo != X) {
|
||||
int msb = 63 - Long.numberOfLeadingZeros(hLo);
|
||||
int msb = 63 - numberOfLeadingZeros(hLo);
|
||||
rLo &= ~((1L << msb << 1) - 1);
|
||||
}
|
||||
}
|
||||
@@ -435,14 +436,14 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
||||
cVLo |= rLo;
|
||||
cVHi |= rHi;
|
||||
}
|
||||
if ((Long.bitCount(rLo) + Long.bitCount(rHi)) < MIN_LEN) penalty += 8000;
|
||||
if ((bitCount(rLo) + bitCount(rHi)) < MIN_LEN) penalty += 8000;
|
||||
} else {
|
||||
penalty += 25000;
|
||||
}
|
||||
}
|
||||
for (long bits = hi_cl; bits != X; bits &= bits - 1) {
|
||||
long lsb = bits & -bits;
|
||||
int clueIdx = Long.numberOfTrailingZeros(lsb);
|
||||
int clueIdx = numberOfTrailingZeros(lsb);
|
||||
int v = (grid.vhi & lsb) != 0 ? 1 : 0;
|
||||
int r = (grid.rhi & lsb) != 0 ? 1 : 0;
|
||||
int key = Slot.packSlotKey(64 | clueIdx, (r << 1) | v);
|
||||
@@ -450,16 +451,16 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
||||
long hLo = rLo & lo_cl, hHi = rHi & hi_cl;
|
||||
if (Slot.increasing(key)) {
|
||||
if (hLo != X) {
|
||||
rLo &= ((1L << Long.numberOfTrailingZeros(hLo)) - 1);
|
||||
rLo &= ((1L << numberOfTrailingZeros(hLo)) - 1);
|
||||
rHi = 0;
|
||||
} else if (hHi != X) { rHi &= ((1L << Long.numberOfTrailingZeros(hHi)) - 1); }
|
||||
} else if (hHi != X) { rHi &= ((1L << numberOfTrailingZeros(hHi)) - 1); }
|
||||
} else {
|
||||
if (hHi != X) {
|
||||
int msb = 63 - Long.numberOfLeadingZeros(hHi);
|
||||
int msb = 63 - numberOfLeadingZeros(hHi);
|
||||
rHi &= ~((1L << msb << 1) - 1);
|
||||
rLo = 0;
|
||||
} else if (hLo != X) {
|
||||
int msb = 63 - Long.numberOfLeadingZeros(hLo);
|
||||
int msb = 63 - numberOfLeadingZeros(hLo);
|
||||
rLo &= ~((1L << msb << 1) - 1);
|
||||
}
|
||||
}
|
||||
@@ -472,7 +473,7 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
||||
cVLo |= rLo;
|
||||
cVHi |= rHi;
|
||||
}
|
||||
if ((Long.bitCount(rLo) + Long.bitCount(rHi)) < MIN_LEN) penalty += 8000;
|
||||
if ((bitCount(rLo) + bitCount(rHi)) < MIN_LEN) penalty += 8000;
|
||||
} else {
|
||||
penalty += 25000;
|
||||
}
|
||||
@@ -488,7 +489,7 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
||||
|
||||
// "unseen clues" in deze helft
|
||||
for (long bits = clueMask & ~seenMask, nLo, nHi; bits != X; bits &= bits - 1) {
|
||||
int clueIdx = base | Long.numberOfTrailingZeros(bits);
|
||||
int clueIdx = base | numberOfTrailingZeros(bits);
|
||||
|
||||
// start nieuwe component
|
||||
size = 0;
|
||||
@@ -515,7 +516,7 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
||||
// push lo-neighbors
|
||||
while (nLo != X) {
|
||||
long lsb = nLo & -nLo;
|
||||
int nidx = Long.numberOfTrailingZeros(nLo); // 0..63
|
||||
int nidx = numberOfTrailingZeros(nLo); // 0..63
|
||||
seenLo |= lsb;
|
||||
|
||||
stack[sp++] = nidx;
|
||||
@@ -526,7 +527,7 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
||||
// push hi-neighbors
|
||||
while (nHi != X) {
|
||||
long lsb = nHi & -nHi;
|
||||
int nidx = 64 | Long.numberOfTrailingZeros(nHi); // 64..127
|
||||
int nidx = 64 | numberOfTrailingZeros(nHi); // 64..127
|
||||
seenHi |= lsb;
|
||||
|
||||
stack[sp++] = nidx;
|
||||
@@ -540,9 +541,9 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
||||
}
|
||||
|
||||
for (long bits = ~lo_cl; bits != X; bits &= bits - 1) {
|
||||
int clueIdx = Long.numberOfTrailingZeros(bits);
|
||||
int clueIdx = numberOfTrailingZeros(bits);
|
||||
var rci = IT[clueIdx];
|
||||
if ((4 - rci.nbrCount()) + Long.bitCount(rci.n1() & lo_cl) + Long.bitCount(rci.n2() & hi_cl) >= 3) penalty += 400;
|
||||
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;
|
||||
@@ -550,9 +551,9 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
||||
else penalty += 600;
|
||||
}
|
||||
for (long bits = ~hi_cl & 0xFFL; bits != X; bits &= bits - 1) {
|
||||
int clueIdx = Long.numberOfTrailingZeros(bits);
|
||||
int clueIdx = numberOfTrailingZeros(bits);
|
||||
var rci = IT[64 | clueIdx];
|
||||
if ((4 - rci.nbrCount()) + Long.bitCount(rci.n1() & lo_cl) + Long.bitCount(rci.n2() & hi_cl) >= 3) penalty += 400;
|
||||
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;
|
||||
@@ -629,14 +630,14 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
||||
(a.rlo & ~maskLo) | (other.rlo & maskLo),
|
||||
(a.rhi & ~maskHi) | (other.rhi & maskHi));
|
||||
|
||||
for (var l = c.lo & ~c.rlo & ~c.vlo; l != X; l &= l - 1) clearCluesLo(c, Long.numberOfTrailingZeros(l), 0);
|
||||
for (var l = c.lo & ~c.rlo & c.vlo; l != X; l &= l - 1) clearCluesLo(c, Long.numberOfTrailingZeros(l), 1);
|
||||
for (var l = c.lo & c.rlo & ~c.vlo; l != X; l &= l - 1) clearCluesLo(c, Long.numberOfTrailingZeros(l), 2);
|
||||
for (var l = c.lo & c.rlo & c.vlo; l != X; l &= l - 1) clearCluesLo(c, Long.numberOfTrailingZeros(l), 3);
|
||||
for (var h = c.hi & ~c.rhi & ~c.vhi; h != X; h &= h - 1) clearCluesHi(c, Long.numberOfTrailingZeros(h), 0);
|
||||
for (var h = c.hi & ~c.rhi & c.vhi; h != X; h &= h - 1) clearCluesHi(c, Long.numberOfTrailingZeros(h), 1);
|
||||
for (var h = c.hi & c.rhi & ~c.vhi; h != X; h &= h - 1) clearCluesHi(c, (Long.numberOfTrailingZeros(h)), 2);
|
||||
for (var h = c.hi & c.rhi & ~c.vhi; h != X; h &= h - 1) clearCluesHi(c, (Long.numberOfTrailingZeros(h)), 3);
|
||||
for (var l = c.lo & ~c.rlo & ~c.vlo; l != X; l &= l - 1) clearCluesLo(c, numberOfTrailingZeros(l), 0);
|
||||
for (var l = c.lo & ~c.rlo & c.vlo; l != X; l &= l - 1) clearCluesLo(c, numberOfTrailingZeros(l), 1);
|
||||
for (var l = c.lo & c.rlo & ~c.vlo; l != X; l &= l - 1) clearCluesLo(c, numberOfTrailingZeros(l), 2);
|
||||
for (var l = c.lo & c.rlo & c.vlo; l != X; l &= l - 1) clearCluesLo(c, numberOfTrailingZeros(l), 3);
|
||||
for (var h = c.hi & ~c.rhi & ~c.vhi; h != X; h &= h - 1) clearCluesHi(c, numberOfTrailingZeros(h), 0);
|
||||
for (var h = c.hi & ~c.rhi & c.vhi; h != X; h &= h - 1) clearCluesHi(c, numberOfTrailingZeros(h), 1);
|
||||
for (var h = c.hi & c.rhi & ~c.vhi; h != X; h &= h - 1) clearCluesHi(c, (numberOfTrailingZeros(h)), 2);
|
||||
for (var h = c.hi & c.rhi & ~c.vhi; h != X; h &= h - 1) clearCluesHi(c, (numberOfTrailingZeros(h)), 3);
|
||||
return c;
|
||||
}
|
||||
public static void clearCluesLo(Clues out, int idx, int d) { if (!out.hasRoomForClue(OFFSETS_D_IDX[Slot.packSlotKey(idx, d)])) out.clearClueLo(~(1L << idx)); }
|
||||
@@ -728,26 +729,26 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
||||
long p = 0;
|
||||
if (Slot.increasing(key)) {
|
||||
for (long b = lo & glo; b != X; b &= b - 1) {
|
||||
int idx = Long.numberOfTrailingZeros(b);
|
||||
int i = Long.bitCount(lo & ((1L << idx) - 1));
|
||||
int idx = numberOfTrailingZeros(b);
|
||||
int i = bitCount(lo & ((1L << idx) - 1));
|
||||
p |= ((long) (i * 26 + g[idx])) << (i << 3);
|
||||
}
|
||||
int offset = Long.bitCount(lo);
|
||||
int offset = bitCount(lo);
|
||||
for (long b = hi & ghi; b != X; b &= b - 1) {
|
||||
int idx = Long.numberOfTrailingZeros(b);
|
||||
int i = offset + Long.bitCount(hi & ((1L << idx) - 1));
|
||||
int idx = numberOfTrailingZeros(b);
|
||||
int i = offset + bitCount(hi & ((1L << idx) - 1));
|
||||
p |= ((long) (i * 26 + g[64 | idx])) << (i << 3);
|
||||
}
|
||||
} else {
|
||||
int offset = Long.bitCount(hi);
|
||||
int offset = bitCount(hi);
|
||||
for (long b = hi & ghi; b != X; b &= b - 1) {
|
||||
int idx = Long.numberOfTrailingZeros(b);
|
||||
int i = Long.bitCount(hi & ~((1L << idx) | ((1L << idx) - 1)));
|
||||
int idx = numberOfTrailingZeros(b);
|
||||
int i = bitCount(hi & ~((1L << idx) | ((1L << idx) - 1)));
|
||||
p |= ((long) (i * 26 + g[64 | idx])) << (i << 3);
|
||||
}
|
||||
for (long b = lo & glo; b != X; b &= b - 1) {
|
||||
int idx = Long.numberOfTrailingZeros(b);
|
||||
int i = offset + Long.bitCount(lo & ~((1L << idx) | ((1L << idx) - 1)));
|
||||
int idx = numberOfTrailingZeros(b);
|
||||
int i = offset + bitCount(lo & ~((1L << idx) | ((1L << idx) - 1)));
|
||||
p |= ((long) (i * 26 + g[idx])) << (i << 3);
|
||||
}
|
||||
}
|
||||
@@ -755,56 +756,56 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
||||
}
|
||||
static int slotScore(byte[] count, long lo, long hi) {
|
||||
int cross = 0;
|
||||
for (long b = lo; b != X; b &= b - 1) cross += (count[Long.numberOfTrailingZeros(b)] - 1);
|
||||
for (long b = hi; b != X; b &= b - 1) cross += (count[64 | Long.numberOfTrailingZeros(b)] - 1);
|
||||
for (long b = lo; b != X; b &= b - 1) cross += (count[numberOfTrailingZeros(b)] - 1);
|
||||
for (long b = hi; b != X; b &= b - 1) cross += (count[64 | numberOfTrailingZeros(b)] - 1);
|
||||
return cross * 10 + Slot.length(lo, hi);
|
||||
}
|
||||
static boolean placeWord(final Grid grid, final byte[] g, final int key, final long lo, final long hi, final long w) {
|
||||
final long glo = grid.lo, ghi = grid.hi;
|
||||
if (Slot.increasing(key)) {
|
||||
for (long b = lo & glo; b != X; b &= b - 1) {
|
||||
int idx = Long.numberOfTrailingZeros(b);
|
||||
if (g[idx] != Lemma.byteAt(w, Long.bitCount(lo & ((1L << idx) - 1)))) return false;
|
||||
int idx = numberOfTrailingZeros(b);
|
||||
if (g[idx] != Lemma.byteAt(w, bitCount(lo & ((1L << idx) - 1)))) return false;
|
||||
}
|
||||
int bcLo = Long.bitCount(lo);
|
||||
int bcLo = bitCount(lo);
|
||||
for (long b = hi & ghi; b != X; b &= b - 1) {
|
||||
int idx = Long.numberOfTrailingZeros(b);
|
||||
if (g[64 | idx] != Lemma.byteAt(w, bcLo + Long.bitCount(hi & ((1L << idx) - 1)))) return false;
|
||||
int idx = numberOfTrailingZeros(b);
|
||||
if (g[64 | idx] != Lemma.byteAt(w, bcLo + bitCount(hi & ((1L << idx) - 1)))) return false;
|
||||
}
|
||||
|
||||
long maskLo = lo & ~glo, maskHi = hi & ~ghi;
|
||||
if ((maskLo | maskHi) != X) {
|
||||
for (long b = maskLo; b != X; b &= b - 1) {
|
||||
int idx = Long.numberOfTrailingZeros(b);
|
||||
g[idx] = Lemma.byteAt(w, Long.bitCount(lo & ((1L << idx) - 1)));
|
||||
int idx = numberOfTrailingZeros(b);
|
||||
g[idx] = Lemma.byteAt(w, bitCount(lo & ((1L << idx) - 1)));
|
||||
}
|
||||
for (long b = maskHi; b != X; b &= b - 1) {
|
||||
int idx = Long.numberOfTrailingZeros(b);
|
||||
g[64 | idx] = Lemma.byteAt(w, bcLo + Long.bitCount(hi & ((1L << idx) - 1)));
|
||||
int idx = numberOfTrailingZeros(b);
|
||||
g[64 | idx] = Lemma.byteAt(w, bcLo + bitCount(hi & ((1L << idx) - 1)));
|
||||
}
|
||||
grid.lo |= maskLo;
|
||||
grid.hi |= maskHi;
|
||||
}
|
||||
} else {
|
||||
int bcHi = Long.bitCount(hi);
|
||||
int bcHi = bitCount(hi);
|
||||
for (long b = hi & ghi; b != X; b &= b - 1) {
|
||||
int idx = Long.numberOfTrailingZeros(b);
|
||||
if (g[64 | idx] != Lemma.byteAt(w, Long.bitCount(hi & ~((1L << idx) | ((1L << idx) - 1))))) return false;
|
||||
int idx = numberOfTrailingZeros(b);
|
||||
if (g[64 | idx] != Lemma.byteAt(w, bitCount(hi & ~((1L << idx) | ((1L << idx) - 1))))) return false;
|
||||
}
|
||||
for (long b = lo & glo; b != X; b &= b - 1) {
|
||||
int idx = Long.numberOfTrailingZeros(b);
|
||||
if (g[idx] != Lemma.byteAt(w, bcHi + Long.bitCount(lo & ~((1L << idx) | ((1L << idx) - 1))))) return false;
|
||||
int idx = numberOfTrailingZeros(b);
|
||||
if (g[idx] != Lemma.byteAt(w, bcHi + bitCount(lo & ~((1L << idx) | ((1L << idx) - 1))))) return false;
|
||||
}
|
||||
|
||||
long maskLo = lo & ~glo, maskHi = hi & ~ghi;
|
||||
if ((maskLo | maskHi) != X) {
|
||||
for (long b = maskHi; b != X; b &= b - 1) {
|
||||
int idx = Long.numberOfTrailingZeros(b);
|
||||
g[64 | idx] = Lemma.byteAt(w, Long.bitCount(hi & ~((1L << idx) | ((1L << idx) - 1))));
|
||||
int idx = numberOfTrailingZeros(b);
|
||||
g[64 | idx] = Lemma.byteAt(w, bitCount(hi & ~((1L << idx) | ((1L << idx) - 1))));
|
||||
}
|
||||
for (long b = maskLo; b != X; b &= b - 1) {
|
||||
int idx = Long.numberOfTrailingZeros(b);
|
||||
g[idx] = Lemma.byteAt(w, bcHi + Long.bitCount(lo & ~((1L << idx) | ((1L << idx) - 1))));
|
||||
int idx = numberOfTrailingZeros(b);
|
||||
g[idx] = Lemma.byteAt(w, bcHi + bitCount(lo & ~((1L << idx) | ((1L << idx) - 1))));
|
||||
}
|
||||
grid.lo |= maskLo;
|
||||
grid.hi |= maskHi;
|
||||
@@ -828,19 +829,19 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
||||
}
|
||||
p >>>= 8;
|
||||
} else {
|
||||
p >>>= (Long.numberOfTrailingZeros(p) & ~7);
|
||||
p >>>= (numberOfTrailingZeros(p) & ~7);
|
||||
}
|
||||
}
|
||||
|
||||
int count = 0;
|
||||
for (int k = 0; k < numLongs; k++) count += Long.bitCount(res[k]);
|
||||
for (int k = 0; k < numLongs; k++) count += bitCount(res[k]);
|
||||
|
||||
int[] indices = new int[count];
|
||||
int ki = 0;
|
||||
for (int k = 0; k < numLongs; k++) {
|
||||
long w = res[k];
|
||||
while (w != X) {
|
||||
int t = Long.numberOfTrailingZeros(w);
|
||||
int t = numberOfTrailingZeros(w);
|
||||
indices[ki++] = (k << 6) | t;
|
||||
w &= w - 1;
|
||||
}
|
||||
@@ -864,20 +865,20 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
||||
}
|
||||
p >>>= 8;
|
||||
} else {
|
||||
p >>>= (Long.numberOfTrailingZeros(p) & ~7);
|
||||
p >>>= (numberOfTrailingZeros(p) & ~7);
|
||||
}
|
||||
}
|
||||
|
||||
int count = 0;
|
||||
for (int k = 0; k < numLongs; k++) count += Long.bitCount(res[k]);
|
||||
for (int k = 0; k < numLongs; k++) count += bitCount(res[k]);
|
||||
return count;
|
||||
}
|
||||
|
||||
static void scoreSlots(int[] slotScores, Slot[] slots) {
|
||||
val count = new byte[SIZE];
|
||||
for (var s : slots) {
|
||||
for (long b = s.lo; b != X; b &= b - 1) count[Long.numberOfTrailingZeros(b)]++;
|
||||
for (long b = s.hi; b != X; b &= b - 1) count[64 | Long.numberOfTrailingZeros(b)]++;
|
||||
for (long b = s.lo; b != X; b &= b - 1) count[numberOfTrailingZeros(b)]++;
|
||||
for (long b = s.hi; b != X; b &= b - 1) count[64 | numberOfTrailingZeros(b)]++;
|
||||
}
|
||||
for (int i = 0; i < slots.length; i++) {
|
||||
var slot = slots[i];
|
||||
@@ -885,14 +886,13 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
||||
}
|
||||
|
||||
}
|
||||
public static FillResult fillMask(Rng rng, Slot[] slots, Grid mask) {
|
||||
val multiThreaded = Thread.currentThread().getName().contains("pool");
|
||||
val NO_LOG = (!Main.VERBOSE || multiThreaded);
|
||||
val grid = mask;
|
||||
val used = new long[2048];
|
||||
val assigned = new long[CLUE_INDEX_MAX_SIZE];
|
||||
val bitset = new long[2500];
|
||||
val g = grid.g;
|
||||
public static FillResult fillMask(final Rng rng,final Slot[] slots,final Grid mask, final boolean multiThreaded) {
|
||||
val NO_LOG = (!Main.VERBOSE || multiThreaded);
|
||||
val grid = mask;
|
||||
val used = new long[2048];
|
||||
val assigned = new long[CLUE_INDEX_MAX_SIZE];
|
||||
val bitset = new long[2500];
|
||||
val g = grid.g;
|
||||
|
||||
val TOTAL = slots.length;
|
||||
val slotScores = new int[TOTAL];
|
||||
@@ -907,7 +907,7 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
||||
long nodes;
|
||||
long backtracks;
|
||||
int lastMRV;
|
||||
long lastLog = t0;
|
||||
long lastLog = t0, glo = grid.lo, ghi = grid.hi;
|
||||
Pick current = CARRIER;
|
||||
void renderProgress() {
|
||||
var now = System.currentTimeMillis();
|
||||
@@ -930,12 +930,44 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
||||
System.out.print("\r" + Strings.padRight(msg, 120));
|
||||
System.out.flush();
|
||||
}
|
||||
boolean placeWord(final int key, final long lo, final long hi, final long w) {
|
||||
int idx;
|
||||
if (Slot.increasing(key)) {
|
||||
for (long b = lo & glo; b != X; b &= b - 1) if (g[idx = numberOfTrailingZeros(b)] != Lemma.byteAt(w, bitCount(lo & ((1L << idx) - 1)))) return false;
|
||||
int bcLo = bitCount(lo);
|
||||
for (long b = hi & ghi; b != X; b &= b - 1)
|
||||
if (g[64 | (idx = numberOfTrailingZeros(b))] != Lemma.byteAt(w, bcLo + bitCount(hi & ((1L << idx) - 1)))) return false;
|
||||
|
||||
long maskLo = lo & ~glo, maskHi = hi & ~ghi;
|
||||
if ((maskLo | maskHi) != X) {
|
||||
for (long b = maskLo; b != X; b &= b - 1) g[idx = idx = numberOfTrailingZeros(b)] = Lemma.byteAt(w, bitCount(lo & ((1L << idx) - 1)));
|
||||
for (long b = maskHi; b != X; b &= b - 1) g[64 | (idx = numberOfTrailingZeros(b))] = Lemma.byteAt(w, bcLo + bitCount(hi & ((1L << idx) - 1)));
|
||||
glo |= maskLo;
|
||||
ghi |= maskHi;
|
||||
}
|
||||
} else {
|
||||
int bcHi = bitCount(hi);
|
||||
for (long b = hi & ghi; b != X; b &= b - 1)
|
||||
if (g[64 | (idx = numberOfTrailingZeros(b))] != Lemma.byteAt(w, bitCount(hi & ~((1L << idx) | ((1L << idx) - 1))))) return false;
|
||||
for (long b = lo & glo; b != X; b &= b - 1)
|
||||
if (g[idx = numberOfTrailingZeros(b)] != Lemma.byteAt(w, bcHi + bitCount(lo & ~((1L << idx) | ((1L << idx) - 1))))) return false;
|
||||
|
||||
long maskLo = lo & ~glo, maskHi = hi & ~ghi;
|
||||
if ((maskLo | maskHi) != X) {
|
||||
for (long b = maskHi; b != X; b &= b - 1) g[64 | (idx = numberOfTrailingZeros(b))] = Lemma.byteAt(w, bitCount(hi & ~((1L << idx) | ((1L << idx) - 1))));
|
||||
for (long b = maskLo; b != X; b &= b - 1) g[idx = numberOfTrailingZeros(b)] = Lemma.byteAt(w, bcHi + bitCount(lo & ~((1L << idx) | ((1L << idx) - 1))));
|
||||
glo |= maskLo;
|
||||
ghi |= maskHi;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
void chooseMRV() {
|
||||
Slot best = null;
|
||||
for (int i = 0, count, count2 = -1, bestScore = -1, n = TOTAL; i < n; i++) {
|
||||
var s = slots[i];
|
||||
if (assigned[s.key] != X) continue;
|
||||
var pattern = patternForSlot(grid.lo, grid.hi, g, s.key, s.lo, s.hi);
|
||||
var pattern = patternForSlot(glo, ghi, g, s.key, s.lo, s.hi);
|
||||
var index = s.entry;
|
||||
count = pattern == X ? index.length : candidateCountForPattern(bitset, pattern, index.posBitsets, index.numlong);
|
||||
|
||||
@@ -957,7 +989,7 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
||||
current = PICK_DONE;
|
||||
return;
|
||||
}
|
||||
var pattern = patternForSlot(grid.lo, grid.hi, g, best.key, best.lo, best.hi);
|
||||
var pattern = patternForSlot(glo, ghi, g, best.key, best.lo, best.hi);
|
||||
var index = best.entry;
|
||||
current = CARRIER;
|
||||
current.slot = best;
|
||||
@@ -1004,9 +1036,9 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
||||
var w = entry.words[idx];
|
||||
var lemIdx = Lemma.unpackIndex(w);
|
||||
if (Bit1029.get(used, lemIdx)) continue;
|
||||
low = grid.lo;
|
||||
top = grid.hi;
|
||||
if (!placeWord(grid, g, k, slo, shi, w)) continue;
|
||||
low = glo;
|
||||
top = ghi;
|
||||
if (!placeWord(k, slo, shi, w)) continue;
|
||||
|
||||
Bit1029.set(used, lemIdx);
|
||||
assigned[k] = w;
|
||||
@@ -1015,8 +1047,8 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
||||
|
||||
assigned[k] = X;
|
||||
Bit1029.clear(used, lemIdx);
|
||||
grid.lo = low;
|
||||
grid.hi = top;
|
||||
glo = low;
|
||||
ghi = top;
|
||||
}
|
||||
backtracks++;
|
||||
return false;
|
||||
@@ -1031,9 +1063,9 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
||||
var w = entry.words[idxInArray];
|
||||
var lemIdx = Lemma.unpackIndex(w);
|
||||
if (Bit1029.get(used, lemIdx)) continue;
|
||||
low = grid.lo;
|
||||
top = grid.hi;
|
||||
if (!placeWord(grid, g, k, slo, shi, w)) continue;
|
||||
low = glo;
|
||||
top = ghi;
|
||||
if (!placeWord(k, slo, shi, w)) continue;
|
||||
|
||||
Bit1029.set(used, lemIdx);
|
||||
assigned[k] = w;
|
||||
@@ -1042,8 +1074,8 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
||||
|
||||
assigned[k] = X;
|
||||
Bit1029.clear(used, lemIdx);
|
||||
grid.lo = low;
|
||||
grid.hi = top;
|
||||
glo = low;
|
||||
ghi = top;
|
||||
}
|
||||
|
||||
backtracks++;
|
||||
@@ -1056,7 +1088,8 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
||||
if (!NO_LOG) solver.renderProgress();
|
||||
var ok = solver.backtrack(0);
|
||||
// final progress line
|
||||
|
||||
grid.lo = solver.glo;
|
||||
grid.hi = solver.ghi;
|
||||
var res = new FillResult(ok, new Gridded(grid), assigned,
|
||||
new FillStats(solver.nodes, solver.backtracks, (System.currentTimeMillis() - t0) / 1000.0, solver.lastMRV));
|
||||
if (!multiThreaded) {
|
||||
@@ -1068,7 +1101,7 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
||||
System.out.println(
|
||||
String.format(Locale.ROOT,
|
||||
"[######################] %d/%d slots | nodes=%d | backtracks=%d | mrv=%d | %.1fs",
|
||||
res.wordCount(), TOTAL, res.nodes(), res.backtracks(), res.lastMRV(), res.seconds()
|
||||
res.wordCount(0), TOTAL, res.nodes(), res.backtracks(), res.lastMRV(), res.seconds()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -180,9 +180,9 @@ public class MainTest {
|
||||
128L,
|
||||
422762372923520L,
|
||||
192L);
|
||||
var filled = fillMask(rng, extractSlots(mask, dict.index()), mask.toGrid());
|
||||
var filled = fillMask(rng, extractSlots(mask, dict.index()), mask.toGrid(), false);
|
||||
Assertions.assertTrue(filled.ok(), "Puzzle generation failed (not ok)");
|
||||
Assertions.assertEquals(18, filled.wordCount(), "Number of assigned words changed");
|
||||
Assertions.assertEquals(18, filled.wordCount(0), "Number of assigned words changed");
|
||||
Assertions.assertEquals("SLEDE", Lemma.asWord(filled.clueMap()[282]));
|
||||
Assertions.assertEquals(-1L, filled.grid().grid().lo);
|
||||
Assertions.assertEquals(255L, filled.grid().grid().hi);
|
||||
@@ -201,7 +201,7 @@ public class MainTest {
|
||||
foundSeed = seed;
|
||||
System.out.println("[DEBUG_LOG] Seed found: " + seed);
|
||||
System.out.println("[DEBUG_LOG] Simplicity: " + res.filled().stats().simplicity);
|
||||
System.out.println("[DEBUG_LOG] ClueMap Size: " + res.filled().wordCount());
|
||||
System.out.println("[DEBUG_LOG] ClueMap Size: " + res.filled().wordCount(0));
|
||||
System.out.println("[DEBUG_LOG] Grid:");
|
||||
System.out.println(res.filled().grid().renderHuman(res.clues().c()));
|
||||
System.out.println(res.filled().grid().gridToString(res.clues().c()));
|
||||
@@ -214,15 +214,8 @@ public class MainTest {
|
||||
Assertions.assertTrue(res.filled().ok(), "Puzzle generation failed (not ok)");
|
||||
Assertions.assertEquals(12348, foundSeed, "Found seed changed");
|
||||
}
|
||||
boolean isLetter(byte b) { return (b & 64) != 0; }
|
||||
@Test
|
||||
public void testIsLetterA() {
|
||||
assertTrue(isLetter((byte) 'A'));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsLetterZ() {
|
||||
assertTrue(isLetter((byte) 'Z'));
|
||||
}
|
||||
boolean isLetter(byte b) { return (b & 64) != 0; }
|
||||
@Test public void testIsLetterA() { assertTrue(isLetter((byte) 'A')); }
|
||||
@Test public void testIsLetterZ() { assertTrue(isLetter((byte) 'Z')); }
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user