|
|
|
|
@@ -13,6 +13,7 @@ import puzzle.Export.DictEntryDTO;
|
|
|
|
|
import puzzle.Export.Gridded;
|
|
|
|
|
import puzzle.Export.Strings;
|
|
|
|
|
import java.io.IOException;
|
|
|
|
|
import java.nio.charset.StandardCharsets;
|
|
|
|
|
import java.nio.file.Files;
|
|
|
|
|
import java.nio.file.Path;
|
|
|
|
|
import java.util.ArrayList;
|
|
|
|
|
@@ -20,7 +21,7 @@ import java.util.Arrays;
|
|
|
|
|
import java.util.Comparator;
|
|
|
|
|
import java.util.Locale;
|
|
|
|
|
import java.util.stream.IntStream;
|
|
|
|
|
import static java.nio.charset.StandardCharsets.*;
|
|
|
|
|
import static java.nio.charset.StandardCharsets.US_ASCII;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* NOTE:
|
|
|
|
|
@@ -66,8 +67,10 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
|
|
|
|
static final int STACK_SIZE = 64;
|
|
|
|
|
static final char C_DASH = '\0';
|
|
|
|
|
static final byte _1 = 49, _9 = 57, A = 65, Z = 90, DASH = (byte) C_DASH;
|
|
|
|
|
static final long RANGE_0_SIZE = (long) SIZE_MIN_1 - 0L + 1L;
|
|
|
|
|
static final long RANGE_0_624 = 624L - 0L + 1L;
|
|
|
|
|
//72 << 3;
|
|
|
|
|
static final int CLUE_INDEX_MAX_SIZE = (288 | 3) + 1;
|
|
|
|
|
static final int CLUE_INDEX_MAX_SIZE = (288 | 3) + 1;
|
|
|
|
|
static int clamp(int x, int a, int b) { return Math.max(a, Math.min(b, x)); }
|
|
|
|
|
@AllArgsConstructor
|
|
|
|
|
static class Pick {
|
|
|
|
|
@@ -140,11 +143,7 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
|
|
|
|
}
|
|
|
|
|
public int wordCount() {
|
|
|
|
|
int k = 0;
|
|
|
|
|
for (var n = 1; n < clueMap.length; n++) {
|
|
|
|
|
if (clueMap[n] != X) {
|
|
|
|
|
k++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for (var n = 1; n < clueMap.length; n++) if (clueMap[n] != X) k++;
|
|
|
|
|
return k;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@@ -165,38 +164,26 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
|
|
|
|
x = y;
|
|
|
|
|
return y;
|
|
|
|
|
}
|
|
|
|
|
byte randbyte(int min, int max) {
|
|
|
|
|
var u = (nextU32() & 0xFFFFFFFFL);
|
|
|
|
|
var range = (long) max - (long) min + 1L;
|
|
|
|
|
return (byte) (min + (u % range));
|
|
|
|
|
}
|
|
|
|
|
int randint2bit() { return nextU32() & 3; }
|
|
|
|
|
byte randint2bitByte() { return (byte) (nextU32() & 3); }
|
|
|
|
|
int randint(int min, int max) {
|
|
|
|
|
var u = (nextU32() & 0xFFFFFFFFL);
|
|
|
|
|
var range = (long) max - (long) min + 1L;
|
|
|
|
|
return (int) (min + (u % range));
|
|
|
|
|
}
|
|
|
|
|
double nextFloat() { return (nextU32() & 0xFFFFFFFFL) / 4294967295.0; }
|
|
|
|
|
int biasedIndexPow3(int N) {
|
|
|
|
|
int m = Math.min(nextU32(), Math.min(nextU32(), nextU32()));
|
|
|
|
|
return (int) (((m & 0xFFFFFFFFL) * (long) N) >>> 32);
|
|
|
|
|
}
|
|
|
|
|
int randint2bit() { return nextU32() & 3; }
|
|
|
|
|
byte randint2bitByte() { return (byte) (nextU32() & 3); }
|
|
|
|
|
int randint(int max) { return (int) (((nextU32() & 0xFFFFFFFFL) % ((long) max - 0L + 1L))); }
|
|
|
|
|
int randint0_SIZE() { return (int) (((nextU32() & 0xFFFFFFFFL) % RANGE_0_SIZE)); }
|
|
|
|
|
int randint0_624() { return (int) (((nextU32() & 0xFFFFFFFFL) % RANGE_0_624)); }
|
|
|
|
|
double nextFloat() { return (nextU32() & 0xFFFFFFFFL) / 4294967295.0; }
|
|
|
|
|
int biasedIndexPow3(int N) { return (int) (((Math.min(nextU32(), Math.min(nextU32(), nextU32())) & 0xFFFFFFFFL) * (long) N) >>> 32); }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@AllArgsConstructor
|
|
|
|
|
static class Clues {
|
|
|
|
|
|
|
|
|
|
long lo, hi, vlo, vhi, rlo, rhi;
|
|
|
|
|
public static Clues createEmpty() {
|
|
|
|
|
return new Clues(0, 0, 0, 0, 0, 0);
|
|
|
|
|
}
|
|
|
|
|
public Clues deepCopyGrid() { return new Clues(lo, hi, vlo, vhi, rlo, rhi); }
|
|
|
|
|
public static Clues createEmpty() { return new Clues(0, 0, 0, 0, 0, 0); }
|
|
|
|
|
public Clues deepCopyGrid() { return new Clues(lo, hi, vlo, vhi, rlo, rhi); }
|
|
|
|
|
boolean clueless(int idx) {
|
|
|
|
|
if (!isClue(idx)) return false;
|
|
|
|
|
if ((idx & 64) == 0) {
|
|
|
|
|
clearClueLo(idx);
|
|
|
|
|
}else{
|
|
|
|
|
} else {
|
|
|
|
|
clearClueHi(idx);
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
@@ -260,7 +247,7 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
|
|
|
|
return (Long.bitCount(matchLo & MASK_LO) + Long.bitCount(matchHi & MASK_HI)) / SIZED;
|
|
|
|
|
}
|
|
|
|
|
public Grid toGrid() { return new Grid(new byte[SIZE], lo, hi); }
|
|
|
|
|
public void forEachSlot(SlotVisitor visitor) {
|
|
|
|
|
public void forEachSlot(SwedishGenerator.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));
|
|
|
|
|
@@ -308,10 +295,12 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
|
|
|
|
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 ThreadLocal<byte[]> BYTES = ThreadLocal.withInitial(() -> new byte[SwedishGenerator.MAX_WORD_LENGTH]);
|
|
|
|
|
public static String asWord(long word) {
|
|
|
|
|
var b = new byte[Lemma.length(word)];
|
|
|
|
|
for (var i = 0; i < b.length; i++) b[i] = (byte) ((word >>> (i * 5)) & 0b11111 | B64);
|
|
|
|
|
return new String(b, US_ASCII);
|
|
|
|
|
val len = Lemma.length(word);
|
|
|
|
|
var b = BYTES.get();//new byte[Lemma.length(word)];
|
|
|
|
|
for (int i = 0, bi = 0; i < len * 5; bi++, i += 5) b[bi] = (byte) (((word >>> i) & 31) | 64);
|
|
|
|
|
return new String(b, 0, 0, len);
|
|
|
|
|
}
|
|
|
|
|
static int unpackIndex(long w) { return (int) (w >>> 40); }
|
|
|
|
|
static int unpackLetters(long w) { return (int) (w & LETTER_MASK); }
|
|
|
|
|
@@ -330,12 +319,7 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
|
|
|
|
var entry = index[L];
|
|
|
|
|
var idx = entry.words().size();
|
|
|
|
|
entry.words().add(lemma);
|
|
|
|
|
|
|
|
|
|
for (var i = 0; i < L; i++) {
|
|
|
|
|
var letter = Lemma.byteAt(lemma, i) - 1;
|
|
|
|
|
if (letter < 0 || letter >= 26) throw new RuntimeException("Illegal letter: " + letter + " in word " + lemma);
|
|
|
|
|
entry.pos()[i][letter].add(idx);
|
|
|
|
|
}
|
|
|
|
|
for (var i = 0; i < L; i++) entry.pos()[i][Lemma.byteAt(lemma, i) - 1].add(idx);
|
|
|
|
|
}
|
|
|
|
|
for (int i = MIN_LEN; i < index.length; i++) if (index[i].words().size() <= 0) throw new RuntimeException("No words for length " + i);
|
|
|
|
|
this(Arrays.stream(index).map(i -> {
|
|
|
|
|
@@ -360,7 +344,7 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
|
|
|
|
static Dict loadDict(String wordsPath) {
|
|
|
|
|
try {
|
|
|
|
|
var map = new LongArrayList(100_000);
|
|
|
|
|
Files.lines(Path.of(wordsPath), UTF_8).forEach(line -> CsvIndexService.lineToLemma(line, map::add));
|
|
|
|
|
Files.lines(Path.of(wordsPath), StandardCharsets.UTF_8).forEach(line -> CsvIndexService.lineToLemma(line, map::add));
|
|
|
|
|
return new Dict(map.toArray());
|
|
|
|
|
} catch (IOException e) {
|
|
|
|
|
e.printStackTrace();
|
|
|
|
|
@@ -601,7 +585,8 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
|
|
|
|
Clues randomMask(final int clueSize) {
|
|
|
|
|
var g = Clues.createEmpty();
|
|
|
|
|
for (int placed = 0, guard = 0, idx; placed < clueSize && guard < 4000; guard++) {
|
|
|
|
|
idx = rng.randint(0, SIZE_MIN_1);
|
|
|
|
|
|
|
|
|
|
idx = rng.randint0_SIZE();
|
|
|
|
|
if (g.isClue(idx)) continue;
|
|
|
|
|
var d_idx = rng.randint2bitByte();
|
|
|
|
|
if (g.hasRoomForClue(OFFSETS_D_IDX[Slot.packSlotKey(idx, d_idx)])) {
|
|
|
|
|
@@ -613,9 +598,9 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
|
|
|
|
}
|
|
|
|
|
Clues mutate(Clues c) {
|
|
|
|
|
int ri;
|
|
|
|
|
var bytes = MUTATE_RI[rng.randint(0, SIZE_MIN_1)];
|
|
|
|
|
var bytes = MUTATE_RI[rng.randint0_SIZE()];
|
|
|
|
|
for (var k = 0; k < 4; k++) {
|
|
|
|
|
ri = bytes[rng.randint(0, 624)];
|
|
|
|
|
ri = bytes[rng.randint0_624()];
|
|
|
|
|
if (!c.clueless(ri)) {
|
|
|
|
|
var d_idx = rng.randint2bitByte();
|
|
|
|
|
if (c.hasRoomForClue(OFFSETS_D_IDX[Slot.packSlotKey(ri, d_idx)])) c.setClue(ri, d_idx);
|
|
|
|
|
@@ -697,8 +682,8 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
|
|
|
|
|
|
|
|
|
for (var k = 0; k < offspring; k++) {
|
|
|
|
|
if (Thread.currentThread().isInterrupted()) break;
|
|
|
|
|
var p1 = pop.get(rng.randint(0, pop.size() - 1));
|
|
|
|
|
var p2 = pop.get(rng.randint(0, pop.size() - 1));
|
|
|
|
|
var p1 = pop.get(rng.randint(pop.size() - 1));
|
|
|
|
|
var p2 = pop.get(rng.randint(pop.size() - 1));
|
|
|
|
|
var child = crossover(p1.grid, p2.grid);
|
|
|
|
|
children.add(new GridAndFit(hillclimb(child, clueSize, 70)));
|
|
|
|
|
}
|
|
|
|
|
@@ -731,39 +716,34 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
|
|
|
|
return best.grid;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static long patternForSlot(Grid grid, final int key, final long lo, final long hi) {
|
|
|
|
|
final long glo = grid.lo, ghi = grid.hi;
|
|
|
|
|
if ((lo & glo) == X && (hi & ghi) == X) {
|
|
|
|
|
static long patternForSlot(final long glo, final long ghi, final byte[] g, final int key, final long lo, final long hi) {
|
|
|
|
|
if (((lo & glo) | (hi & ghi)) == X) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
long p = 0;
|
|
|
|
|
if (Slot.increasing(key)) {
|
|
|
|
|
for (long b = lo & glo; b != X; b &= b - 1) {
|
|
|
|
|
int idx = Long.numberOfTrailingZeros(b);
|
|
|
|
|
byte val = grid.g[idx];
|
|
|
|
|
int i = Long.bitCount(lo & ((1L << idx) - 1));
|
|
|
|
|
p |= ((long) (i * 26 + val)) << (i << 3);
|
|
|
|
|
p |= ((long) (i * 26 + g[idx])) << (i << 3);
|
|
|
|
|
}
|
|
|
|
|
int offset = Long.bitCount(lo);
|
|
|
|
|
for (long b = hi & ghi; b != X; b &= b - 1) {
|
|
|
|
|
int idx = Long.numberOfTrailingZeros(b);
|
|
|
|
|
byte val = grid.g[64 | idx];
|
|
|
|
|
int i = offset + Long.bitCount(hi & ((1L << idx) - 1));
|
|
|
|
|
p |= ((long) (i * 26 + val)) << (i << 3);
|
|
|
|
|
p |= ((long) (i * 26 + g[64 | idx])) << (i << 3);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
int offset = Long.bitCount(hi);
|
|
|
|
|
for (long b = hi & ghi; b != X; b &= b - 1) {
|
|
|
|
|
int idx = Long.numberOfTrailingZeros(b);
|
|
|
|
|
byte val = grid.g[64 | idx];
|
|
|
|
|
int i = Long.bitCount(hi & ~((1L << idx) | ((1L << idx) - 1)));
|
|
|
|
|
p |= ((long) (i * 26 + val)) << (i << 3);
|
|
|
|
|
p |= ((long) (i * 26 + g[64 | idx])) << (i << 3);
|
|
|
|
|
}
|
|
|
|
|
for (long b = lo & glo; b != X; b &= b - 1) {
|
|
|
|
|
int idx = Long.numberOfTrailingZeros(b);
|
|
|
|
|
byte val = grid.g[idx];
|
|
|
|
|
int i = offset + Long.bitCount(lo & ~((1L << idx) | ((1L << idx) - 1)));
|
|
|
|
|
p |= ((long) (i * 26 + val)) << (i << 3);
|
|
|
|
|
p |= ((long) (i * 26 + g[idx])) << (i << 3);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return p;
|
|
|
|
|
@@ -774,28 +754,28 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
|
|
|
|
for (long b = hi; b != X; b &= b - 1) cross += (count[64 | Long.numberOfTrailingZeros(b)] - 1);
|
|
|
|
|
return cross * 10 + Slot.length(lo, hi);
|
|
|
|
|
}
|
|
|
|
|
static boolean placeWord(Grid grid, final int key, final long lo, final long hi, final long w) {
|
|
|
|
|
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 (grid.g[idx] != Lemma.byteAt(w, Long.bitCount(lo & ((1L << idx) - 1)))) return false;
|
|
|
|
|
if (g[idx] != Lemma.byteAt(w, Long.bitCount(lo & ((1L << idx) - 1)))) return false;
|
|
|
|
|
}
|
|
|
|
|
int bcLo = Long.bitCount(lo);
|
|
|
|
|
for (long b = hi & ghi; b != X; b &= b - 1) {
|
|
|
|
|
int idx = Long.numberOfTrailingZeros(b);
|
|
|
|
|
if (grid.g[64 | idx] != Lemma.byteAt(w, bcLo + Long.bitCount(hi & ((1L << idx) - 1)))) return false;
|
|
|
|
|
if (g[64 | idx] != Lemma.byteAt(w, bcLo + Long.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);
|
|
|
|
|
grid.g[idx] = Lemma.byteAt(w, Long.bitCount(lo & ((1L << idx) - 1)));
|
|
|
|
|
g[idx] = Lemma.byteAt(w, Long.bitCount(lo & ((1L << idx) - 1)));
|
|
|
|
|
}
|
|
|
|
|
for (long b = maskHi; b != X; b &= b - 1) {
|
|
|
|
|
int idx = Long.numberOfTrailingZeros(b);
|
|
|
|
|
grid.g[64 | idx] = Lemma.byteAt(w, bcLo + Long.bitCount(hi & ((1L << idx) - 1)));
|
|
|
|
|
g[64 | idx] = Lemma.byteAt(w, bcLo + Long.bitCount(hi & ((1L << idx) - 1)));
|
|
|
|
|
}
|
|
|
|
|
grid.lo |= maskLo;
|
|
|
|
|
grid.hi |= maskHi;
|
|
|
|
|
@@ -804,22 +784,22 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
|
|
|
|
int bcHi = Long.bitCount(hi);
|
|
|
|
|
for (long b = hi & ghi; b != X; b &= b - 1) {
|
|
|
|
|
int idx = Long.numberOfTrailingZeros(b);
|
|
|
|
|
if (grid.g[64 | idx] != Lemma.byteAt(w, Long.bitCount(hi & ~((1L << idx) | ((1L << idx) - 1))))) return false;
|
|
|
|
|
if (g[64 | idx] != Lemma.byteAt(w, Long.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 (grid.g[idx] != Lemma.byteAt(w, bcHi + Long.bitCount(lo & ~((1L << idx) | ((1L << idx) - 1))))) return false;
|
|
|
|
|
if (g[idx] != Lemma.byteAt(w, bcHi + Long.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);
|
|
|
|
|
grid.g[64 | idx] = Lemma.byteAt(w, Long.bitCount(hi & ~((1L << idx) | ((1L << idx) - 1))));
|
|
|
|
|
g[64 | idx] = Lemma.byteAt(w, Long.bitCount(hi & ~((1L << idx) | ((1L << idx) - 1))));
|
|
|
|
|
}
|
|
|
|
|
for (long b = maskLo; b != X; b &= b - 1) {
|
|
|
|
|
int idx = Long.numberOfTrailingZeros(b);
|
|
|
|
|
grid.g[idx] = Lemma.byteAt(w, bcHi + Long.bitCount(lo & ~((1L << idx) | ((1L << idx) - 1))));
|
|
|
|
|
g[idx] = Lemma.byteAt(w, bcHi + Long.bitCount(lo & ~((1L << idx) | ((1L << idx) - 1))));
|
|
|
|
|
}
|
|
|
|
|
grid.lo |= maskLo;
|
|
|
|
|
grid.hi |= maskHi;
|
|
|
|
|
@@ -900,13 +880,14 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
public static FillResult fillMask(Rng rng, Slot[] slots, Grid mask) {
|
|
|
|
|
public static SwedishGenerator.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 Bit1029();
|
|
|
|
|
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];
|
|
|
|
|
@@ -917,7 +898,7 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
|
|
|
|
|
|
|
|
|
class Solver {
|
|
|
|
|
|
|
|
|
|
private final Pick CARRIER = new Pick(null, null, 0);
|
|
|
|
|
private final SwedishGenerator.Pick CARRIER = new Pick(null, null, 0);
|
|
|
|
|
long nodes;
|
|
|
|
|
long backtracks;
|
|
|
|
|
int lastMRV;
|
|
|
|
|
@@ -949,7 +930,7 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
|
|
|
|
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, s.key, s.lo, s.hi);
|
|
|
|
|
var pattern = patternForSlot(grid.lo, grid.hi, g, s.key, s.lo, s.hi);
|
|
|
|
|
var index = s.entry;
|
|
|
|
|
count = pattern == X ? index.length : candidateCountForPattern(bitset, pattern, index.posBitsets, index.numlong);
|
|
|
|
|
|
|
|
|
|
@@ -971,7 +952,7 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
|
|
|
|
current = PICK_DONE;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
var pattern = patternForSlot(grid, best.key, best.lo, best.hi);
|
|
|
|
|
var pattern = patternForSlot(grid.lo, grid.hi, g, best.key, best.lo, best.hi);
|
|
|
|
|
var index = best.entry;
|
|
|
|
|
current = CARRIER;
|
|
|
|
|
current.slot = best;
|
|
|
|
|
@@ -1017,18 +998,18 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
|
|
|
|
var idx = idxs[idxInArray];
|
|
|
|
|
var w = entry.words[idx];
|
|
|
|
|
var lemIdx = Lemma.unpackIndex(w);
|
|
|
|
|
if (used.get(lemIdx)) continue;
|
|
|
|
|
if (Bit1029.get(used, lemIdx)) continue;
|
|
|
|
|
low = grid.lo;
|
|
|
|
|
top = grid.hi;
|
|
|
|
|
if (!placeWord(grid, k, slo, shi, w)) continue;
|
|
|
|
|
if (!placeWord(grid, g, k, slo, shi, w)) continue;
|
|
|
|
|
|
|
|
|
|
used.set(lemIdx);
|
|
|
|
|
Bit1029.set(used, lemIdx);
|
|
|
|
|
assigned[k] = w;
|
|
|
|
|
|
|
|
|
|
if (backtrack(depth + 1)) return true;
|
|
|
|
|
|
|
|
|
|
assigned[k] = X;
|
|
|
|
|
used.clear(lemIdx);
|
|
|
|
|
Bit1029.clear(used, lemIdx);
|
|
|
|
|
grid.lo = low;
|
|
|
|
|
grid.hi = top;
|
|
|
|
|
}
|
|
|
|
|
@@ -1044,18 +1025,18 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
|
|
|
|
int idxInArray = (int) (r * r * r * (N - 1));
|
|
|
|
|
var w = entry.words[idxInArray];
|
|
|
|
|
var lemIdx = Lemma.unpackIndex(w);
|
|
|
|
|
if (used.get(lemIdx)) continue;
|
|
|
|
|
if (Bit1029.get(used, lemIdx)) continue;
|
|
|
|
|
low = grid.lo;
|
|
|
|
|
top = grid.hi;
|
|
|
|
|
if (!placeWord(grid, k, slo, shi, w)) continue;
|
|
|
|
|
if (!placeWord(grid, g, k, slo, shi, w)) continue;
|
|
|
|
|
|
|
|
|
|
used.set(lemIdx);
|
|
|
|
|
Bit1029.set(used, lemIdx);
|
|
|
|
|
assigned[k] = w;
|
|
|
|
|
|
|
|
|
|
if (backtrack(depth + 1)) return true;
|
|
|
|
|
|
|
|
|
|
assigned[k] = X;
|
|
|
|
|
used.clear(lemIdx);
|
|
|
|
|
Bit1029.clear(used, lemIdx);
|
|
|
|
|
grid.lo = low;
|
|
|
|
|
grid.hi = top;
|
|
|
|
|
}
|
|
|
|
|
@@ -1071,7 +1052,8 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
|
|
|
|
var ok = solver.backtrack(0);
|
|
|
|
|
// final progress line
|
|
|
|
|
|
|
|
|
|
var res = new FillResult(ok, new Gridded(grid), assigned, new FillStats(solver.nodes, solver.backtracks, (System.currentTimeMillis() - t0) / 1000.0, solver.lastMRV));
|
|
|
|
|
var res = new FillResult(ok, new Gridded(grid), assigned,
|
|
|
|
|
new SwedishGenerator.FillStats(solver.nodes, solver.backtracks, (System.currentTimeMillis() - t0) / 1000.0, solver.lastMRV));
|
|
|
|
|
if (!multiThreaded) {
|
|
|
|
|
System.out.print("\r" + Strings.padRight("", 120) + "\r");
|
|
|
|
|
System.out.flush();
|
|
|
|
|
|