Gather data
This commit is contained in:
6
pom.xml
6
pom.xml
@@ -41,6 +41,12 @@
|
||||
<version>2.0.13</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter</artifactId>
|
||||
<version>RELEASE</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
||||
@@ -78,9 +78,11 @@ public record SwedishGenerator(int W, int H, int SIZE, int MAX_LEN, int[] buff)
|
||||
int[] covV,
|
||||
int[] cellCount,
|
||||
int[] stack,
|
||||
BitSet seen) {
|
||||
BitSet seen,
|
||||
char[] pattern,
|
||||
IntList[] intListBuffer) {
|
||||
|
||||
public Context() { this(new int[256], new int[256], new int[256], new int[256], new BitSet(256)); }
|
||||
public Context() { this(new int[256], new int[256], new int[256], new int[256], new BitSet(256), new char[32], new IntList[32]); }
|
||||
}
|
||||
|
||||
static final ThreadLocal<Context> CTX = ThreadLocal.withInitial(Context::new);
|
||||
@@ -278,28 +280,28 @@ public record SwedishGenerator(int W, int H, int SIZE, int MAX_LEN, int[] buff)
|
||||
return Arrays.copyOf(buff, k);
|
||||
}
|
||||
|
||||
CandidateInfo candidateInfoForPattern(DictEntry entry, char[] pattern) {
|
||||
var lists = new ArrayList<IntList>();
|
||||
for (var i = 0; i < pattern.length; i++) {
|
||||
CandidateInfo candidateInfoForPattern(DictEntry entry, char[] pattern, int len) {
|
||||
var ctx = CTX.get();
|
||||
var listBuffer = ctx.intListBuffer;
|
||||
int listCount = 0;
|
||||
for (var i = 0; i < len; i++) {
|
||||
var ch = pattern[i];
|
||||
if (isLetter(ch)) {
|
||||
lists.add(entry.pos[i][ch - 'A']);
|
||||
listBuffer[listCount++] = entry.pos[i][ch - 'A'];
|
||||
}
|
||||
}
|
||||
|
||||
if (lists.isEmpty()) {
|
||||
if (listCount == 0) {
|
||||
return new CandidateInfo(null, entry.words.size());
|
||||
}
|
||||
|
||||
var first = lists.get(0);
|
||||
var cur = first.data();//Arrays.copyOf(first.data(), first.size());
|
||||
var curLen = cur.length;
|
||||
var first = listBuffer[0];
|
||||
var cur = first.data();
|
||||
var curLen = first.size();
|
||||
|
||||
for (var k = 1; k < lists.size(); k++) {
|
||||
var nxt = lists.get(k);
|
||||
var nextArr = nxt.data();
|
||||
var nextLen = nxt.size();
|
||||
cur = intersectSorted(buff, cur, curLen, nextArr, nextLen);
|
||||
for (var k = 1; k < listCount; k++) {
|
||||
var nxt = listBuffer[k];
|
||||
cur = intersectSorted(buff, cur, curLen, nxt.data(), nxt.size());
|
||||
curLen = cur.length;
|
||||
if (curLen == 0) break;
|
||||
}
|
||||
@@ -312,13 +314,22 @@ public record SwedishGenerator(int W, int H, int SIZE, int MAX_LEN, int[] buff)
|
||||
public int clueR() { return (key >> 8) & 15; }
|
||||
public int clueC() { return (key >> 4) & 15; }
|
||||
public int dir() { return key & 15; }
|
||||
public boolean horiz() { return (dir() & 1) == 0; }
|
||||
public int r(int i) { return (int) ((rs >> (i << 2)) & 15); }
|
||||
public int c(int i) { return (int) ((cs >> (i << 2)) & 15); }
|
||||
public boolean horiz() { return horiz(key); }
|
||||
public int r(int i) { return r(rs, i); }
|
||||
public int c(int i) { return c(cs, i); }
|
||||
|
||||
public static boolean horiz(int key) { return ((key & 15) & 1) == 0; }
|
||||
public static int r(long rs, int i) { return (int) ((rs >> (i << 2)) & 15); }
|
||||
public static int c(long cs, int i) { return (int) ((cs >> (i << 2)) & 15); }
|
||||
}
|
||||
|
||||
ArrayList<Slot> extractSlots(Grid grid) {
|
||||
var slots = new ArrayList<Slot>(64);
|
||||
@FunctionalInterface
|
||||
interface SlotVisitor {
|
||||
|
||||
void visit(int key, long rs, long cs, int len);
|
||||
}
|
||||
|
||||
void forEachSlot(Grid grid, SlotVisitor visitor) {
|
||||
for (var r = 0; r < H; r++) {
|
||||
for (var c = 0; c < W; c++) {
|
||||
if (!grid.isDigitAt(r, c)) continue;
|
||||
@@ -343,9 +354,16 @@ public record SwedishGenerator(int W, int H, int SIZE, int MAX_LEN, int[] buff)
|
||||
cc += dc;
|
||||
if (n >= 12) break;
|
||||
}
|
||||
slots.add(new Slot((r << 8) | (c << 4) | d, packedRs, packedCs,n ));
|
||||
if (n > 0) {
|
||||
visitor.visit((r << 8) | (c << 4) | d, packedRs, packedCs, n);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ArrayList<Slot> extractSlots(Grid grid) {
|
||||
var slots = new ArrayList<Slot>(64);
|
||||
forEachSlot(grid, (key, rs, cs, len) -> slots.add(new Slot(key, rs, cs, len)));
|
||||
return slots;
|
||||
}
|
||||
|
||||
@@ -372,35 +390,59 @@ public record SwedishGenerator(int W, int H, int SIZE, int MAX_LEN, int[] buff)
|
||||
var targetClues = (int) Math.round(SIZE * 0.25); // ~18
|
||||
penalty += 8L * Math.abs(clueCount - targetClues);
|
||||
|
||||
var slots = extractSlots(grid);
|
||||
if (slots.isEmpty()) return 1_000_000_000L;
|
||||
|
||||
var ctx = CTX.get();
|
||||
var covH = ctx.covH;
|
||||
var covV = ctx.covV;
|
||||
Arrays.fill(covH, 0, SIZE, 0);
|
||||
Arrays.fill(covV, 0, SIZE, 0);
|
||||
|
||||
for (var s : slots) {
|
||||
if (s.len() < MIN_LEN) {
|
||||
penalty += 8000;
|
||||
}
|
||||
/* else if (s.len > MAX_LEN) {
|
||||
penalty += 8000 + (long) (s.len - MAX_LEN) * 500L;
|
||||
throw new RuntimeException();
|
||||
}*/
|
||||
else {
|
||||
if (lenCounts[s.len()] <= 0) penalty += 12000;
|
||||
}
|
||||
|
||||
for (var i = 0; i < s.len(); i++) {
|
||||
int r = s.r(i), c = s.c(i);
|
||||
int idx = grid.offset(r, c);
|
||||
if (s.horiz()) covH[idx] += 1;
|
||||
else covV[idx] += 1;
|
||||
boolean hasSlots = false;
|
||||
for (var r = 0; r < H; r++) {
|
||||
for (var c = 0; c < W; c++) {
|
||||
if (!grid.isDigitAt(r, c)) continue;
|
||||
var d = grid.digitAt(r, c);
|
||||
int or = OFFSETS[d].x, oc = OFFSETS[d].y;
|
||||
int dr = STEPS[d].x, dc = STEPS[d].y;
|
||||
|
||||
int rr = r + or, cc = c + oc;
|
||||
if (rr < 0 || rr >= H || cc < 0 || cc >= W) continue;
|
||||
if (grid.isDigitAt(rr, cc)) continue;
|
||||
|
||||
long packedRs = 0;
|
||||
long packedCs = 0;
|
||||
var n = 0;
|
||||
|
||||
while (rr >= 0 && rr < H && cc >= 0 && cc < W) {
|
||||
if (grid.isDigitAt(rr, cc)) break;
|
||||
packedRs |= (long) rr << (n << 2);
|
||||
packedCs |= (long) cc << (n << 2);
|
||||
n++;
|
||||
rr += dr;
|
||||
cc += dc;
|
||||
if (n >= 12) break;
|
||||
}
|
||||
if (n == 0) continue;
|
||||
hasSlots = true;
|
||||
|
||||
if (n < MIN_LEN) {
|
||||
penalty += 8000;
|
||||
} else {
|
||||
if (lenCounts[n] <= 0) penalty += 12000;
|
||||
}
|
||||
|
||||
boolean horiz = Slot.horiz((r << 8) | (c << 4) | d);
|
||||
for (var i = 0; i < n; i++) {
|
||||
int sr = Slot.r(packedRs, i);
|
||||
int sc = Slot.c(packedCs, i);
|
||||
int idx = grid.offset(sr, sc);
|
||||
if (horiz) covH[idx] += 1;
|
||||
else covV[idx] += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasSlots) return 1_000_000_000L;
|
||||
|
||||
for (var r = 0; r < H; r++)
|
||||
for (var c = 0; c < W; c++) {
|
||||
if (grid.isDigitAt(r, c)) continue;
|
||||
@@ -636,13 +678,12 @@ public record SwedishGenerator(int W, int H, int SIZE, int MAX_LEN, int[] buff)
|
||||
}
|
||||
}
|
||||
|
||||
static char[] patternForSlot(Grid grid, Slot s) {
|
||||
var pat = new char[s.len()];
|
||||
static int patternForSlot(Grid grid, Slot s, char[] pat) {
|
||||
for (var i = 0; i < s.len(); i++) {
|
||||
var ch = grid.getCharAt(s.r(i), s.c(i));
|
||||
if (isLetter(ch)) pat[i] = ch;
|
||||
pat[i] = isLetter(ch) ? ch : C_DASH;
|
||||
}
|
||||
return pat;
|
||||
return s.len();
|
||||
}
|
||||
|
||||
static int slotScore(int[] cellCount, Slot s, Grid grid) {
|
||||
@@ -733,8 +774,8 @@ public record SwedishGenerator(int W, int H, int SIZE, int MAX_LEN, int[] buff)
|
||||
return new Pick(null, null, false);
|
||||
}
|
||||
|
||||
var pat = patternForSlot(grid, s);
|
||||
var info = candidateInfoForPattern(entry, pat);
|
||||
var patLen = patternForSlot(grid, s, ctx.pattern);
|
||||
var info = candidateInfoForPattern(entry, ctx.pattern, patLen);
|
||||
|
||||
if (info.count == 0) {
|
||||
return new Pick(null, null, false);
|
||||
@@ -778,29 +819,8 @@ public record SwedishGenerator(int W, int H, int SIZE, int MAX_LEN, int[] buff)
|
||||
var s = pick.slot;
|
||||
var k = s.key();
|
||||
var entry = dictIndex[s.len()];
|
||||
var pat = patternForSlot(grid, s);
|
||||
|
||||
Predicate<Lemma> tryWord = (Lemma w) -> {
|
||||
if (used.get(w.index())) return false;
|
||||
|
||||
for (var i = 0; i < pat.length; i++) {
|
||||
// if ((pat[i] != w.charAt(i)) != (pat[i] != C_DASH)) throw new RuntimeException("word does not match pattern");
|
||||
if (pat[i] != C_DASH && pat[i] != w.charAt(i)) return false;
|
||||
}
|
||||
|
||||
var undo = placeWord(grid, s, w);
|
||||
if (undo == null) return false;
|
||||
|
||||
used.set(w.index());
|
||||
assigned.put(k, w);
|
||||
|
||||
if (backtrack()) return true;
|
||||
|
||||
assigned.remove(k);
|
||||
used.set(w.index, false);
|
||||
undoPlace(grid, undo);
|
||||
return false;
|
||||
};
|
||||
var pat = new char[s.len()];
|
||||
patternForSlot(grid, s, pat);
|
||||
|
||||
if (pick.info.indices != null && pick.info.indices.length > 0) {
|
||||
var idxs = pick.info.indices;
|
||||
@@ -815,7 +835,29 @@ public record SwedishGenerator(int W, int H, int SIZE, int MAX_LEN, int[] buff)
|
||||
int idxInArray = (int) (r * r * r * L);
|
||||
var idx = idxs[idxInArray];
|
||||
var w = entry.words.get(idx);
|
||||
if (tryWord.test(w)) return true;
|
||||
|
||||
if (used.get(w.index())) continue;
|
||||
|
||||
boolean match = true;
|
||||
for (var i = 0; i < pat.length; i++) {
|
||||
if (pat[i] != C_DASH && pat[i] != w.charAt(i)) {
|
||||
match = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!match) continue;
|
||||
|
||||
var undo = placeWord(grid, s, w);
|
||||
if (undo == null) continue;
|
||||
|
||||
used.set(w.index());
|
||||
assigned.put(k, w);
|
||||
|
||||
if (backtrack()) return true;
|
||||
|
||||
assigned.remove(k);
|
||||
used.set(w.index, false);
|
||||
undoPlace(grid, undo);
|
||||
}
|
||||
stats.backtracks++;
|
||||
return false;
|
||||
@@ -832,7 +874,29 @@ public record SwedishGenerator(int W, int H, int SIZE, int MAX_LEN, int[] buff)
|
||||
double r = rng.nextFloat();
|
||||
int idxInArray = (int) (r * r * r * N);
|
||||
var w = entry.words.get(idxInArray);
|
||||
if (tryWord.test(w)) return true;
|
||||
|
||||
if (used.get(w.index())) continue;
|
||||
|
||||
boolean match = true;
|
||||
for (var i = 0; i < pat.length; i++) {
|
||||
if (pat[i] != C_DASH && pat[i] != w.charAt(i)) {
|
||||
match = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!match) continue;
|
||||
|
||||
var undo = placeWord(grid, s, w);
|
||||
if (undo == null) continue;
|
||||
|
||||
used.set(w.index());
|
||||
assigned.put(k, w);
|
||||
|
||||
if (backtrack()) return true;
|
||||
|
||||
assigned.remove(k);
|
||||
used.set(w.index, false);
|
||||
undoPlace(grid, undo);
|
||||
}
|
||||
|
||||
stats.backtracks++;
|
||||
|
||||
Reference in New Issue
Block a user