Gather data
This commit is contained in:
@@ -26,7 +26,7 @@ import java.util.function.Supplier;
|
||||
* java SwedishGenerator [--seed N] [--pop N] [--gens N] [--tries N] [--words word-list.txt]
|
||||
*/
|
||||
@SuppressWarnings("ALL")
|
||||
public record SwedishGenerator(int[] buff) {
|
||||
public record SwedishGenerator() {
|
||||
|
||||
record CandidateInfo(int[] indices, int count) { }
|
||||
|
||||
@@ -39,20 +39,7 @@ public record SwedishGenerator(int[] buff) {
|
||||
}
|
||||
}
|
||||
|
||||
record rci(int r, int c, int i, long n1, long n2) {
|
||||
void forEachSetBit71(java.util.function.IntConsumer consumer) {
|
||||
long lo = n1, hi = n2;
|
||||
while (lo != 0L) {
|
||||
int bit = Long.numberOfTrailingZeros(lo);
|
||||
consumer.accept(bit);
|
||||
lo &= (lo - 1);
|
||||
}
|
||||
while (hi != 0L) {
|
||||
int bit = Long.numberOfTrailingZeros(hi);
|
||||
consumer.accept(64 + bit);
|
||||
hi &= (hi - 1L);
|
||||
}
|
||||
}
|
||||
record rci(int r, int c, int i, long n1, long n2, int nbrCount, long n8_1, long n8_2) {
|
||||
}
|
||||
|
||||
static final int BAR_LEN = 22;
|
||||
@@ -74,7 +61,8 @@ public record SwedishGenerator(int[] buff) {
|
||||
static boolean isLetter(byte b) { return (b & 64) != 0; }
|
||||
static int clamp(int x, int a, int b) { return Math.max(a, Math.min(b, x)); }
|
||||
|
||||
public SwedishGenerator() { this(new int[8124]); }
|
||||
public SwedishGenerator() { }
|
||||
public SwedishGenerator(int[] buff) { this(); }
|
||||
|
||||
// Directions for '1'..'6'
|
||||
static final nbrs_16[] OFFSETS = new nbrs_16[]{
|
||||
@@ -103,11 +91,11 @@ public record SwedishGenerator(int[] buff) {
|
||||
new nbrs_8(0, 1)
|
||||
};
|
||||
|
||||
static final rci[] IT = new rci[SIZE];
|
||||
static final rci[] IT = new rci[SIZE];
|
||||
static {
|
||||
for (int i = 0; i < SIZE; i++) {
|
||||
int r = i % R;
|
||||
int c = i / R;
|
||||
int r = i % R;
|
||||
int c = i / R;
|
||||
long n1 = 0, n2 = 0;
|
||||
for (var d : nbrs4) {
|
||||
int nr = r + d.r;
|
||||
@@ -118,10 +106,20 @@ public record SwedishGenerator(int[] buff) {
|
||||
else n2 |= (1L << (nidx - 64));
|
||||
}
|
||||
}
|
||||
IT[i] = new rci(r, c, i, n1, n2);
|
||||
long n8_1 = 0, n8_2 = 0;
|
||||
for (var d : nbrs8) {
|
||||
int nr = r + d.r;
|
||||
int nc = c + d.c;
|
||||
if (nr >= 0 && nr < R && nc >= 0 && nc < C) {
|
||||
int nidx = nc * R + nr;
|
||||
if (nidx < 64) n8_1 |= (1L << nidx);
|
||||
else n8_2 |= (1L << (nidx - 64));
|
||||
}
|
||||
}
|
||||
IT[i] = new rci(r, c, i, n1, n2, (int) (Long.bitCount(n1) + Long.bitCount(n2)), n8_1, n8_2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static record Context(int[] covH,
|
||||
int[] covV,
|
||||
int[] cellCount,
|
||||
@@ -129,11 +127,13 @@ public record SwedishGenerator(int[] buff) {
|
||||
Bit seen,
|
||||
byte[] pattern,
|
||||
IntList[] intListBuffer,
|
||||
int[] undo) {
|
||||
int[] undo,
|
||||
int[] inter1,
|
||||
int[] inter2) {
|
||||
|
||||
public Context() {
|
||||
this(new int[SIZE], new int[SIZE], new int[SIZE], new int[SIZE], new Bit(), new byte[MAX_WORD_LENGTH], new IntList[MAX_WORD_LENGTH],
|
||||
new int[2048]);
|
||||
new int[2048], new int[160000], new int[160000]);
|
||||
}
|
||||
void setPatter(byte[] chars) { System.arraycopy(chars, 0, this.pattern, 0, chars.length); }
|
||||
}
|
||||
@@ -334,22 +334,21 @@ public record SwedishGenerator(int[] buff) {
|
||||
}
|
||||
}
|
||||
|
||||
return new Dict(map .toArray(Lemma[]::new));
|
||||
return new Dict(map.toArray(Lemma[]::new));
|
||||
}
|
||||
static int[] intersectSorted(int[] buff, int[] a, int aLen, int[] b, int bLen) {
|
||||
//var out = new int[Math.min(aLen, bLen)];
|
||||
int i = 0, j = 0, k = 0, x = 0, y = 0;
|
||||
static int intersectSorted(int[] a, int aLen, int[] b, int bLen, int[] out) {
|
||||
int i = 0, j = 0, k = 0;
|
||||
while (i < aLen && j < bLen) {
|
||||
x = a[i];
|
||||
y = b[j];
|
||||
int x = a[i];
|
||||
int y = b[j];
|
||||
if (x == y) {
|
||||
buff[k++] = x;
|
||||
out[k++] = x;
|
||||
i++;
|
||||
j++;
|
||||
} else if (x < y) i++;
|
||||
else j++;
|
||||
}
|
||||
return Arrays.copyOf(buff, k);
|
||||
return k;
|
||||
}
|
||||
|
||||
CandidateInfo candidateInfoForPattern(Context ctx, DictEntry entry, int len) {
|
||||
@@ -378,18 +377,24 @@ public record SwedishGenerator(int[] buff) {
|
||||
}
|
||||
}
|
||||
|
||||
var first = listBuffer[0];
|
||||
var cur = first.data();
|
||||
var curLen = first.size();
|
||||
var cur = listBuffer[0].data();
|
||||
var curLen = listBuffer[0].size();
|
||||
if (listCount == 1) return new CandidateInfo(cur, curLen);
|
||||
|
||||
int[] b1 = ctx.inter1;
|
||||
int[] b2 = ctx.inter2;
|
||||
int[] in = cur;
|
||||
int[] out = b1;
|
||||
|
||||
for (var k = 1; k < listCount; k++) {
|
||||
var nxt = listBuffer[k];
|
||||
cur = intersectSorted(buff, cur, curLen, nxt.data(), nxt.size());
|
||||
curLen = cur.length;
|
||||
curLen = intersectSorted(in, curLen, nxt.data(), nxt.size(), out);
|
||||
in = out;
|
||||
out = (out == b1) ? b2 : b1;
|
||||
if (curLen == 0) break;
|
||||
}
|
||||
|
||||
return new CandidateInfo(cur, curLen);
|
||||
return new CandidateInfo(in, curLen);
|
||||
}
|
||||
static record Slot(int key, long packedPos) {
|
||||
|
||||
@@ -421,24 +426,37 @@ public record SwedishGenerator(int[] buff) {
|
||||
}
|
||||
|
||||
void forEachSlot(Grid grid, SlotVisitor visitor) {
|
||||
grid.forEachSetBit71(idx -> {
|
||||
var d = grid.digitAt(idx);
|
||||
var nbrs16 = OFFSETS[d];
|
||||
int r = Grid.r(idx), c = Grid.c(idx), rr = r + nbrs16.r, cc = c + nbrs16.c;
|
||||
if (rr < 0 || rr >= R || cc < 0 || cc >= C || grid.isDigitAt(rr, cc)) return;
|
||||
long packedPos = 0;
|
||||
var n = 0;
|
||||
|
||||
while (rr >= 0 && rr < R && cc >= 0 && cc < C && grid.isLettercell(rr, cc) && n < MAX_WORD_LENGTH) {
|
||||
packedPos |= (long) Grid.offset(rr, cc) << (n * 7);
|
||||
n++;
|
||||
rr += nbrs16.dr;
|
||||
cc += nbrs16.dc;
|
||||
}
|
||||
if (n > 0) {
|
||||
visitor.visit((idx << 4) | d, packedPos, n);
|
||||
}
|
||||
});
|
||||
long lo = grid.bo[0], hi = grid.bo[1];
|
||||
int idx;
|
||||
while (lo != 0) {
|
||||
idx = Long.numberOfTrailingZeros(lo);
|
||||
lo &= (lo - 1);
|
||||
processSlot(grid, visitor, idx);
|
||||
}
|
||||
while (hi != 0) {
|
||||
idx = 64 + Long.numberOfTrailingZeros(hi);
|
||||
hi &= (hi - 1);
|
||||
processSlot(grid, visitor, idx);
|
||||
}
|
||||
}
|
||||
|
||||
private void processSlot(Grid grid, SlotVisitor visitor, int idx) {
|
||||
var d = grid.digitAt(idx);
|
||||
var nbrs16 = OFFSETS[d];
|
||||
int r = Grid.r(idx), c = Grid.c(idx), rr = r + nbrs16.r, cc = c + nbrs16.c;
|
||||
if (rr < 0 || rr >= R || cc < 0 || cc >= C || grid.isDigitAt(rr, cc)) return;
|
||||
long packedPos = 0;
|
||||
var n = 0;
|
||||
|
||||
while (rr >= 0 && rr < R && cc >= 0 && cc < C && grid.isLettercell(rr, cc) && n < MAX_WORD_LENGTH) {
|
||||
packedPos |= (long) Grid.offset(rr, cc) << (n * 7);
|
||||
n++;
|
||||
rr += nbrs16.dr;
|
||||
cc += nbrs16.dc;
|
||||
}
|
||||
if (n > 0) {
|
||||
visitor.visit((idx << 4) | d, packedPos, n);
|
||||
}
|
||||
}
|
||||
|
||||
ArrayList<Slot> extractSlots(Grid grid) {
|
||||
@@ -471,15 +489,18 @@ public record SwedishGenerator(int[] buff) {
|
||||
Arrays.fill(covV, 0, SIZE, 0);
|
||||
|
||||
boolean[] hasSlots = { false };
|
||||
grid.forEachSetBit71(clueIdx -> {
|
||||
long lo_cl = grid.bo[0], hi_cl = grid.bo[1];
|
||||
while (lo_cl != 0) {
|
||||
int clueIdx = Long.numberOfTrailingZeros(lo_cl);
|
||||
lo_cl &= (lo_cl - 1);
|
||||
|
||||
var d = grid.digitAt(clueIdx);
|
||||
var nbrs16 = OFFSETS[d];
|
||||
int rr = Grid.r(clueIdx) + nbrs16.r, cc = Grid.c(clueIdx) + nbrs16.c;
|
||||
if (rr < 0 || rr >= R || cc < 0 || cc >= C || grid.isDigitAt(rr, cc)) return;
|
||||
if (rr < 0 || rr >= R || cc < 0 || cc >= C || grid.isDigitAt(rr, cc)) continue;
|
||||
|
||||
long packedPos = 0;
|
||||
var n = 0;
|
||||
|
||||
while (rr >= 0 && rr < R && cc >= 0 && cc < C && n < MAX_WORD_LENGTH) {
|
||||
if (grid.isDigitAt(rr, cc)) break;
|
||||
packedPos |= (long) Grid.offset(rr, cc) << (n * 7);
|
||||
@@ -487,28 +508,47 @@ public record SwedishGenerator(int[] buff) {
|
||||
rr += nbrs16.dr;
|
||||
cc += nbrs16.dc;
|
||||
}
|
||||
if (n == 0) return;
|
||||
if (n == 0) continue;
|
||||
hasSlots[0] = true;
|
||||
|
||||
if (n < MIN_LEN) {
|
||||
penalty[0] += 8000;
|
||||
} else {
|
||||
if (lenCounts[n] <= 0) penalty[0] += 12000;
|
||||
} else if (lenCounts[n] <= 0) {
|
||||
penalty[0] += 12000;
|
||||
}
|
||||
|
||||
var horiz = Slot.horiz(d) ? covH : covV;
|
||||
for (var i = 0; i < n; i++) horiz[Slot.offset(packedPos, i)] += 1;
|
||||
});
|
||||
}
|
||||
while (hi_cl != 0) {
|
||||
int clueIdx = 64 + Long.numberOfTrailingZeros(hi_cl);
|
||||
hi_cl &= (hi_cl - 1);
|
||||
|
||||
var d = grid.digitAt(clueIdx);
|
||||
var nbrs16 = OFFSETS[d];
|
||||
int rr = Grid.r(clueIdx) + nbrs16.r, cc = Grid.c(clueIdx) + nbrs16.c;
|
||||
if (rr < 0 || rr >= R || cc < 0 || cc >= C || grid.isDigitAt(rr, cc)) continue;
|
||||
|
||||
long packedPos = 0;
|
||||
var n = 0;
|
||||
while (rr >= 0 && rr < R && cc >= 0 && cc < C && n < MAX_WORD_LENGTH) {
|
||||
if (grid.isDigitAt(rr, cc)) break;
|
||||
packedPos |= (long) Grid.offset(rr, cc) << (n * 7);
|
||||
n++;
|
||||
rr += nbrs16.dr;
|
||||
cc += nbrs16.dc;
|
||||
}
|
||||
if (n == 0) continue;
|
||||
hasSlots[0] = true;
|
||||
if (n < MIN_LEN) {
|
||||
penalty[0] += 8000;
|
||||
} else if (lenCounts[n] <= 0) {
|
||||
penalty[0] += 12000;
|
||||
}
|
||||
var horiz = Slot.horiz(d) ? covH : covV;
|
||||
for (var i = 0; i < n; i++) horiz[Slot.offset(packedPos, i)] += 1;
|
||||
}
|
||||
|
||||
if (!hasSlots[0]) return 1_000_000_000L;
|
||||
|
||||
/* grid.forEachSetBit71(clueIdx -> {
|
||||
var h = covH[clueIdx];
|
||||
var v = covV[clueIdx];
|
||||
if (h == 0 && v == 0) penalty[0] += 1500;
|
||||
else if (h > 0 && v > 0) { *//* ok *//* } else if (h + v == 1) penalty[0] += 200;
|
||||
else penalty[0] += 600;
|
||||
});*/
|
||||
int idx, h, v;
|
||||
for (idx = 0; idx < SIZE; idx++) {
|
||||
if (grid.isDigitAt(idx)) continue;
|
||||
@@ -549,26 +589,13 @@ public record SwedishGenerator(int[] buff) {
|
||||
|
||||
if (size >= 2) penalty[0] += (size - 1L) * 120L;
|
||||
});
|
||||
int sp, nr, nc;
|
||||
long size;
|
||||
int walls;
|
||||
int walls;
|
||||
// dead-end-ish letter cell (3+ walls)
|
||||
for (var rci : IT) {
|
||||
if (grid.isDigitAt(rci.i)) continue;
|
||||
walls = 4 - Long.bitCount(rci.n1) - Long.bitCount(rci.n2);
|
||||
walls += Long.bitCount(rci.n1 & grid.bo[0]) + Long.bitCount(rci.n2 & grid.bo[1]);
|
||||
walls = (4 - rci.nbrCount) + Long.bitCount(rci.n1 & grid.bo[0]) + Long.bitCount(rci.n2 & grid.bo[1]);
|
||||
if (walls >= 3) penalty[0] += 400;
|
||||
}
|
||||
/*for (var rci : IT) {
|
||||
if (grid.isDigitAt(rci.i)) continue;
|
||||
walls = 0;
|
||||
for (var d : nbrs4) {
|
||||
wr = rci.r + d.r;
|
||||
wc = rci.c + d.c;
|
||||
if (wr < 0 || wr >= R || wc < 0 || wc >= C || grid.isDigitAt(wr, wc)) walls++;
|
||||
}
|
||||
if (walls >= 3) penalty[0] += 400;
|
||||
}*/
|
||||
return penalty[0];
|
||||
}
|
||||
|
||||
@@ -789,8 +816,7 @@ public record SwedishGenerator(int[] buff) {
|
||||
if ((now - lastLog.get()) < logEveryMs) return;
|
||||
lastLog.set(now);
|
||||
|
||||
var done = assigned.size();
|
||||
// if (done!=grid.clueCount())throw new RuntimeException();
|
||||
var done = assigned.size();
|
||||
var pct = (TOTAL == 0) ? 100 : (int) Math.floor((done / (double) TOTAL) * 100);
|
||||
var filled = Math.min(BAR_LEN, (int) Math.floor((pct / 100.0) * BAR_LEN));
|
||||
var bar = "[" + "#".repeat(filled) + "-".repeat(BAR_LEN - filled) + "]";
|
||||
@@ -811,9 +837,6 @@ public record SwedishGenerator(int[] buff) {
|
||||
int bestSlot = -1;
|
||||
for (var s : slots) {
|
||||
if (assigned.containsKey(s.key())) continue;
|
||||
/* if (assigned.size()!= grid.clueCount())
|
||||
throw new RuntimeException();*/
|
||||
|
||||
var entry = dictIndex[s.len()];
|
||||
if (entry == null) return PICK_NOT_DONE;
|
||||
patternForSlot(grid, s, ctx.pattern);
|
||||
@@ -826,7 +849,11 @@ public record SwedishGenerator(int[] buff) {
|
||||
|| (info.count == bestInfo.count && (slotScore = slotScore(count, s)) > bestSlot)) {
|
||||
best = s;
|
||||
bestSlot = (slotScore != -1) ? slotScore : slotScore(count, s);
|
||||
bestInfo = info;
|
||||
if (info.indices != null && (info.indices == ctx.inter1 || info.indices == ctx.inter2)) {
|
||||
bestInfo = new CandidateInfo(Arrays.copyOf(info.indices, info.count), info.count);
|
||||
} else {
|
||||
bestInfo = info;
|
||||
}
|
||||
if (info.count <= 1) break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -159,13 +159,15 @@ public class SwedishGeneratorTest {
|
||||
var a = new int[]{ 1, 3, 5, 7, 9 };
|
||||
var b = new int[]{ 2, 3, 6, 7, 10 };
|
||||
|
||||
var res = SwedishGenerator.intersectSorted(buff, a, a.length, b, b.length);
|
||||
assertArrayEquals(new int[]{ 3, 7 }, res);
|
||||
var count = SwedishGenerator.intersectSorted(a, a.length, b, b.length, buff);
|
||||
assertEquals(2, count);
|
||||
assertEquals(3, buff[0]);
|
||||
assertEquals(7, buff[1]);
|
||||
|
||||
var c = new int[]{ 1, 2, 3 };
|
||||
var d = new int[]{ 4, 5, 6 };
|
||||
res = SwedishGenerator.intersectSorted(buff, c, c.length, d, d.length);
|
||||
assertEquals(0, res.length);
|
||||
count = SwedishGenerator.intersectSorted(c, c.length, d, d.length, buff);
|
||||
assertEquals(0, count);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user