Gather data

This commit is contained in:
mike
2026-01-09 20:02:22 +01:00
parent a2cdddccd9
commit dc331fc96b
2 changed files with 125 additions and 96 deletions

View File

@@ -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;
}
}

View File

@@ -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