Gather data
This commit is contained in:
@@ -2,13 +2,15 @@ package puzzle;
|
|||||||
|
|
||||||
import puzzle.Main.PuzzleResult;
|
import puzzle.Main.PuzzleResult;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import static puzzle.SwedishGenerator.H;
|
import static puzzle.SwedishGenerator.R;
|
||||||
import static puzzle.SwedishGenerator.Lemma;
|
import static puzzle.SwedishGenerator.Lemma;
|
||||||
|
import static puzzle.SwedishGenerator.SIZE;
|
||||||
import static puzzle.SwedishGenerator.Slot;
|
import static puzzle.SwedishGenerator.Slot;
|
||||||
import static puzzle.SwedishGenerator.W;
|
import static puzzle.SwedishGenerator.C;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ExportFormat.java
|
* ExportFormat.java
|
||||||
@@ -19,19 +21,34 @@ import static puzzle.SwedishGenerator.W;
|
|||||||
* - crops to bounding box (words + arrow cells) with 1-cell margin
|
* - crops to bounding box (words + arrow cells) with 1-cell margin
|
||||||
* - outputs gridv2 + words[] (+ difficulty, rewards)
|
* - outputs gridv2 + words[] (+ difficulty, rewards)
|
||||||
*/
|
*/
|
||||||
public final class ExportFormat {
|
public record ExportFormat() {
|
||||||
|
|
||||||
|
record Bit(long[] bits) {
|
||||||
|
|
||||||
|
public Bit() { this(new long[(SIZE >> 6) + 1]); }
|
||||||
|
static int wordIndex(int bitIndex) { return bitIndex >> 6; }
|
||||||
|
public boolean get(int bitIndex) { return (this.bits[wordIndex(bitIndex)] & 1L << bitIndex) != 0L; }
|
||||||
|
public void set(int bitIndex) { bits[wordIndex(bitIndex)] |= 1L << bitIndex; }
|
||||||
|
public void clear(int bitIndex) { this.bits[wordIndex(bitIndex)] &= ~(1L << bitIndex); }
|
||||||
|
public void clear() { Arrays.fill(bits, 0L); }
|
||||||
|
}
|
||||||
|
|
||||||
|
record Bit1029(long[] bits) {
|
||||||
|
|
||||||
|
public Bit1029() { this(new long[1029]); }
|
||||||
|
static int wordIndex(int bitIndex) { return bitIndex >> 6; }
|
||||||
|
public boolean get(int bitIndex) { return (this.bits[wordIndex(bitIndex)] & 1L << bitIndex) != 0L; }
|
||||||
|
public void set(int bitIndex) { bits[wordIndex(bitIndex)] |= 1L << bitIndex; }
|
||||||
|
public void clear(int bitIndex) { this.bits[wordIndex(bitIndex)] &= ~(1L << bitIndex); }
|
||||||
|
public void clear() { Arrays.fill(bits, 0L); }
|
||||||
|
}
|
||||||
|
|
||||||
private ExportFormat() { }
|
|
||||||
static final String HORIZONTAL = "h", VERTICAL = "v";
|
static final String HORIZONTAL = "h", VERTICAL = "v";
|
||||||
private static boolean inBounds(int H, int W, int r, int c) { return r >= 0 && r < H && c >= 0 && c < W; }
|
private static boolean inBounds(int r, int c) { return r >= 0 && r < SwedishGenerator.R && c >= 0 && c < SwedishGenerator.C; }
|
||||||
|
|
||||||
// ---------- Public API ----------
|
|
||||||
|
|
||||||
public static ExportedPuzzle exportFormatFromFilled(PuzzleResult puz, int difficulty, Rewards rewards) {
|
public static ExportedPuzzle exportFormatFromFilled(PuzzleResult puz, int difficulty, Rewards rewards) {
|
||||||
Objects.requireNonNull(puz, "puz");
|
Objects.requireNonNull(puz, "puz");
|
||||||
var g = puz.filled().grid();
|
var g = puz.filled().grid();
|
||||||
|
|
||||||
// 1) extract "placed" list from all clue digits in the filled grid
|
|
||||||
var placed = new ArrayList<Placed>();
|
var placed = new ArrayList<Placed>();
|
||||||
var clueMap = puz.filled().clueMap();
|
var clueMap = puz.filled().clueMap();
|
||||||
puz.swe().forEachSlot(g, (int key, long rs, long cs, int len) -> {
|
puz.swe().forEachSlot(g, (int key, long rs, long cs, int len) -> {
|
||||||
@@ -44,10 +61,10 @@ public final class ExportFormat {
|
|||||||
|
|
||||||
// If nothing placed: return full grid mapped to letters/# only
|
// If nothing placed: return full grid mapped to letters/# only
|
||||||
if (placed.isEmpty()) {
|
if (placed.isEmpty()) {
|
||||||
var gridv2 = new ArrayList<String>(H);
|
var gridv2 = new ArrayList<String>(R);
|
||||||
for (var r = 0; r < H; r++) {
|
for (var r = 0; r < R; r++) {
|
||||||
var sb = new StringBuilder(W);
|
var sb = new StringBuilder(C);
|
||||||
for (var c = 0; c < W; c++) {
|
for (var c = 0; c < C; c++) {
|
||||||
sb.append(g.isLetterAt(r, c) ? g.getCharAt(r, c) : '#');
|
sb.append(g.isLetterAt(r, c) ? g.getCharAt(r, c) : '#');
|
||||||
}
|
}
|
||||||
gridv2.add(sb.toString());
|
gridv2.add(sb.toString());
|
||||||
@@ -78,7 +95,7 @@ public final class ExportFormat {
|
|||||||
for (var p : placed) {
|
for (var p : placed) {
|
||||||
for (var rc : p.cells) {
|
for (var rc : p.cells) {
|
||||||
int rr = rc[0], cc = rc[1];
|
int rr = rc[0], cc = rc[1];
|
||||||
if (inBounds(H, W, rr, cc) && g.isLetterAt(rr, cc)) {
|
if (inBounds(rr, cc) && g.isLetterAt(rr, cc)) {
|
||||||
letterAt.put(pack(rr, cc), g.getCharAt(rr, cc));
|
letterAt.put(pack(rr, cc), g.getCharAt(rr, cc));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -181,4 +198,5 @@ public final class ExportFormat {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public record ExportedPuzzle(List<String> gridv2, WordOut[] words, int difficulty, Rewards rewards) { }
|
public record ExportedPuzzle(List<String> gridv2, WordOut[] words, int difficulty, Rewards rewards) { }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,13 +2,14 @@ package puzzle;
|
|||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
import puzzle.ExportFormat.Bit;
|
||||||
|
import puzzle.ExportFormat.Bit1029;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.BitSet;
|
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
@@ -27,16 +28,17 @@ public record SwedishGenerator(int[] buff) {
|
|||||||
|
|
||||||
record CandidateInfo(int[] indices, int count) { }
|
record CandidateInfo(int[] indices, int count) { }
|
||||||
|
|
||||||
record nbrs_8(int x, int y) { }
|
record nbrs_8(int r, int c) { }
|
||||||
|
|
||||||
record nbrs_16(int x, int y, int dx, int dy) { }
|
record nbrs_16(int r, int c, int dr, int dc) { }
|
||||||
|
|
||||||
static final int W = Config.PUZZLE_COLS;
|
static final int C = Config.PUZZLE_COLS;
|
||||||
static final double CROSS_Y = (W - 1) / 2.0;
|
static final double CROSS_Y = (C - 1) / 2.0;
|
||||||
static final int H = Config.PUZZLE_ROWS;
|
static final int R = Config.PUZZLE_ROWS;
|
||||||
static final double CROSS_X = (H - 1) / 2.0;
|
static final double CROSS_X = (R - 1) / 2.0;
|
||||||
static final int SIZE = W * H;
|
static final int SIZE = C * R;// ~18
|
||||||
static final int MAX_WORD_LENGTH = Math.min(W, H);
|
static final int TARGET_CLUES = SIZE >> 2;
|
||||||
|
static final int MAX_WORD_LENGTH = Math.min(C, R);
|
||||||
static final int MIN_LEN = Config.MIN_LEN;
|
static final int MIN_LEN = Config.MIN_LEN;
|
||||||
static final int CLUE_SIZE = Config.CLUE_SIZE;
|
static final int CLUE_SIZE = Config.CLUE_SIZE;
|
||||||
static final int SIMPLICITY_DEFAULT_SCORE = 2;
|
static final int SIMPLICITY_DEFAULT_SCORE = 2;
|
||||||
@@ -52,18 +54,12 @@ public record SwedishGenerator(int[] buff) {
|
|||||||
// Directions for '1'..'6'
|
// Directions for '1'..'6'
|
||||||
static final nbrs_16[] OFFSETS = new nbrs_16[]{
|
static final nbrs_16[] OFFSETS = new nbrs_16[]{
|
||||||
null,
|
null,
|
||||||
// 1: up
|
new nbrs_16(-1, 0, -1, 0), // 1: up
|
||||||
new nbrs_16(-1, 0, -1, 0),
|
new nbrs_16(0, 1, 0, 1), // 2: right
|
||||||
// 2: right
|
new nbrs_16(1, 0, 1, 0),// 3: down
|
||||||
new nbrs_16(0, 1, 0, 1),
|
new nbrs_16(0, -1, 0, -1),// 4: left
|
||||||
// 3: down
|
new nbrs_16(0, -1, 1, 0),// 5: vertical down, clue is on the right of the first letter
|
||||||
new nbrs_16(1, 0, 1, 0),
|
new nbrs_16(0, 1, 1, 0)// 6: vertical down, clue is on the left of the first letter
|
||||||
// 4: left
|
|
||||||
new nbrs_16(0, -1, 0, -1),
|
|
||||||
// 5: vertical down, clue is on the right of the first letter
|
|
||||||
new nbrs_16(0, -1, 1, 0),
|
|
||||||
// 6: vertical down, clue is on the left of the first letter
|
|
||||||
new nbrs_16(0, 1, 1, 0)
|
|
||||||
};
|
};
|
||||||
final static nbrs_8[] nbrs8 = new nbrs_8[]{
|
final static nbrs_8[] nbrs8 = new nbrs_8[]{
|
||||||
new nbrs_8(-1, -1),
|
new nbrs_8(-1, -1),
|
||||||
@@ -86,13 +82,13 @@ public record SwedishGenerator(int[] buff) {
|
|||||||
int[] covV,
|
int[] covV,
|
||||||
int[] cellCount,
|
int[] cellCount,
|
||||||
int[] stack,
|
int[] stack,
|
||||||
BitSet seen,
|
Bit seen,
|
||||||
char[] pattern,
|
char[] pattern,
|
||||||
IntList[] intListBuffer,
|
IntList[] intListBuffer,
|
||||||
long[] undoBuffer) {
|
long[] undoBuffer) {
|
||||||
|
|
||||||
public Context() {
|
public Context() {
|
||||||
this(new int[SIZE], new int[SIZE], new int[SIZE], new int[SIZE], new BitSet(128), new char[MAX_WORD_LENGTH], new IntList[MAX_WORD_LENGTH],
|
this(new int[SIZE], new int[SIZE], new int[SIZE], new int[SIZE], new Bit(), new char[MAX_WORD_LENGTH], new IntList[MAX_WORD_LENGTH],
|
||||||
new long[2048]);
|
new long[2048]);
|
||||||
}
|
}
|
||||||
void setPatter(char[] chars) { System.arraycopy(chars, 0, this.pattern, 0, chars.length); }
|
void setPatter(char[] chars) { System.arraycopy(chars, 0, this.pattern, 0, chars.length); }
|
||||||
@@ -114,7 +110,7 @@ public record SwedishGenerator(int[] buff) {
|
|||||||
x = y;
|
x = y;
|
||||||
return y;
|
return y;
|
||||||
}
|
}
|
||||||
int randint(int min, int max) { // inclusive
|
int randint(int min, int max) {
|
||||||
var u = (nextU32() & 0xFFFFFFFFL);
|
var u = (nextU32() & 0xFFFFFFFFL);
|
||||||
var range = (long) max - (long) min + 1L;
|
var range = (long) max - (long) min + 1L;
|
||||||
return (int) (min + (u % range));
|
return (int) (min + (u % range));
|
||||||
@@ -124,8 +120,10 @@ public record SwedishGenerator(int[] buff) {
|
|||||||
|
|
||||||
record Grid(byte[] g) {
|
record Grid(byte[] g) {
|
||||||
|
|
||||||
|
public static int r(int offset) { return offset & 7; }
|
||||||
|
public static int c(int offset) { return offset >> 3; }
|
||||||
Grid deepCopyGrid() { return new Grid(g.clone()); }
|
Grid deepCopyGrid() { return new Grid(g.clone()); }
|
||||||
private int offset(int r, int c) { return r | (c << 3); }
|
static int offset(int r, int c) { return r | (c << 3); }
|
||||||
boolean isLettercell(int r, int c) { return (g[offset(r, c)] & 48) != 48; }
|
boolean isLettercell(int r, int c) { return (g[offset(r, c)] & 48) != 48; }
|
||||||
char getCharAt(int r, int c) { return (char) (g[offset(r, c)]); }
|
char getCharAt(int r, int c) { return (char) (g[offset(r, c)]); }
|
||||||
int digitAt(int r, int c) { return g[offset(r, c)] - 48; }
|
int digitAt(int r, int c) { return g[offset(r, c)] - 48; }
|
||||||
@@ -133,6 +131,7 @@ public record SwedishGenerator(int[] buff) {
|
|||||||
void setCharAt(int r, int c, char ch) { g[offset(r, c)] = (byte) ch; }
|
void setCharAt(int r, int c, char ch) { g[offset(r, c)] = (byte) ch; }
|
||||||
boolean isLetterAt(int r, int c) { return ((g[offset(r, c)] & 64) != 0); }
|
boolean isLetterAt(int r, int c) { return ((g[offset(r, c)] & 64) != 0); }
|
||||||
boolean isDigitAt(int r, int c) { return (g[offset(r, c)] & 48) == 48; }
|
boolean isDigitAt(int r, int c) { return (g[offset(r, c)] & 48) == 48; }
|
||||||
|
boolean isDigitAt(int index) { return (g[index] & 48) == 48; }
|
||||||
public double similarity(Grid b) {
|
public double similarity(Grid b) {
|
||||||
var same = 0;
|
var same = 0;
|
||||||
for (int i = 0; i < SIZE; i++) if (g[i] == b.g[i]) same++;
|
for (int i = 0; i < SIZE; i++) if (g[i] == b.g[i]) same++;
|
||||||
@@ -143,18 +142,18 @@ public record SwedishGenerator(int[] buff) {
|
|||||||
|
|
||||||
String gridToString(Grid g) {
|
String gridToString(Grid g) {
|
||||||
var sb = new StringBuilder();
|
var sb = new StringBuilder();
|
||||||
for (var r = 0; r < H; r++) {
|
for (var r = 0; r < R; r++) {
|
||||||
if (r > 0) sb.append('\n');
|
if (r > 0) sb.append('\n');
|
||||||
for (var c = 0; c < W; c++) sb.append(g.getCharAt(r, c));
|
for (var c = 0; c < C; c++) sb.append(g.getCharAt(r, c));
|
||||||
}
|
}
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String renderHuman(Grid g) {
|
public String renderHuman(Grid g) {
|
||||||
var sb = new StringBuilder();
|
var sb = new StringBuilder();
|
||||||
for (var r = 0; r < H; r++) {
|
for (var r = 0; r < R; r++) {
|
||||||
if (r > 0) sb.append('\n');
|
if (r > 0) sb.append('\n');
|
||||||
for (var c = 0; c < W; c++) {
|
for (var c = 0; c < C; c++) {
|
||||||
sb.append(g.isDigitAt(r, c) ? ' ' : g.getCharAt(r, c));
|
sb.append(g.isDigitAt(r, c) ? ' ' : g.getCharAt(r, c));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -352,24 +351,24 @@ public record SwedishGenerator(int[] buff) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void forEachSlot(Grid grid, SlotVisitor visitor) {
|
void forEachSlot(Grid grid, SlotVisitor visitor) {
|
||||||
for (var r = 0; r < H; r++) {
|
for (var r = 0; r < R; r++) {
|
||||||
for (var c = 0; c < W; c++) {
|
for (var c = 0; c < C; c++) {
|
||||||
if (!grid.isDigitAt(r, c)) continue;
|
if (!grid.isDigitAt(r, c)) continue;
|
||||||
var d = grid.digitAt(r, c);
|
var d = grid.digitAt(r, c);
|
||||||
var nbrs16 = OFFSETS[d];
|
var nbrs16 = OFFSETS[d];
|
||||||
int rr = r + nbrs16.x, cc = c + nbrs16.y;
|
int rr = r + nbrs16.r, cc = c + nbrs16.c;
|
||||||
|
|
||||||
if (rr < 0 || rr >= H || cc < 0 || cc >= W || grid.isDigitAt(rr, cc)) continue;
|
if (rr < 0 || rr >= R || cc < 0 || cc >= C || grid.isDigitAt(rr, cc)) continue;
|
||||||
long packedRs = 0;
|
long packedRs = 0;
|
||||||
long packedCs = 0;
|
long packedCs = 0;
|
||||||
var n = 0;
|
var n = 0;
|
||||||
|
|
||||||
while (rr >= 0 && rr < H && cc >= 0 && cc < W && grid.isLettercell(rr, cc) && n < MAX_WORD_LENGTH) {
|
while (rr >= 0 && rr < R && cc >= 0 && cc < C && grid.isLettercell(rr, cc) && n < MAX_WORD_LENGTH) {
|
||||||
packedRs |= (long) rr << (n << 2);
|
packedRs |= (long) rr << (n << 2);
|
||||||
packedCs |= (long) cc << (n << 2);
|
packedCs |= (long) cc << (n << 2);
|
||||||
n++;
|
n++;
|
||||||
rr += nbrs16.dx;
|
rr += nbrs16.dr;
|
||||||
cc += nbrs16.dy;
|
cc += nbrs16.dc;
|
||||||
}
|
}
|
||||||
if (n > 0) {
|
if (n > 0) {
|
||||||
visitor.visit((r << 8) | (c << 4) | d, packedRs, packedCs, n);
|
visitor.visit((r << 8) | (c << 4) | d, packedRs, packedCs, n);
|
||||||
@@ -386,12 +385,12 @@ public record SwedishGenerator(int[] buff) {
|
|||||||
|
|
||||||
boolean hasRoomForClue(Grid grid, int r, int c, char d) {
|
boolean hasRoomForClue(Grid grid, int r, int c, char d) {
|
||||||
var nbrs16 = OFFSETS[d - '0'];
|
var nbrs16 = OFFSETS[d - '0'];
|
||||||
int rr = r + nbrs16.x, cc = c + nbrs16.y;
|
int rr = r + nbrs16.r, cc = c + nbrs16.c;
|
||||||
var run = 0;
|
var run = 0;
|
||||||
while (rr >= 0 && rr < H && cc >= 0 && cc < W && (grid.isLettercell(rr, cc)) && run < MAX_WORD_LENGTH) {
|
while (rr >= 0 && rr < R && cc >= 0 && cc < C && (grid.isLettercell(rr, cc)) && run < MAX_WORD_LENGTH) {
|
||||||
run++;
|
run++;
|
||||||
rr += nbrs16.dx;
|
rr += nbrs16.dr;
|
||||||
cc += nbrs16.dy;
|
cc += nbrs16.dc;
|
||||||
if (run >= MIN_LEN) return true;
|
if (run >= MIN_LEN) return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -401,10 +400,9 @@ public record SwedishGenerator(int[] buff) {
|
|||||||
long penalty = 0;
|
long penalty = 0;
|
||||||
|
|
||||||
var clueCount = 0;
|
var clueCount = 0;
|
||||||
for (var r = 0; r < H; r++) for (var c = 0; c < W; c++) if (grid.isDigitAt(r, c)) clueCount++;
|
for (var r = 0; r < R; r++) for (var c = 0; c < C; c++) if (grid.isDigitAt(r, c)) clueCount++;
|
||||||
|
|
||||||
var targetClues = (int) Math.round(SIZE * 0.25); // ~18
|
penalty += 8L * Math.abs(clueCount - TARGET_CLUES);
|
||||||
penalty += 8L * Math.abs(clueCount - targetClues);
|
|
||||||
|
|
||||||
var ctx = CTX.get();
|
var ctx = CTX.get();
|
||||||
var covH = ctx.covH;
|
var covH = ctx.covH;
|
||||||
@@ -413,25 +411,25 @@ public record SwedishGenerator(int[] buff) {
|
|||||||
Arrays.fill(covV, 0, SIZE, 0);
|
Arrays.fill(covV, 0, SIZE, 0);
|
||||||
|
|
||||||
boolean hasSlots = false;
|
boolean hasSlots = false;
|
||||||
for (var r = 0; r < H; r++) {
|
for (var r = 0; r < R; r++) {
|
||||||
for (var c = 0; c < W; c++) {
|
for (var c = 0; c < C; c++) {
|
||||||
if (!grid.isDigitAt(r, c)) continue;
|
if (!grid.isDigitAt(r, c)) continue;
|
||||||
var d = grid.digitAt(r, c);
|
var d = grid.digitAt(r, c);
|
||||||
var nbrs16 = OFFSETS[d];
|
var nbrs16 = OFFSETS[d];
|
||||||
int rr = r + nbrs16.x, cc = c + nbrs16.y;
|
int rr = r + nbrs16.r, cc = c + nbrs16.c;
|
||||||
if (rr < 0 || rr >= H || cc < 0 || cc >= W || grid.isDigitAt(rr, cc)) continue;
|
if (rr < 0 || rr >= R || cc < 0 || cc >= C || grid.isDigitAt(rr, cc)) continue;
|
||||||
|
|
||||||
long packedRs = 0;
|
long packedRs = 0;
|
||||||
long packedCs = 0;
|
long packedCs = 0;
|
||||||
var n = 0;
|
var n = 0;
|
||||||
|
|
||||||
while (rr >= 0 && rr < H && cc >= 0 && cc < W && n < MAX_WORD_LENGTH) {
|
while (rr >= 0 && rr < R && cc >= 0 && cc < C && n < MAX_WORD_LENGTH) {
|
||||||
if (grid.isDigitAt(rr, cc)) break;
|
if (grid.isDigitAt(rr, cc)) break;
|
||||||
packedRs |= (long) rr << (n << 2);
|
packedRs |= (long) rr << (n << 2);
|
||||||
packedCs |= (long) cc << (n << 2);
|
packedCs |= (long) cc << (n << 2);
|
||||||
n++;
|
n++;
|
||||||
rr += nbrs16.dx;
|
rr += nbrs16.dr;
|
||||||
cc += nbrs16.dy;
|
cc += nbrs16.dc;
|
||||||
}
|
}
|
||||||
if (n == 0) continue;
|
if (n == 0) continue;
|
||||||
hasSlots = true;
|
hasSlots = true;
|
||||||
@@ -443,16 +441,16 @@ public record SwedishGenerator(int[] buff) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var horiz = Slot.horiz(d) ? covH : covV;
|
var horiz = Slot.horiz(d) ? covH : covV;
|
||||||
for (var i = 0; i < n; i++) horiz[grid.offset(Slot.r(packedRs, i), Slot.c(packedCs, i))] += 1;
|
for (var i = 0; i < n; i++) horiz[Grid.offset(Slot.r(packedRs, i), Slot.c(packedCs, i))] += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!hasSlots) return 1_000_000_000L;
|
if (!hasSlots) return 1_000_000_000L;
|
||||||
|
|
||||||
for (var r = 0; r < H; r++)
|
for (var r = 0; r < R; r++)
|
||||||
for (var c = 0; c < W; c++) {
|
for (var c = 0; c < C; c++) {
|
||||||
if (grid.isDigitAt(r, c)) continue;
|
if (grid.isDigitAt(r, c)) continue;
|
||||||
int idx = grid.offset(r, c);
|
int idx = Grid.offset(r, c);
|
||||||
int h = covH[idx], v = covV[idx];
|
int h = covH[idx], v = covV[idx];
|
||||||
if (h == 0 && v == 0) penalty += 1500;
|
if (h == 0 && v == 0) penalty += 1500;
|
||||||
else if (h > 0 && v > 0) { /* ok */ } else if (h + v == 1) penalty += 200;
|
else if (h > 0 && v > 0) { /* ok */ } else if (h + v == 1) penalty += 200;
|
||||||
@@ -465,8 +463,8 @@ public record SwedishGenerator(int[] buff) {
|
|||||||
var stack = ctx.stack;
|
var stack = ctx.stack;
|
||||||
int sp, idx;
|
int sp, idx;
|
||||||
|
|
||||||
for (var r = 0; r < H; r++)
|
for (var r = 0; r < R; r++)
|
||||||
for (var c = 0; c < W; c++) {
|
for (var c = 0; c < C; c++) {
|
||||||
idx = grid.offset(r, c);
|
idx = grid.offset(r, c);
|
||||||
if (!grid.isDigitAt(r, c) || seen.get(idx)) continue;
|
if (!grid.isDigitAt(r, c) || seen.get(idx)) continue;
|
||||||
sp = 0;
|
sp = 0;
|
||||||
@@ -476,12 +474,12 @@ public record SwedishGenerator(int[] buff) {
|
|||||||
|
|
||||||
while (sp > 0) {
|
while (sp > 0) {
|
||||||
var p = stack[--sp];
|
var p = stack[--sp];
|
||||||
int x = p / W, y = p % W;
|
int x = p / C, y = p % C;
|
||||||
size++;
|
size++;
|
||||||
|
|
||||||
for (var d : nbrs8) {
|
for (var d : nbrs8) {
|
||||||
int nx = x + d.x, ny = y + d.y;
|
int nx = x + d.r, ny = y + d.c;
|
||||||
if (nx < 0 || nx >= H || ny < 0 || ny >= W) continue;
|
if (nx < 0 || nx >= R || ny < 0 || ny >= C) continue;
|
||||||
int nidx = grid.offset(nx, ny);
|
int nidx = grid.offset(nx, ny);
|
||||||
if (seen.get(nidx)) continue;
|
if (seen.get(nidx)) continue;
|
||||||
if (!grid.isDigitAt(nx, ny)) continue;
|
if (!grid.isDigitAt(nx, ny)) continue;
|
||||||
@@ -494,13 +492,13 @@ public record SwedishGenerator(int[] buff) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// dead-end-ish letter cell (3+ walls)
|
// dead-end-ish letter cell (3+ walls)
|
||||||
for (var r = 0; r < H; r++)
|
for (var r = 0; r < R; r++)
|
||||||
for (var c = 0; c < W; c++) {
|
for (var c = 0; c < C; c++) {
|
||||||
if (grid.isDigitAt(r, c)) continue;
|
if (grid.isDigitAt(r, c)) continue;
|
||||||
var walls = 0;
|
var walls = 0;
|
||||||
for (var d : nbrs4) {
|
for (var d : nbrs4) {
|
||||||
int rr = r + d.x, cc = c + d.y;
|
int rr = r + d.r, cc = c + d.c;
|
||||||
if (rr < 0 || rr >= H || cc < 0 || cc >= W) {
|
if (rr < 0 || rr >= R || cc < 0 || cc >= C) {
|
||||||
walls++;
|
walls++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -520,8 +518,8 @@ public record SwedishGenerator(int[] buff) {
|
|||||||
int placed = 0, guard = 0;
|
int placed = 0, guard = 0;
|
||||||
|
|
||||||
while (placed < targetClues && guard++ < 4000) {
|
while (placed < targetClues && guard++ < 4000) {
|
||||||
var r = rng.randint(0, H - 1);
|
var r = rng.randint(0, R - 1);
|
||||||
var c = rng.randint(0, W - 1);
|
var c = rng.randint(0, C - 1);
|
||||||
if (g.isDigitAt(r, c)) continue;
|
if (g.isDigitAt(r, c)) continue;
|
||||||
|
|
||||||
var d = (char) ('0' + rng.randint(1, c == 0 ? CLUE_SIZE : 4));
|
var d = (char) ('0' + rng.randint(1, c == 0 ? CLUE_SIZE : 4));
|
||||||
@@ -537,13 +535,13 @@ public record SwedishGenerator(int[] buff) {
|
|||||||
|
|
||||||
Grid mutate(Rng rng, Grid grid) {
|
Grid mutate(Rng rng, Grid grid) {
|
||||||
var g = grid.deepCopyGrid();
|
var g = grid.deepCopyGrid();
|
||||||
var cx = rng.randint(0, H - 1);
|
var cx = rng.randint(0, R - 1);
|
||||||
var cy = rng.randint(0, W - 1);
|
var cy = rng.randint(0, C - 1);
|
||||||
|
|
||||||
var steps = 4;
|
var steps = 4;
|
||||||
for (var k = 0; k < steps; k++) {
|
for (var k = 0; k < steps; k++) {
|
||||||
var rr = clamp(cx + (rng.randint(-2, 2) + rng.randint(-2, 2)), 0, H - 1);
|
var rr = clamp(cx + (rng.randint(-2, 2) + rng.randint(-2, 2)), 0, R - 1);
|
||||||
var cc = clamp(cy + (rng.randint(-2, 2) + rng.randint(-2, 2)), 0, W - 1);
|
var cc = clamp(cy + (rng.randint(-2, 2) + rng.randint(-2, 2)), 0, C - 1);
|
||||||
|
|
||||||
if (g.isDigitAt(rr, cc)) {
|
if (g.isDigitAt(rr, cc)) {
|
||||||
g.setCharAt(rr, cc, C_DASH);
|
g.setCharAt(rr, cc, C_DASH);
|
||||||
@@ -562,13 +560,13 @@ public record SwedishGenerator(int[] buff) {
|
|||||||
var nx = Math.cos(theta);
|
var nx = Math.cos(theta);
|
||||||
var ny = Math.sin(theta);
|
var ny = Math.sin(theta);
|
||||||
|
|
||||||
for (var r = 0; r < H; r++)
|
for (var r = 0; r < R; r++)
|
||||||
for (var c = 0; c < W; c++) {
|
for (var c = 0; c < C; c++) {
|
||||||
out.setCharAt(r, c, ((r - CROSS_X) * nx + (c - CROSS_Y) * ny >= 0) ? a.getCharAt(r, c) : b.getCharAt(r, c));
|
out.setCharAt(r, c, ((r - CROSS_X) * nx + (c - CROSS_Y) * ny >= 0) ? a.getCharAt(r, c) : b.getCharAt(r, c));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var r = 0; r < H; r++)
|
for (var r = 0; r < R; r++)
|
||||||
for (var c = 0; c < W; c++) {
|
for (var c = 0; c < C; c++) {
|
||||||
if (out.isDigitAt(r, c) && !hasRoomForClue(out, r, c, out.getCharAt(r, c))) out.setCharAt(r, c, C_DASH);
|
if (out.isDigitAt(r, c) && !hasRoomForClue(out, r, c, out.getCharAt(r, c))) out.setCharAt(r, c, C_DASH);
|
||||||
}
|
}
|
||||||
return out;
|
return out;
|
||||||
@@ -648,6 +646,7 @@ public record SwedishGenerator(int[] buff) {
|
|||||||
pop.sort(Comparator.comparingLong(GridAndFit::fit));
|
pop.sort(Comparator.comparingLong(GridAndFit::fit));
|
||||||
return pop.get(0).grid;
|
return pop.get(0).grid;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Grid generateMask2(Rng rng, int[] lenCounts, int popSize, int gens, boolean verbose) {
|
public Grid generateMask2(Rng rng, int[] lenCounts, int popSize, int gens, boolean verbose) {
|
||||||
if (verbose) System.out.println("generateMask init pop: " + popSize);
|
if (verbose) System.out.println("generateMask init pop: " + popSize);
|
||||||
var pop = new ArrayList<Grid>();
|
var pop = new ArrayList<Grid>();
|
||||||
@@ -734,7 +733,7 @@ public record SwedishGenerator(int[] buff) {
|
|||||||
|
|
||||||
static int slotScore(int[] cellCount, Slot s, Grid grid) {
|
static int slotScore(int[] cellCount, Slot s, Grid grid) {
|
||||||
var cross = 0;
|
var cross = 0;
|
||||||
for (var i = 0; i < s.len(); i++) cross += (cellCount[grid.offset(s.r(i), s.c(i))] - 1);
|
for (var i = 0; i < s.len(); i++) cross += (cellCount[Grid.offset(s.r(i), s.c(i))] - 1);
|
||||||
return cross * 10 + s.len();
|
return cross * 10 + s.len();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -767,13 +766,13 @@ public record SwedishGenerator(int[] buff) {
|
|||||||
var grid = mask.deepCopyGrid();
|
var grid = mask.deepCopyGrid();
|
||||||
var slots = extractSlots(grid);
|
var slots = extractSlots(grid);
|
||||||
|
|
||||||
var used = new BitSet(SIZE << 1);
|
var used = new Bit1029();
|
||||||
var assigned = new HashMap<Integer, Lemma>();
|
var assigned = new HashMap<Integer, Lemma>();
|
||||||
|
|
||||||
var ctx = CTX.get();
|
var ctx = CTX.get();
|
||||||
var cellCount = ctx.cellCount;
|
var cellCount = ctx.cellCount;
|
||||||
Arrays.fill(cellCount, 0, SIZE, 0);
|
Arrays.fill(cellCount, 0, SIZE, 0);
|
||||||
for (var s : slots) for (var i = 0; i < s.len(); i++) cellCount[grid.offset(s.r(i), s.c(i))]++;
|
for (var s : slots) for (var i = 0; i < s.len(); i++) cellCount[Grid.offset(s.r(i), s.c(i))]++;
|
||||||
|
|
||||||
var t0 = System.currentTimeMillis();
|
var t0 = System.currentTimeMillis();
|
||||||
final var lastLog = new AtomicLong(t0);
|
final var lastLog = new AtomicLong(t0);
|
||||||
@@ -894,7 +893,7 @@ public record SwedishGenerator(int[] buff) {
|
|||||||
if (backtrack(depth + 1)) return true;
|
if (backtrack(depth + 1)) return true;
|
||||||
|
|
||||||
assigned.remove(k);
|
assigned.remove(k);
|
||||||
used.set(w.index, false);
|
used.clear(w.index);
|
||||||
undoPlace(grid, ctx.undoBuffer, undoOffset, nPlaced);
|
undoPlace(grid, ctx.undoBuffer, undoOffset, nPlaced);
|
||||||
}
|
}
|
||||||
stats.backtracks++;
|
stats.backtracks++;
|
||||||
@@ -933,7 +932,7 @@ public record SwedishGenerator(int[] buff) {
|
|||||||
if (backtrack(depth + 1)) return true;
|
if (backtrack(depth + 1)) return true;
|
||||||
|
|
||||||
assigned.remove(k);
|
assigned.remove(k);
|
||||||
used.set(w.index, false);
|
used.clear(w.index);
|
||||||
undoPlace(grid, ctx.undoBuffer, undoOffset, nPlaced);
|
undoPlace(grid, ctx.undoBuffer, undoOffset, nPlaced);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user