This commit is contained in:
mike
2026-01-23 11:58:57 +01:00
parent 2aa08fedb0
commit 7db439a9dc
8 changed files with 129 additions and 106 deletions

View File

@@ -1,10 +1,11 @@
package puzzle; package puzzle;
import module java.base; import module java.base;
import anno.Shaped;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.experimental.Delegate; import lombok.experimental.Delegate;
import lombok.val; import lombok.val;
import precomp.Const9x8.Cell; import precomp.Const9x8;
import puzzle.Export.Puzzle.Replacar.Rell; import puzzle.Export.Puzzle.Replacar.Rell;
import puzzle.Meta.ShardLem; import puzzle.Meta.ShardLem;
import puzzle.SwedishGenerator.Dict; import puzzle.SwedishGenerator.Dict;
@@ -12,14 +13,16 @@ import puzzle.SwedishGenerator.FillResult;
import puzzle.SwedishGenerator.Grid; import puzzle.SwedishGenerator.Grid;
import puzzle.SwedishGenerator.Slotinfo; import puzzle.SwedishGenerator.Slotinfo;
import static precomp.Const9x8.CLUE_DOWN0; import static precomp.Const9x8.CLUE_DOWN0;
import static precomp.Const9x8.CLUE_LEFT3;
import static precomp.Const9x8.CLUE_LEFT_TOP4;
import static precomp.Const9x8.CLUE_NONE;
import static precomp.Const9x8.CLUE_RIGHT1; import static precomp.Const9x8.CLUE_RIGHT1;
import static precomp.Const9x8.INIT_GRID_OUTPUT; import static precomp.Const9x8.CLUE_RIGHT_TOP5;
import static precomp.Const9x8.INIT_GRID_OUTPUT_ARR; import static precomp.Const9x8.CLUE_UP2;
import static puzzle.Export.Clue.DOWN0; import static puzzle.Export.Clue.DOWN0;
import static puzzle.Export.Clue.RIGHT1; import static puzzle.Export.Clue.RIGHT1;
import static puzzle.Clues.createEmpty; import static puzzle.Clues.createEmpty;
import static puzzle.Masker.Slot; import static puzzle.Masker.Slot;
import static puzzle.Masker.C;
import static puzzle.SwedishGenerator.Lemma; import static puzzle.SwedishGenerator.Lemma;
import static puzzle.SwedishGenerator.X; import static puzzle.SwedishGenerator.X;
@@ -34,26 +37,30 @@ import static puzzle.SwedishGenerator.X;
*/ */
public record Export() { public record Export() {
public static final ThreadLocal<byte[]> BYTES = ThreadLocal.withInitial(() -> new byte[8]); public static final ThreadLocal<byte[]> BYTES = ThreadLocal.withInitial(() -> new byte[8]);
static final byte CLUE_UP = 2; static final byte CLUE_UP = 2;
static final byte CLUE_LEFT = 3; static final byte CLUE_LEFT = 3;
static final byte CLUE_LEFT_TOP = 4; static final byte CLUE_LEFT_TOP = 4;
static final byte CLUE_RIGHT_TOP = 5; static final byte CLUE_RIGHT_TOP = 5;
@Shaped static final String INIT_GRID_OUTPUT = Const9x8.INIT_GRID_OUTPUT;
@Shaped static final int R = Const9x8.R;
@Shaped static final int C = Const9x8.C;
@Shaped static final byte[] INIT_GRID_OUTPUT_ARR = Const9x8.INIT_GRID_OUTPUT_ARR;
static int HI(int in) { return in | 64; } static int HI(int in) { return in | 64; }
static char LETTER(int in) { return (char) (in | 64); } static char LETTER(int in) { return (char) (in | 64); }
static char CLUE_CHAR(int s) { return (char) (s | 48); } static char CLUE_CHAR(int s) { return (char) (s | 48); }
static int INDEX_ROW(int idx) { return idx & 7; } static int INDEX_ROW(int idx) { return idx % R; }
static int INDEX_COL(int idx) { return idx >>> 3; } static int INDEX_COL(int idx) { return idx / R; }
static int INDEX(int r, int cols, int c) { return r * cols + c; } static int INDEX(int r, int cols, int c) { return r * cols + c; }
@AllArgsConstructor @AllArgsConstructor
enum Clue { enum Clue {
DOWN0(CLUE_DOWN0, 'B', 'b'), DOWN0(CLUE_DOWN0, 'B', 'b'),
RIGHT1(CLUE_RIGHT1, 'A', 'a'), RIGHT1(CLUE_RIGHT1, 'A', 'a'),
UP2(CLUE_UP, 'C', 'c'), UP2(CLUE_UP2, 'C', 'c'),
LEFT3(CLUE_LEFT, 'D', 'd'), LEFT3(CLUE_LEFT3, 'D', 'd'),
LEFT_TOP4(CLUE_LEFT_TOP, 'E', 'e'), LEFT_TOP4(CLUE_LEFT_TOP4, 'E', 'e'),
RIGHT_TOP5(CLUE_RIGHT_TOP, 'F', 'f'), RIGHT_TOP5(CLUE_RIGHT_TOP5, 'F', 'f'),
NONE(CLUE_LEFT, '?', '?'); NONE(CLUE_NONE, '?', '?');
final byte dir; final byte dir;
final char slotChar, clueChar; final char slotChar, clueChar;
private static final Clue[] CLUES = new Clue[]{ DOWN0, RIGHT1, UP2, LEFT3, LEFT_TOP4, RIGHT_TOP5, NONE, NONE, NONE }; private static final Clue[] CLUES = new Clue[]{ DOWN0, RIGHT1, UP2, LEFT3, LEFT_TOP4, RIGHT_TOP5, NONE, NONE, NONE };
@@ -113,15 +120,15 @@ public record Export() {
for (var h = grid.hi & ~cl.hi & 0xFF; h != X; h &= h - 1) stream.accept(Lettrix.from(64 | Long.numberOfTrailingZeros(h), grid.g)); for (var h = grid.hi & ~cl.hi & 0xFF; h != X; h &= h - 1) stream.accept(Lettrix.from(64 | Long.numberOfTrailingZeros(h), grid.g));
return stream.build(); return stream.build();
} }
String gridToString() { String gridToString(Slotinfo[] slots) {
var sb = INIT_GRID_OUTPUT_ARR.clone(); var sb = INIT_GRID_OUTPUT_ARR.clone();
Masker.forEachSlot(cl, (s, _, _) -> { for (var slot : slots) {
val idx = Slot.clueIndex(s); val idx = Slot.clueIndex(slot.key());
val r = idx & 7; val r = idx & 7;
val c = idx >>> 3; val c = idx >>> 3;
val dir = Slot.dir(s); val dir = Slot.dir(slot.key());
sb[r * (C + 1) + c] = (byte) (dir | 48); sb[r * (C + 1) + c] = (byte) (dir | 48);
}); }
stream().forEach((l) -> sb[l.index(C + 1)] = (byte) l.human()); stream().forEach((l) -> sb[l.index(C + 1)] = (byte) l.human());
return new String(sb); return new String(sb);
} }
@@ -137,9 +144,9 @@ public record Export() {
stream().forEach((l) -> sb[l.index(C + 1)] = (byte) l.human()); stream().forEach((l) -> sb[l.index(C + 1)] = (byte) l.human());
return new String(sb).replaceAll(" ", String.valueOf(emptyFallback)).split("\n"); return new String(sb).replaceAll(" ", String.valueOf(emptyFallback)).split("\n");
} }
public static IntStream cellWalk(byte base, long lo, long hi) { public static IntStream cellWalk(int base, long lo, long hi) {
if (Slotinfo.increasing(base)) { if (Slotinfo.increasing(base)) {
return IntStream.concat( return IntStream.concat(IntStream.of(Slot.clueIndex(base)), IntStream.concat(
IntStream.generate(new IntSupplier() { IntStream.generate(new IntSupplier() {
long temp = lo; long temp = lo;
@@ -159,9 +166,9 @@ public record Export() {
temp &= temp - 1; temp &= temp - 1;
return res; return res;
} }
}).limit(Long.bitCount(hi))); }).limit(Long.bitCount(hi))));
} else { } else {
return IntStream.concat( return IntStream.concat(IntStream.of(Slot.clueIndex(base)), IntStream.concat(
IntStream.generate(new IntSupplier() { IntStream.generate(new IntSupplier() {
long temp = hi; long temp = hi;
@@ -181,11 +188,10 @@ public record Export() {
temp &= ~(1L << msb); temp &= ~(1L << msb);
return msb; return msb;
} }
}).limit(Long.bitCount(lo))); }).limit(Long.bitCount(lo))));
} }
} }
public String renderHuman() { return String.join("\n", exportGrid(_ -> ' ', '#')); }
@FunctionalInterface @FunctionalInterface
interface Replacar { interface Replacar {
@@ -195,16 +201,16 @@ public record Export() {
} }
record Placed(rci[] rcis, long lemma, int slotKey, int[] cells) { record Placed(long lemma, int slotKey, rci[] cells) {
public static final char HORIZONTAL = 'h'; public static final char HORIZONTAL = 'h';
static final char VERTICAL = 'v'; static final char VERTICAL = 'v';
static final char[] DIRECTION = { Placed.VERTICAL, Placed.HORIZONTAL, Placed.VERTICAL, Placed.HORIZONTAL, Placed.VERTICAL, Placed.VERTICAL }; static final char[] DIRECTION = { Placed.VERTICAL, Placed.HORIZONTAL, Placed.VERTICAL, Placed.HORIZONTAL, Placed.VERTICAL, Placed.VERTICAL };
public int arrowCol() { return rcis[Slot.clueIndex(slotKey)].c(); } public int arrowCol() { return cells[0].c()/*rcis[Slot.clueIndex(slotKey)].c()*/; }
public int arrowRow() { return rcis[Slot.clueIndex(slotKey)].r(); } public int arrowRow() { return cells[0].r()/*rcis[Slot.clueIndex(slotKey)].r()*/; }
public int startRow() { return rcis[cells[0]].r(); } public int startRow() { return cells[1].r(); }
public int startCol() { return rcis[cells[0]].c(); } public int startCol() { return cells[1].c(); }
public boolean isReversed() { return !Slotinfo.increasing(slotKey); } public boolean isReversed() { return !Slotinfo.increasing(slotKey); }
public char direction() { return DIRECTION[Slot.dir(slotKey)]; } public char direction() { return DIRECTION[Slot.dir(slotKey)]; }
} }
@@ -247,31 +253,33 @@ public record Export() {
public record PuzzleResult(Signa clues, Puzzle grid, Slotinfo[] slots, FillResult filled) { public record PuzzleResult(Signa clues, Puzzle grid, Slotinfo[] slots, FillResult filled) {
public String gridRenderHuman() {
return String.join("\n", grid.exportGrid(_ -> ' ', '#'));
}
public String gridGridToString() {
return grid.gridToString(slots);
}
public ExportedPuzzle exportFormatFromFilled(Rewards rewards, rci[] rcis, int bits) { public ExportedPuzzle exportFormatFromFilled(Rewards rewards, rci[] rcis, int bits) {
// If nothing placed: return full grid mapped to letters/# only // If nothing placed: return full grid mapped to letters/# only
if (slots.length == 0) { if (slots.length == 0) {
return new ExportedPuzzle(grid.exportGrid(_ -> '#', '#'), new WordOut[0], 1, rewards); return new ExportedPuzzle(grid.exportGrid(_ -> '#', '#'), new WordOut[0], 1, rewards);
} }
var placed = Arrays.stream(slots).map(slot -> new Placed(rcis, slot.assign().w, slot.key(), Puzzle.cellWalk((byte) slot.key(), slot.lo(), slot.hi()).toArray())).toArray( var placed = Arrays.stream(slots)
Placed[]::new); .map(slot -> new Placed(slot.assign().w, slot.key(), Puzzle.cellWalk(slot.key(), slot.lo(), slot.hi()).mapToObj(i -> rcis[i]).toArray(rci[]::new)))
.toArray(Placed[]::new);
// 2) bounding box around all word cells + arrow cells, with 1-cell margin // 2) bounding box around all word cells + arrow cells, with 1-cell margin
int minR = Integer.MAX_VALUE, minC = Integer.MAX_VALUE; int minR = Integer.MAX_VALUE, minC = Integer.MAX_VALUE;
int maxR = Integer.MIN_VALUE, maxC = Integer.MIN_VALUE; int maxR = Integer.MIN_VALUE, maxC = Integer.MIN_VALUE;
for (var rc : placed) { for (var rc : placed) {
for (var c : rc.cells) { for (var it : rc.cells) {
val it = rcis[c];
minR = Math.min(minR, it.r()); minR = Math.min(minR, it.r());
minC = Math.min(minC, it.c()); minC = Math.min(minC, it.c());
maxR = Math.max(maxR, it.r()); maxR = Math.max(maxR, it.r());
maxC = Math.max(maxC, it.c()); maxC = Math.max(maxC, it.c());
} }
minR = Math.min(minR, rc.arrowRow());
minC = Math.min(minC, rc.arrowCol());
maxR = Math.max(maxR, rc.arrowRow());
maxC = Math.max(maxC, rc.arrowCol());
} }
// 3) map of only used letter cells (everything else becomes '#') // 3) map of only used letter cells (everything else becomes '#')
@@ -299,6 +307,8 @@ public record Export() {
var total = 0.0001d + Arrays.stream(wordsOut).mapToDouble(WordOut::complex).sum(); var total = 0.0001d + Arrays.stream(wordsOut).mapToDouble(WordOut::complex).sum();
return new ExportedPuzzle(gridv2, wordsOut, (int) (total / wordsOut.length), rewards); return new ExportedPuzzle(gridv2, wordsOut, (int) (total / wordsOut.length), rewards);
} }
} }
record Lettrix(int index, byte letter) { record Lettrix(int index, byte letter) {

View File

@@ -96,10 +96,10 @@ public class Main {
System.out.print(indentLines(res.clues().gridToString())); System.out.print(indentLines(res.clues().gridToString()));
section("Grid (raw)"); section("Grid (raw)");
System.out.print(indentLines(res.grid().gridToString())); System.out.print(indentLines(res.gridGridToString()));
section("Grid (human)"); section("Grid (human)");
System.out.print(indentLines(res.grid().renderHuman())); System.out.print(indentLines(res.gridRenderHuman()));
var exported = res.exportFormatFromFilled(new Rewards(50, 2, 1), Masker.IT, 3); var exported = res.exportFormatFromFilled(new Rewards(50, 2, 1), Masker.IT, 3);

View File

@@ -11,35 +11,37 @@ import static puzzle.SwedishGenerator.*;
@GenerateShapedCopies( @GenerateShapedCopies(
packageName = "puzzle", packageName = "puzzle",
className = "Masker", className = "Masker",
shapes = { "precomp.Neighbors9x8", "precomp.Neighbors4x3" , "precomp.Neighbors3x4" } shapes = { "precomp.Neighbors9x8", "precomp.Neighbors4x3", "precomp.Neighbors3x4" }
) )
public final class Masker { public final class Masker {
@Shaped public static final int SIZE = Neighbors9x8.SIZE; @Shaped public static final int SIZE = Neighbors9x8.SIZE;
@Shaped public static final rci[] IT = Neighbors9x8.IT; @Shaped public static final rci[] IT = Neighbors9x8.IT;
@Shaped public static final long[] PATH_LO = Neighbors9x8.PATH_LO; @Shaped public static final long[] PATH_LO = Neighbors9x8.PATH_LO;
@Shaped public static final long[] PATH_HI = Neighbors9x8.PATH_HI; @Shaped public static final long[] PATH_HI = Neighbors9x8.PATH_HI;
@Shaped public static final long MASK_LO = Neighbors9x8.MASK_LO; @Shaped public static final long MASK_LO = Neighbors9x8.MASK_LO;
@Shaped public static final long MASK_HI = Neighbors9x8.MASK_HI;//(1L << (SIZE - 64)) - 1; @Shaped public static final long RANGE_0_SIZE = Neighbors9x8.RANGE_0_SIZE;
@Shaped public static final int MIN_LEN = Neighbors9x8.MIN_LEN;//Config.MIN_LEN; @Shaped public static final long RANGE_0_624 = Neighbors9x8.RANGE_0_624;
@Shaped public static final int C = Neighbors9x8.C; @Shaped public static final long MASK_HI = Neighbors9x8.MASK_HI;//(1L << (SIZE - 64)) - 1;
@Shaped public static final int R = Neighbors9x8.R; @Shaped public static final int MIN_LEN = Neighbors9x8.MIN_LEN;//Config.MIN_LEN;
@Shaped public static final double SIZED = Neighbors9x8.SIZED;// ~18 @Shaped public static final int C = Neighbors9x8.C;
@Shaped private static final long[] NBR_LO = Neighbors9x8.NBR_LO; @Shaped public static final int R = Neighbors9x8.R;
@Shaped private static final long[] NBR_HI = Neighbors9x8.NBR_HI; @Shaped public static final double SIZED = Neighbors9x8.SIZED;// ~18
public static final int[][] MUTATE_RI = new int[SIZE][625]; @Shaped private static final long[] NBR_LO = Neighbors9x8.NBR_LO;
private static final boolean VERBOSE = false; @Shaped private static final long[] NBR_HI = Neighbors9x8.NBR_HI;
private final int[] activeCIdx = new int[SIZE]; public static final int[][] MUTATE_RI = new int[SIZE][625];
private final long[] activeSLo = new long[SIZE]; private static final boolean VERBOSE = false;
private final long[] activeSHi = new long[SIZE]; private final int[] activeCIdx = new int[SIZE];
private final long[] adjLo = new long[SIZE]; private final long[] activeSLo = new long[SIZE];
private final long[] adjHi = new long[SIZE]; private final long[] activeSHi = new long[SIZE];
private final int[] rCount = new int[R]; private final long[] adjLo = new long[SIZE];
private final int[] cCount = new int[C]; private final long[] adjHi = new long[SIZE];
private final int[] rCount = new int[R];
private final int[] cCount = new int[C];
private final Rng rng; private final Rng rng;
private final int[] stack; private final int[] stack;
private final Clues cache; private final Clues cache;
public static final int STACK_SIZE = 128; public static final int STACK_SIZE = 128;
public Masker(Rng rng, int[] stack, Clues cache) { public Masker(Rng rng, int[] stack, Clues cache) {
this.rng = rng; this.rng = rng;
this.stack = stack; this.stack = stack;
@@ -75,7 +77,7 @@ public final class Masker {
if (num == 0) return -1; if (num == 0) return -1;
var start = rng.randint0_SIZE() % num; var start = rng.randint0_SIZE(RANGE_0_SIZE) % num;
var n = 0; var n = 0;
for (var i = 0; i < num; i++) { for (var i = 0; i < num; i++) {
var idx = activeCIdx[(start + i) % num]; var idx = activeCIdx[(start + i) % num];
@@ -470,7 +472,7 @@ public final class Masker {
var g = Clues.createEmpty(); var g = Clues.createEmpty();
for (int placed = 0, guard = 0, ri; placed < clueSize && guard < 4000; guard++) { for (int placed = 0, guard = 0, ri; placed < clueSize && guard < 4000; guard++) {
ri = rng.randint0_SIZE(); ri = rng.randint0_SIZE(RANGE_0_SIZE);
if (isLo(ri)) { if (isLo(ri)) {
if (g.isClueLo(ri)) continue; if (g.isClueLo(ri)) continue;
var d_idx = rng.randomClueDir(); var d_idx = rng.randomClueDir();
@@ -496,9 +498,9 @@ public final class Masker {
} }
public Clues mutate(Clues c) { public Clues mutate(Clues c) {
var bytes = MUTATE_RI[rng.randint0_SIZE()]; var bytes = MUTATE_RI[rng.randint0_SIZE(RANGE_0_SIZE)];
for (int k = 0, ri; k < 6; k++) { for (int k = 0, ri; k < 6; k++) {
ri = bytes[rng.randint0_624()]; ri = bytes[rng.randint0_624(RANGE_0_624)];
if (c.notClue(ri)) { // ADD if (c.notClue(ri)) { // ADD
var d = rng.randomClueDir(); var d = rng.randomClueDir();
var key = Slot.packSlotKey(ri, d); var key = Slot.packSlotKey(ri, d);
@@ -543,7 +545,7 @@ public final class Masker {
} }
} }
} // MOVE } // MOVE
var nri = bytes[rng.randint0_624()]; var nri = bytes[rng.randint0_624(RANGE_0_624)];
if (c.notClue(nri)) { if (c.notClue(nri)) {
var d = c.getDir(ri); var d = c.getDir(ri);
var nkey = Slot.packSlotKey(nri, d); var nkey = Slot.packSlotKey(nri, d);

View File

@@ -3,11 +3,9 @@ package puzzle;
import anno.ConstGen; import anno.ConstGen;
import anno.GenerateNeighbor; import anno.GenerateNeighbor;
import anno.GenerateNeighbors; import anno.GenerateNeighbors;
import anno.Shaped;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.val; import lombok.val;
import precomp.Neighbors9x8;
import static java.lang.Long.bitCount; import static java.lang.Long.bitCount;
import static java.lang.Long.numberOfLeadingZeros; import static java.lang.Long.numberOfLeadingZeros;
import static java.lang.Long.numberOfTrailingZeros; import static java.lang.Long.numberOfTrailingZeros;
@@ -40,9 +38,6 @@ public record SwedishGenerator() {
public static final int MAX_TRIES_PER_SLOT = 500;// MAX_TRIES_PER_SLOT; public static final int MAX_TRIES_PER_SLOT = 500;// MAX_TRIES_PER_SLOT;
public static final long X = 0L; public static final long X = 0L;
@Shaped static final int SIZE = Neighbors9x8.SIZE;
@Shaped private static final long RANGE_0_SIZE = Neighbors9x8.RANGE_0_SIZE;
@Shaped private static final long RANGE_0_624 = Neighbors9x8.RANGE_0_624;
interface Bit1029 { interface Bit1029 {
@@ -80,8 +75,8 @@ public record SwedishGenerator() {
public byte randomClueDir() { return rand(BYTE); } public byte randomClueDir() { return rand(BYTE); }
public <T> T rand(T[] p) { return p[(int) (((nextU32() & 0xFFFFFFFFL) % ((long) p.length)))]; } public <T> T rand(T[] p) { return p[(int) (((nextU32() & 0xFFFFFFFFL) % ((long) p.length)))]; }
public byte rand(byte[] p) { return p[(int) (((nextU32() & 0xFFFFFFFFL) % ((long) p.length)))]; } public byte rand(byte[] p) { return p[(int) (((nextU32() & 0xFFFFFFFFL) % ((long) p.length)))]; }
public int randint0_SIZE() { return (int) (((nextU32() & 0xFFFFFFFFL) % RANGE_0_SIZE)); } public int randint0_SIZE(long range0size) { return (int) (((nextU32() & 0xFFFFFFFFL) % range0size)); }
public int randint0_624() { return (int) (((nextU32() & 0xFFFFFFFFL) % RANGE_0_624)); } public int randint0_624(long range0624) { return (int) (((nextU32() & 0xFFFFFFFFL) % range0624)); }
public double nextFloat() { return (nextU32() & 0xFFFFFFFFL) / 4294967295.0; } public double nextFloat() { return (nextU32() & 0xFFFFFFFFL) / 4294967295.0; }
public int biasedIndexPow3(int N) { return (int) (((Math.min(nextU32(), Math.min(nextU32(), nextU32())) & 0xFFFFFFFFL) * (long) N) >>> 32); } public int biasedIndexPow3(int N) { return (int) (((Math.min(nextU32(), Math.min(nextU32(), nextU32())) & 0xFFFFFFFFL) * (long) N) >>> 32); }
} }

View File

@@ -58,11 +58,11 @@ public class MainTest {
assertEquals(1, slots.length); assertEquals(1, slots.length);
var s = slots[0]; var s = slots[0];
assertEquals(8, Masker.Slot.length(s.lo(), s.hi())); assertEquals(8, Masker.Slot.length(s.lo(), s.hi()));
var cells = Puzzle.cellWalk((byte) s.key(), s.lo(), s.hi()).mapToObj(c -> Masker.IT[c]).toArray(rci[]::new); var cells = Puzzle.cellWalk(s.key(), s.lo(), s.hi()).mapToObj(c -> Masker.IT[c]).toArray(rci[]::new);
assertEquals(0, cells[0].r());
assertEquals(1, cells[0].c());
assertEquals(0, cells[1].r()); assertEquals(0, cells[1].r());
assertEquals(2, cells[1].c()); assertEquals(1, cells[1].c());
assertEquals(0, cells[2].r());
assertEquals(2, cells[2].c());
} }
@Test @Test
@@ -186,9 +186,10 @@ public class MainTest {
Assertions.assertEquals("BEADEMT", Lemma.asWord(slotInfo[0].assign().w, Export.BYTES.get())); Assertions.assertEquals("BEADEMT", Lemma.asWord(slotInfo[0].assign().w, Export.BYTES.get()));
Assertions.assertEquals(74732156493031040L, grid.lo); Assertions.assertEquals(74732156493031040L, grid.lo);
Assertions.assertEquals(193L, grid.hi); Assertions.assertEquals(193L, grid.hi);
var g = new Puzzle(grid, mask.c()); var g = new Puzzle(grid, mask.c());
g.gridToString(); var result = new PuzzleResult(mask, g, slotInfo, filled);
var aa = new PuzzleResult(mask, g, slotInfo, filled).exportFormatFromFilled(new Rewards(1, 1, 1), Masker.IT, 3); var aa = result.exportFormatFromFilled(new Rewards(1, 1, 1), Masker.IT, 3);
result.gridGridToString();
System.out.println(String.join("\n", aa.grid())); System.out.println(String.join("\n", aa.grid()));
} }
@@ -204,8 +205,8 @@ public class MainTest {
System.out.println("[DEBUG_LOG] Seed found: " + seed); System.out.println("[DEBUG_LOG] Seed found: " + seed);
System.out.println("[DEBUG_LOG] ClueMap Size: " + Slotinfo.wordCount(0, res.slots())); System.out.println("[DEBUG_LOG] ClueMap Size: " + Slotinfo.wordCount(0, res.slots()));
System.out.println("[DEBUG_LOG] Grid:"); System.out.println("[DEBUG_LOG] Grid:");
System.out.println(res.grid().renderHuman()); System.out.println(res.gridRenderHuman());
System.out.println(res.grid().gridToString()); System.out.println(res.gridGridToString());
break; break;
} }
} }

View File

@@ -31,6 +31,13 @@ import static puzzle.dict900.DictData900.DICT900;
simpleMax = 800, simpleMax = 800,
minLen = 2, minLen = 2,
maxLen = 8 maxLen = 8
), @DictGen(
packageName = "puzzle.dict800_4",
className = "DictData800_4",
scv = "/home/mike/dev/puzzle-generator/nl_score_hints_v4.csv",
simpleMax = 800,
minLen = 2,
maxLen = 4
) }) ) })
public class PerformanceTest { public class PerformanceTest {
@@ -73,7 +80,7 @@ public class PerformanceTest {
for (var i = 0; i < iterations; i++) { for (var i = 0; i < iterations; i++) {
val slotInfo = Masker.slots(arr[c], DICT800); val slotInfo = Masker.slots(arr[c], DICT800);
var grid = Masker.grid(slotInfo); var grid = Masker.grid(slotInfo);
val result = fillMask(rng, slotInfo,grid.lo,grid.hi, grid.g); val result = fillMask(rng, slotInfo, grid.lo, grid.hi, grid.g);
if (result.ok()) successCount++; if (result.ok()) successCount++;
totalNodes += result.nodes(); totalNodes += result.nodes();
totalBacktracks += result.backtracks(); totalBacktracks += result.backtracks();
@@ -143,7 +150,7 @@ public class PerformanceTest {
for (var s : slots) s.assign().w = 0; for (var s : slots) s.assign().w = 0;
var grid = Masker.grid(slots); var grid = Masker.grid(slots);
val result = fillMask(rng, slots, grid.lo,grid.hi,grid.g); val result = fillMask(rng, slots, grid.lo, grid.hi, grid.g);
if (result.ok()) { if (result.ok()) {
successCount++; successCount++;
} }
@@ -178,17 +185,19 @@ public class PerformanceTest {
var slotChar = dir.slotChar; var slotChar = dir.slotChar;
display[cr][cc] = clueChar; display[cr][cc] = clueChar;
Puzzle.cellWalk((byte) slot.key(), slot.lo(), slot.hi()).forEach(idx -> { Puzzle.cellWalk(slot.key(), slot.lo(), slot.hi())
var r = Masker.IT[idx].r(); .skip(1)
var c = Masker.IT[idx].c(); .forEach(idx -> {
if (display[r][c] == ' ' || (display[r][c] >= 'A' && display[r][c] <= 'D')) { var r = Masker.IT[idx].r();
if (display[r][c] != ' ' && display[r][c] != slotChar) { var c = Masker.IT[idx].c();
display[r][c] = '+'; // Intersection if (display[r][c] == ' ' || (display[r][c] >= 'A' && display[r][c] <= 'D')) {
} else { if (display[r][c] != ' ' && display[r][c] != slotChar) {
display[r][c] = slotChar; display[r][c] = '+'; // Intersection
} } else {
} display[r][c] = slotChar;
}); }
}
});
} }
for (var r = 0; r < R; r++) { for (var r = 0; r < R; r++) {

View File

@@ -168,13 +168,13 @@ public class SwedishGeneratorTest {
assertEquals(OFF_2_3, Slot.clueIndex(r2c3d0.slotKey)); assertEquals(OFF_2_3, Slot.clueIndex(r2c3d0.slotKey));
assertEquals(CLUE_DOWN0, Slot.dir(r2c3d0.slotKey)); assertEquals(CLUE_DOWN0, Slot.dir(r2c3d0.slotKey));
assertFalse(Slot.horiz(r2c3d0.slotKey)); assertFalse(Slot.horiz(r2c3d0.slotKey));
var cells = Puzzle.cellWalk((byte) r2c3d0.slotKey, r2c5.or(r3c5).or(r4c5).lo(), 0L).mapToObj(i -> Masker.IT[i]).toArray(rci[]::new); var cells = Puzzle.cellWalk( r2c3d0.slotKey, r2c5.or(r3c5).or(r4c5).lo(), 0L).mapToObj(i -> Masker.IT[i]).toArray(rci[]::new);
assertEquals(2, cells[0].r()); assertEquals(2, cells[1].r());
assertEquals(3, cells[1].r());
assertEquals(4, cells[2].r());
assertEquals(5, cells[0].c());
assertEquals(5, cells[1].c()); assertEquals(5, cells[1].c());
assertEquals(3, cells[2].r());
assertEquals(5, cells[2].c()); assertEquals(5, cells[2].c());
assertEquals(4, cells[3].r());
assertEquals(5, cells[3].c());
assertTrue(Slot.horiz(CLUE_RIGHT1)); // right assertTrue(Slot.horiz(CLUE_RIGHT1)); // right
assertFalse(Slot.horiz(CLUE_DOWN0)); // down assertFalse(Slot.horiz(CLUE_DOWN0)); // down

View File

@@ -13,6 +13,7 @@ import puzzle.Export.Signa;
import puzzle.Export.Vestigium; import puzzle.Export.Vestigium;
import puzzle.SwedishGenerator.Rng; import puzzle.SwedishGenerator.Rng;
import puzzle.dict800.DictData800; import puzzle.dict800.DictData800;
import puzzle.dict800_4.DictData800_4;
import java.util.Arrays; import java.util.Arrays;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static precomp.Const3x4.Cell.r0c0d4; import static precomp.Const3x4.Cell.r0c0d4;
@@ -29,6 +30,10 @@ public class TestDuplication {
Test123X_Neighbors4x3.start(); Test123X_Neighbors4x3.start();
Test123X_Neighbors9x8.start(); Test123X_Neighbors9x8.start();
} }
static void main() {
TestDuplication test = new TestDuplication();
test.testFiller2();
}
@Test @Test
void testFiller2() { void testFiller2() {
var mask = Signa.of( var mask = Signa.of(
@@ -39,14 +44,15 @@ public class TestDuplication {
Assertions.assertEquals(5, mask.clueCount()); Assertions.assertEquals(5, mask.clueCount());
val map = mask.stream().collect(Collectors.toMap(Vestigium::index, Vestigium::clue)); val map = mask.stream().collect(Collectors.toMap(Vestigium::index, Vestigium::clue));
Assertions.assertEquals(5, map.size()); Assertions.assertEquals(5, map.size());
var slots = Masker_Neighbors3x4.slots(mask.c(), DictData800.DICT800); var slots = Masker_Neighbors3x4.slots(mask.c(), DictData800_4.DICT800);
var grid = Masker_Neighbors3x4.grid(slots); var grid = Masker_Neighbors3x4.grid(slots);
var filled = SwedishGenerator.fillMask(new Rng(1), slots, grid.lo, grid.hi, grid.g); var filled = SwedishGenerator.fillMask(new Rng(1), slots, grid.lo, grid.hi, grid.g);
grid.lo = Masker_Neighbors3x4.MASK_LO & ~mask.c().lo; grid.lo = Masker_Neighbors3x4.MASK_LO & ~mask.c().lo;
grid.hi = Masker_Neighbors3x4.MASK_HI & ~mask.c().hi; grid.hi = Masker_Neighbors3x4.MASK_HI & ~mask.c().hi;
var grid1 = new Puzzle(grid, mask.c()); var grid1 = new Puzzle(grid, mask.c());
var result = new PuzzleResult(new Signa(mask.c()), grid1, slots, filled); var result = new PuzzleResult(new Signa(mask.c()), grid1, slots, filled);
if (filled.ok()) { if (filled.ok()) {
System.out.println(filled);
val res = result.exportFormatFromFilled(new Rewards(0, 0, 0), Masker_Neighbors3x4.IT, 2); val res = result.exportFormatFromFilled(new Rewards(0, 0, 0), Masker_Neighbors3x4.IT, 2);
System.out.println(String.join("\n", res.grid())); System.out.println(String.join("\n", res.grid()));
} }