redo
This commit is contained in:
82
src/main/java/puzzle/Clues.java
Normal file
82
src/main/java/puzzle/Clues.java
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
package puzzle;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.experimental.Accessors;
|
||||||
|
import static java.lang.Long.bitCount;
|
||||||
|
import static puzzle.SwedishGenerator.X;
|
||||||
|
//@formatter:on
|
||||||
|
@AllArgsConstructor
|
||||||
|
@Accessors(fluent = true)
|
||||||
|
public final class Clues {
|
||||||
|
|
||||||
|
@Getter long lo, hi, vlo, vhi, rlo, rhi, xlo, xhi;
|
||||||
|
public static Clues createEmpty() { return new Clues(0, 0, 0, 0, 0, 0, 0, 0); }
|
||||||
|
|
||||||
|
public Clues setClue(precomp.Const9x8.Cell cell) {
|
||||||
|
if ((cell.index & 64) == 0) setClueLo(cell.mask, cell.d);
|
||||||
|
else setClueHi(cell.mask, cell.d);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setClueLo(long mask, byte idx) {
|
||||||
|
lo |= mask;
|
||||||
|
if ((idx & 1) != 0) vlo |= mask;
|
||||||
|
else vlo &= ~mask;
|
||||||
|
if ((idx & 2) != 0) rlo |= mask;
|
||||||
|
else rlo &= ~mask;
|
||||||
|
if ((idx & 4) != 0) xlo |= mask;
|
||||||
|
else xlo &= ~mask;
|
||||||
|
}
|
||||||
|
public void setClueHi(long mask, byte idx) {
|
||||||
|
hi |= mask;
|
||||||
|
if ((idx & 1) != 0) vhi |= mask;
|
||||||
|
else vhi &= ~mask;
|
||||||
|
if ((idx & 2) != 0) rhi |= mask;
|
||||||
|
else rhi &= ~mask;
|
||||||
|
if ((idx & 4) != 0) xhi |= mask;
|
||||||
|
else xhi &= ~mask;
|
||||||
|
}
|
||||||
|
public void clearClueLo(long mask) {
|
||||||
|
lo &= mask;
|
||||||
|
vlo &= mask;
|
||||||
|
rlo &= mask;
|
||||||
|
xlo &= mask;
|
||||||
|
}
|
||||||
|
public void clearClueHi(long mask) {
|
||||||
|
hi &= mask;
|
||||||
|
vhi &= mask;
|
||||||
|
rhi &= mask;
|
||||||
|
xhi &= mask;
|
||||||
|
}
|
||||||
|
public boolean isClueLo(int index) { return ((lo >>> index) & 1L) != X; }
|
||||||
|
public boolean isClueHi(int index) { return ((hi >>> (index & 63)) & 1L) != X; }
|
||||||
|
public boolean notClue(int index) { return ((index & 64) == 0) ? ((lo >>> index) & 1L) == X : ((hi >>> (index & 63)) & 1L) == X; }
|
||||||
|
|
||||||
|
public int clueCount() { return bitCount(lo) + bitCount(hi); }
|
||||||
|
|
||||||
|
public Clues from(Clues best) {
|
||||||
|
lo = best.lo;
|
||||||
|
hi = best.hi;
|
||||||
|
vlo = best.vlo;
|
||||||
|
vhi = best.vhi;
|
||||||
|
rlo = best.rlo;
|
||||||
|
rhi = best.rhi;
|
||||||
|
xlo = best.xlo;
|
||||||
|
xhi = best.xhi;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
public byte getDir(int index) {
|
||||||
|
if ((index & 64) == 0) {
|
||||||
|
var v = (vlo & (1L << index)) != 0 ? 1 : 0;
|
||||||
|
var r = (rlo & (1L << index)) != 0 ? 1 : 0;
|
||||||
|
var x = (xlo & (1L << index)) != 0 ? 1 : 0;
|
||||||
|
return (byte) ((x << 2) | (r << 1) | v);
|
||||||
|
} else {
|
||||||
|
var v = (vhi & (1L << (index & 63))) != 0 ? 1 : 0;
|
||||||
|
var r = (rhi & (1L << (index & 63))) != 0 ? 1 : 0;
|
||||||
|
var x = (xhi & (1L << (index & 63))) != 0 ? 1 : 0;
|
||||||
|
return (byte) ((x << 2) | (r << 1) | v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,7 +6,6 @@ import lombok.experimental.Delegate;
|
|||||||
import lombok.val;
|
import lombok.val;
|
||||||
import precomp.Const9x8.Cell;
|
import precomp.Const9x8.Cell;
|
||||||
import puzzle.Export.Puzzle.Replacar.Rell;
|
import puzzle.Export.Puzzle.Replacar.Rell;
|
||||||
import puzzle.Masker.Clues;
|
|
||||||
import puzzle.Meta.ShardLem;
|
import puzzle.Meta.ShardLem;
|
||||||
import puzzle.SwedishGenerator.Dict;
|
import puzzle.SwedishGenerator.Dict;
|
||||||
import puzzle.SwedishGenerator.FillResult;
|
import puzzle.SwedishGenerator.FillResult;
|
||||||
@@ -18,7 +17,7 @@ import static precomp.Const9x8.INIT_GRID_OUTPUT;
|
|||||||
import static precomp.Const9x8.INIT_GRID_OUTPUT_ARR;
|
import static precomp.Const9x8.INIT_GRID_OUTPUT_ARR;
|
||||||
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.Masker.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.Masker.C;
|
||||||
import static puzzle.SwedishGenerator.Lemma;
|
import static puzzle.SwedishGenerator.Lemma;
|
||||||
@@ -73,7 +72,7 @@ public record Export() {
|
|||||||
public Signa deepCopyGrid() { return new Signa(new Clues(c.lo, c.hi, c.vlo, c.vhi, c.rlo, c.rhi, c.xlo, c.xhi)); }
|
public Signa deepCopyGrid() { return new Signa(new Clues(c.lo, c.hi, c.vlo, c.vhi, c.rlo, c.rhi, c.xlo, c.xhi)); }
|
||||||
String gridToString() {
|
String gridToString() {
|
||||||
var sb = new StringBuilder(INIT_GRID_OUTPUT);
|
var sb = new StringBuilder(INIT_GRID_OUTPUT);
|
||||||
forEachSlot((s, _, _) -> {
|
Masker.forEachSlot(c, (s, _, _) -> {
|
||||||
val idx = Slot.clueIndex(s);
|
val idx = Slot.clueIndex(s);
|
||||||
val dir = Slot.dir(s);
|
val dir = Slot.dir(s);
|
||||||
sb.setCharAt(INDEX(INDEX_ROW(idx), C + 1, INDEX_COL(idx)), CLUE_CHAR(dir));
|
sb.setCharAt(INDEX(INDEX_ROW(idx), C + 1, INDEX_COL(idx)), CLUE_CHAR(dir));
|
||||||
@@ -106,7 +105,7 @@ public record Export() {
|
|||||||
record Puzzle(@Delegate Grid grid, Clues cl)
|
record Puzzle(@Delegate Grid grid, Clues cl)
|
||||||
implements Stream<Lettrix> {
|
implements Stream<Lettrix> {
|
||||||
|
|
||||||
public Puzzle(Clues clues) { this(clues.toGrid(), clues); }
|
public Puzzle(Clues clues) { this(Masker.toGrid(clues), clues); }
|
||||||
public Puzzle(Signa clues) { this(clues.c); }
|
public Puzzle(Signa clues) { this(clues.c); }
|
||||||
public @Delegate Stream<Lettrix> stream() {
|
public @Delegate Stream<Lettrix> stream() {
|
||||||
val stream = Stream.<Lettrix>builder();
|
val stream = Stream.<Lettrix>builder();
|
||||||
@@ -116,7 +115,7 @@ public record Export() {
|
|||||||
}
|
}
|
||||||
String gridToString() {
|
String gridToString() {
|
||||||
var sb = INIT_GRID_OUTPUT_ARR.clone();
|
var sb = INIT_GRID_OUTPUT_ARR.clone();
|
||||||
cl.forEachSlot((s, _, _) -> {
|
Masker.forEachSlot(cl, (s, _, _) -> {
|
||||||
val idx = Slot.clueIndex(s);
|
val idx = Slot.clueIndex(s);
|
||||||
val r = idx & 7;
|
val r = idx & 7;
|
||||||
val c = idx >>> 3;
|
val c = idx >>> 3;
|
||||||
@@ -128,7 +127,7 @@ public record Export() {
|
|||||||
}
|
}
|
||||||
public String[] exportGrid(Replacar clueChar, char emptyFallback) {
|
public String[] exportGrid(Replacar clueChar, char emptyFallback) {
|
||||||
var sb = INIT_GRID_OUTPUT_ARR.clone();
|
var sb = INIT_GRID_OUTPUT_ARR.clone();
|
||||||
cl.forEachSlot((s, l, a) -> {
|
Masker.forEachSlot(cl, (s, l, a) -> {
|
||||||
val idx = Slot.clueIndex(s);
|
val idx = Slot.clueIndex(s);
|
||||||
val r = idx & 7;
|
val r = idx & 7;
|
||||||
val c = idx >>> 3;
|
val c = idx >>> 3;
|
||||||
|
|||||||
@@ -5,9 +5,7 @@ import anno.DictGen;
|
|||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import lombok.SneakyThrows;
|
|
||||||
import lombok.val;
|
import lombok.val;
|
||||||
import puzzle.Masker.Clues;
|
|
||||||
import puzzle.SwedishGenerator.Rng;
|
import puzzle.SwedishGenerator.Rng;
|
||||||
|
|
||||||
import static puzzle.Export.*;
|
import static puzzle.Export.*;
|
||||||
@@ -358,7 +356,7 @@ public class Main {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
static Clues generateNewClues(Rng rng, Opts opts) {
|
static Clues generateNewClues(Rng rng, Opts opts) {
|
||||||
var masker = new Masker(rng, new int[Masker.STACK_SIZE], Masker.Clues.createEmpty());
|
var masker = new Masker(rng, new int[Masker.STACK_SIZE], Clues.createEmpty());
|
||||||
return masker.generateMask(opts.clueSize, opts.pop, opts.gens, opts.offspring);
|
return masker.generateMask(opts.clueSize, opts.pop, opts.gens, opts.offspring);
|
||||||
}
|
}
|
||||||
static PuzzleResult _attempt(Rng rng, Dict dict, Opts opts) {
|
static PuzzleResult _attempt(Rng rng, Dict dict, Opts opts) {
|
||||||
|
|||||||
@@ -3,9 +3,6 @@ package puzzle;
|
|||||||
import module java.base;
|
import module java.base;
|
||||||
import anno.GenerateShapedCopies;
|
import anno.GenerateShapedCopies;
|
||||||
import anno.Shaped;
|
import anno.Shaped;
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.experimental.Accessors;
|
|
||||||
import lombok.val;
|
import lombok.val;
|
||||||
import precomp.Neighbors9x8;
|
import precomp.Neighbors9x8;
|
||||||
import gen.rci;
|
import gen.rci;
|
||||||
@@ -13,7 +10,7 @@ import gen.rci;
|
|||||||
import static java.lang.Long.*;
|
import static java.lang.Long.*;
|
||||||
import static puzzle.SwedishGenerator.*;
|
import static puzzle.SwedishGenerator.*;
|
||||||
@GenerateShapedCopies(
|
@GenerateShapedCopies(
|
||||||
packageName = "gen",
|
packageName = "puzzle",
|
||||||
className = "Masker",
|
className = "Masker",
|
||||||
shapes = { "precomp.Neighbors9x8", "precomp.Neighbors4x3" }
|
shapes = { "precomp.Neighbors9x8", "precomp.Neighbors4x3" }
|
||||||
)
|
)
|
||||||
@@ -31,6 +28,7 @@ public final class Masker {
|
|||||||
@Shaped public static final double SIZED = Neighbors9x8.SIZED;// ~18
|
@Shaped public static final double SIZED = Neighbors9x8.SIZED;// ~18
|
||||||
@Shaped private static final long[] NBR_LO = Neighbors9x8.NBR_LO;
|
@Shaped private static final long[] NBR_LO = Neighbors9x8.NBR_LO;
|
||||||
@Shaped private static final long[] NBR_HI = Neighbors9x8.NBR_HI;
|
@Shaped private static final long[] NBR_HI = Neighbors9x8.NBR_HI;
|
||||||
|
public static final int[][] MUTATE_RI = new int[SIZE][625];
|
||||||
private static final boolean VERBOSE = false;
|
private static final boolean VERBOSE = false;
|
||||||
private final int[] activeCIdx = new int[SIZE];
|
private final int[] activeCIdx = new int[SIZE];
|
||||||
private final long[] activeSLo = new long[SIZE];
|
private final long[] activeSLo = new long[SIZE];
|
||||||
@@ -49,6 +47,12 @@ public final class Masker {
|
|||||||
this.cache = cache;
|
this.cache = cache;
|
||||||
}
|
}
|
||||||
public static boolean isLo(int n) { return (n & 64) == 0; }
|
public static boolean isLo(int n) { return (n & 64) == 0; }
|
||||||
|
public static double similarity(Clues a, Clues b) {
|
||||||
|
var matchLo = (~(a.lo ^ b.lo)) & (~a.lo | (~(a.vlo ^ b.vlo) & ~(a.rlo ^ b.rlo) & ~(a.xlo ^ b.xlo)));
|
||||||
|
var matchHi = (~(a.hi ^ b.hi)) & (~a.hi | (~(a.vhi ^ b.vhi) & ~(a.rhi ^ b.rhi) & ~(a.xhi ^ b.xhi)));
|
||||||
|
|
||||||
|
return (bitCount(matchLo & MASK_LO) + bitCount(matchHi & MASK_HI)) / SIZED;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isValid(Clues c) {
|
public boolean isValid(Clues c) {
|
||||||
return findOffendingClue(c) == -1;
|
return findOffendingClue(c) == -1;
|
||||||
@@ -91,7 +95,7 @@ public final class Masker {
|
|||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
public static Grid toGrid(Clues c) { return new Grid(new byte[SIZE], c.lo, c.hi); }
|
||||||
public void cleanup(Clues c) {
|
public void cleanup(Clues c) {
|
||||||
var guard = 0;
|
var guard = 0;
|
||||||
while (guard++ < 50) {
|
while (guard++ < 50) {
|
||||||
@@ -102,10 +106,8 @@ public final class Masker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final int[][] MUTATE_RI = new int[Neighbors9x8.SIZE][625];
|
|
||||||
|
|
||||||
static {
|
static {
|
||||||
for (var i = 0; i < Neighbors9x8.SIZE; i++) {
|
for (var i = 0; i < SIZE; i++) {
|
||||||
var k = 0;
|
var k = 0;
|
||||||
for (var dr1 = -2; dr1 <= 2; dr1++)
|
for (var dr1 = -2; dr1 <= 2; dr1++)
|
||||||
for (var dr2 = -2; dr2 <= 2; dr2++)
|
for (var dr2 = -2; dr2 <= 2; dr2++)
|
||||||
@@ -120,7 +122,7 @@ public final class Masker {
|
|||||||
// slice ray to stop before first clue, depending on direction monotonicity
|
// slice ray to stop before first clue, depending on direction monotonicity
|
||||||
// right/down => increasing indices; up/left => decreasing indices
|
// right/down => increasing indices; up/left => decreasing indices
|
||||||
// first clue is highest index among hits (hi first, then lo)
|
// first clue is highest index among hits (hi first, then lo)
|
||||||
private static void processSlotRev(Clues c, SlotVisitor visitor, int key) {
|
static void processSlotRev(Clues c, SlotVisitor visitor, int key) {
|
||||||
var rayLo = PATH_LO[key];
|
var rayLo = PATH_LO[key];
|
||||||
var rayHi = PATH_HI[key];
|
var rayHi = PATH_HI[key];
|
||||||
// only consider clue cells
|
// only consider clue cells
|
||||||
@@ -140,7 +142,7 @@ public final class Masker {
|
|||||||
if (Long.bitCount(rayLo) + Long.bitCount(rayHi) >= MIN_LEN)
|
if (Long.bitCount(rayLo) + Long.bitCount(rayHi) >= MIN_LEN)
|
||||||
visitor.visit(key, rayLo, rayHi);
|
visitor.visit(key, rayLo, rayHi);
|
||||||
}
|
}
|
||||||
private static boolean validSlotRev(long lo, long hi, int key) {
|
static boolean validSlotRev(long lo, long hi, int key) {
|
||||||
var rayLo = PATH_LO[key];
|
var rayLo = PATH_LO[key];
|
||||||
var rayHi = PATH_HI[key];
|
var rayHi = PATH_HI[key];
|
||||||
// only consider clue cells
|
// only consider clue cells
|
||||||
@@ -151,7 +153,7 @@ public final class Masker {
|
|||||||
else if (hitsLo != X) return (Long.bitCount(rayLo & -(1L << 63 - numberOfLeadingZeros(hitsLo) << 1)) + Long.bitCount(rayHi) >= MIN_LEN);
|
else if (hitsLo != X) return (Long.bitCount(rayLo & -(1L << 63 - numberOfLeadingZeros(hitsLo) << 1)) + Long.bitCount(rayHi) >= MIN_LEN);
|
||||||
else return (Long.bitCount(rayLo) + Long.bitCount(rayHi) >= MIN_LEN);
|
else return (Long.bitCount(rayLo) + Long.bitCount(rayHi) >= MIN_LEN);
|
||||||
}
|
}
|
||||||
private static boolean validSlot(long lo, long hi, int key) {
|
static boolean validSlot(long lo, long hi, int key) {
|
||||||
var rayLo = PATH_LO[key];
|
var rayLo = PATH_LO[key];
|
||||||
var rayHi = PATH_HI[key];
|
var rayHi = PATH_HI[key];
|
||||||
var hitsLo = rayLo & lo;
|
var hitsLo = rayLo & lo;
|
||||||
@@ -161,7 +163,7 @@ public final class Masker {
|
|||||||
else if (hitsHi != X) return (Long.bitCount(rayLo) + Long.bitCount(rayHi & ((1L << numberOfTrailingZeros(hitsHi)) - 1)) >= MIN_LEN);
|
else if (hitsHi != X) return (Long.bitCount(rayLo) + Long.bitCount(rayHi & ((1L << numberOfTrailingZeros(hitsHi)) - 1)) >= MIN_LEN);
|
||||||
else return (Long.bitCount(rayLo) + Long.bitCount(rayHi) >= MIN_LEN);
|
else return (Long.bitCount(rayLo) + Long.bitCount(rayHi) >= MIN_LEN);
|
||||||
}
|
}
|
||||||
private static void processSlot(Clues c, SlotVisitor visitor, int key) {
|
static void processSlot(Clues c, SlotVisitor visitor, int key) {
|
||||||
var rayLo = PATH_LO[key];
|
var rayLo = PATH_LO[key];
|
||||||
var rayHi = PATH_HI[key];
|
var rayHi = PATH_HI[key];
|
||||||
var hitsLo = rayLo & c.lo;
|
var hitsLo = rayLo & c.lo;
|
||||||
@@ -178,9 +180,25 @@ public final class Masker {
|
|||||||
if (Long.bitCount(rayLo) + Long.bitCount(rayHi) >= MIN_LEN)
|
if (Long.bitCount(rayLo) + Long.bitCount(rayHi) >= MIN_LEN)
|
||||||
visitor.visit(key, rayLo, rayHi);
|
visitor.visit(key, rayLo, rayHi);
|
||||||
}
|
}
|
||||||
|
public static void forEachSlot(Clues c,SlotVisitor visitor) {
|
||||||
|
final long lo = c.lo, hi = c.hi, xlo = c.xlo, xhi = c.xhi, rlo = c.rlo, rhi = c.rhi, vlo = c.vlo, vhi = c.vhi;
|
||||||
|
for (var l = lo & ~xlo & ~rlo & vlo; l != X; l &= l - 1) processSlot(c, visitor, Slot.packSlotKey(numberOfTrailingZeros(l), 1));
|
||||||
|
for (var l = lo & ~xlo & ~rlo & ~vlo; l != X; l &= l - 1) processSlot(c, visitor, Slot.packSlotKey(numberOfTrailingZeros(l), 0));
|
||||||
|
for (var l = lo & ~xlo & rlo & ~vlo; l != X; l &= l - 1) processSlotRev(c, visitor, Slot.packSlotKey(numberOfTrailingZeros(l), 2));
|
||||||
|
for (var l = lo & ~xlo & rlo & vlo; l != X; l &= l - 1) processSlotRev(c, visitor, Slot.packSlotKey(numberOfTrailingZeros(l), 3));
|
||||||
|
for (var l = lo & xlo & ~rlo & ~vlo; l != X; l &= l - 1) processSlot(c, visitor, Slot.packSlotKey(numberOfTrailingZeros(l), 4));
|
||||||
|
for (var l = lo & xlo & ~rlo & vlo; l != X; l &= l - 1) processSlot(c, visitor, Slot.packSlotKey(numberOfTrailingZeros(l), 5));
|
||||||
|
|
||||||
|
for (var h = hi & ~xhi & ~rhi & vhi; h != X; h &= h - 1) processSlot(c, visitor, Slot.packSlotKey(64 | numberOfTrailingZeros(h), 1));
|
||||||
|
for (var h = hi & ~xhi & ~rhi & ~vhi; h != X; h &= h - 1) processSlot(c, visitor, Slot.packSlotKey(64 | numberOfTrailingZeros(h), 0));
|
||||||
|
for (var h = hi & ~xhi & rhi & ~vhi; h != X; h &= h - 1) processSlotRev(c, visitor, Slot.packSlotKey((64 | numberOfTrailingZeros(h)), 2));
|
||||||
|
for (var h = hi & ~xhi & rhi & vhi; h != X; h &= h - 1) processSlotRev(c, visitor, Slot.packSlotKey((64 | numberOfTrailingZeros(h)), 3));
|
||||||
|
for (var h = hi & xhi & ~rhi & ~vhi; h != X; h &= h - 1) processSlot(c, visitor, Slot.packSlotKey(64 | numberOfTrailingZeros(h), 4));
|
||||||
|
for (var h = hi & xhi & ~rhi & vhi; h != X; h &= h - 1) processSlot(c, visitor, Slot.packSlotKey(64 | numberOfTrailingZeros(h), 5));
|
||||||
|
}
|
||||||
public static Slot[] extractSlots(Clues c, DictEntry[] index, DictEntry[] rev) {
|
public static Slot[] extractSlots(Clues c, DictEntry[] index, DictEntry[] rev) {
|
||||||
var slots = new ArrayList<Slot>(c.clueCount());
|
var slots = new ArrayList<Slot>(c.clueCount());
|
||||||
c.forEachSlot((key, lo, hi) -> slots.add(Slot.from(key, lo, hi, Slotinfo.increasing(key) ? index[Slot.length(lo, hi)] : rev[Slot.length(lo, hi)])));
|
forEachSlot(c,(key, lo, hi) -> slots.add(Slot.from(key, lo, hi, Slotinfo.increasing(key) ? index[Slot.length(lo, hi)] : rev[Slot.length(lo, hi)])));
|
||||||
return slots.toArray(Slot[]::new);
|
return slots.toArray(Slot[]::new);
|
||||||
}
|
}
|
||||||
public static Slotinfo[] slots(Clues mask, Dict d) { return slots(mask, d.index(), d.reversed()); }
|
public static Slotinfo[] slots(Clues mask, Dict d) { return slots(mask, d.index(), d.reversed()); }
|
||||||
@@ -437,7 +455,10 @@ public final class Masker {
|
|||||||
|
|
||||||
return penalty;
|
return penalty;
|
||||||
}
|
}
|
||||||
|
public static boolean hasRoomForClue(Clues c,int key) {
|
||||||
|
if (Slotinfo.increasing(key)) if (!validSlot(c.lo, c.hi, key)) return false;
|
||||||
|
return validSlotRev(c.lo, c.hi, key);
|
||||||
|
}
|
||||||
public Clues randomMask(final int clueSize) {
|
public Clues randomMask(final int clueSize) {
|
||||||
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++) {
|
||||||
@@ -447,7 +468,7 @@ public final class Masker {
|
|||||||
if (g.isClueLo(ri)) continue;
|
if (g.isClueLo(ri)) continue;
|
||||||
var d_idx = rng.randomClueDir();
|
var d_idx = rng.randomClueDir();
|
||||||
var key = Slot.packSlotKey(ri, d_idx);
|
var key = Slot.packSlotKey(ri, d_idx);
|
||||||
if (g.hasRoomForClue(key)) {
|
if (hasRoomForClue(g,key)) {
|
||||||
g.setClueLo(1L << ri, d_idx);
|
g.setClueLo(1L << ri, d_idx);
|
||||||
if (isValid(g)) placed++;
|
if (isValid(g)) placed++;
|
||||||
else g.clearClueLo(~(1L << ri));
|
else g.clearClueLo(~(1L << ri));
|
||||||
@@ -456,7 +477,7 @@ public final class Masker {
|
|||||||
if (g.isClueHi(ri)) continue;
|
if (g.isClueHi(ri)) continue;
|
||||||
var d_idx = rng.randomClueDir();
|
var d_idx = rng.randomClueDir();
|
||||||
var key = Slot.packSlotKey(ri, d_idx);
|
var key = Slot.packSlotKey(ri, d_idx);
|
||||||
if (g.hasRoomForClue(key)) {
|
if (hasRoomForClue(g,key)) {
|
||||||
g.setClueHi(1L << (ri & 63), d_idx);
|
g.setClueHi(1L << (ri & 63), d_idx);
|
||||||
if (isValid(g)) placed++;
|
if (isValid(g)) placed++;
|
||||||
else g.clearClueHi(~(1L << (ri & 63)));
|
else g.clearClueHi(~(1L << (ri & 63)));
|
||||||
@@ -474,7 +495,7 @@ public final class Masker {
|
|||||||
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);
|
||||||
if (c.hasRoomForClue(key)) {
|
if (hasRoomForClue(c,key)) {
|
||||||
if (isLo(ri)) {
|
if (isLo(ri)) {
|
||||||
c.setClueLo(1L << ri, d);
|
c.setClueLo(1L << ri, d);
|
||||||
if (!isValid(c)) c.clearClueLo(~(1L << ri));
|
if (!isValid(c)) c.clearClueLo(~(1L << ri));
|
||||||
@@ -502,7 +523,7 @@ public final class Masker {
|
|||||||
if (op < 4) { // CHANGE DIRECTION
|
if (op < 4) { // CHANGE DIRECTION
|
||||||
var d = rng.randomClueDir();
|
var d = rng.randomClueDir();
|
||||||
var key = Slot.packSlotKey(ri, d);
|
var key = Slot.packSlotKey(ri, d);
|
||||||
if (c.hasRoomForClue(key)) {
|
if (hasRoomForClue(c,key)) {
|
||||||
var oldD = c.getDir(ri);
|
var oldD = c.getDir(ri);
|
||||||
if (isLo(ri)) {
|
if (isLo(ri)) {
|
||||||
c.setClueLo(1L << ri, d);
|
c.setClueLo(1L << ri, d);
|
||||||
@@ -519,7 +540,7 @@ public final class Masker {
|
|||||||
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);
|
||||||
if (c.hasRoomForClue(nkey)) {
|
if (hasRoomForClue(c,nkey)) {
|
||||||
if (isLo(ri)) c.clearClueLo(~(1L << ri));
|
if (isLo(ri)) c.clearClueLo(~(1L << ri));
|
||||||
else c.clearClueHi(~(1L << (ri & 63)));
|
else c.clearClueHi(~(1L << (ri & 63)));
|
||||||
if (isLo(nri)) c.setClueLo(1L << nri, d);
|
if (isLo(nri)) c.setClueLo(1L << nri, d);
|
||||||
@@ -626,7 +647,7 @@ public final class Masker {
|
|||||||
if (nextCount >= popSize) break;
|
if (nextCount >= popSize) break;
|
||||||
var unique = true;
|
var unique = true;
|
||||||
for (var i = 0; i < nextCount; i++) {
|
for (var i = 0; i < nextCount; i++) {
|
||||||
if (cand.grid.similarity(next[i].grid) > 0.92) {
|
if (similarity(cand.grid, next[i].grid) > 0.92) {
|
||||||
unique = false;
|
unique = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -661,108 +682,6 @@ public final class Masker {
|
|||||||
}
|
}
|
||||||
//@formatter:off
|
//@formatter:off
|
||||||
@FunctionalInterface public interface SlotVisitor { void visit(int key, long lo, long hi); }
|
@FunctionalInterface public interface SlotVisitor { void visit(int key, long lo, long hi); }
|
||||||
//@formatter:on
|
|
||||||
@AllArgsConstructor
|
|
||||||
@Accessors(fluent = true)
|
|
||||||
public static final class Clues {
|
|
||||||
|
|
||||||
@Getter long lo, hi, vlo, vhi, rlo, rhi, xlo, xhi;
|
|
||||||
public static Clues createEmpty() { return new Clues(0, 0, 0, 0, 0, 0, 0, 0); }
|
|
||||||
|
|
||||||
public boolean hasRoomForClue(int key) {
|
|
||||||
if (Slotinfo.increasing(key)) if (!validSlot(lo, hi, key)) return false;
|
|
||||||
return validSlotRev(lo, hi, key);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Clues setClue(precomp.Const9x8.Cell cell) {
|
|
||||||
if ((cell.index & 64) == 0) setClueLo(cell.mask, cell.d);
|
|
||||||
else setClueHi(cell.mask, cell.d);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setClueLo(long mask, byte idx) {
|
|
||||||
lo |= mask;
|
|
||||||
if ((idx & 1) != 0) vlo |= mask;
|
|
||||||
else vlo &= ~mask;
|
|
||||||
if ((idx & 2) != 0) rlo |= mask;
|
|
||||||
else rlo &= ~mask;
|
|
||||||
if ((idx & 4) != 0) xlo |= mask;
|
|
||||||
else xlo &= ~mask;
|
|
||||||
}
|
|
||||||
public void setClueHi(long mask, byte idx) {
|
|
||||||
hi |= mask;
|
|
||||||
if ((idx & 1) != 0) vhi |= mask;
|
|
||||||
else vhi &= ~mask;
|
|
||||||
if ((idx & 2) != 0) rhi |= mask;
|
|
||||||
else rhi &= ~mask;
|
|
||||||
if ((idx & 4) != 0) xhi |= mask;
|
|
||||||
else xhi &= ~mask;
|
|
||||||
}
|
|
||||||
public void clearClueLo(long mask) {
|
|
||||||
lo &= mask;
|
|
||||||
vlo &= mask;
|
|
||||||
rlo &= mask;
|
|
||||||
xlo &= mask;
|
|
||||||
}
|
|
||||||
public void clearClueHi(long mask) {
|
|
||||||
hi &= mask;
|
|
||||||
vhi &= mask;
|
|
||||||
rhi &= mask;
|
|
||||||
xhi &= mask;
|
|
||||||
}
|
|
||||||
public boolean isClueLo(int index) { return ((lo >>> index) & 1L) != X; }
|
|
||||||
public boolean isClueHi(int index) { return ((hi >>> (index & 63)) & 1L) != X; }
|
|
||||||
public boolean notClue(int index) { return ((index & 64) == 0) ? ((lo >>> index) & 1L) == X : ((hi >>> (index & 63)) & 1L) == X; }
|
|
||||||
|
|
||||||
public int clueCount() { return bitCount(lo) + bitCount(hi); }
|
|
||||||
public double similarity(Clues b) {
|
|
||||||
var matchLo = (~(lo ^ b.lo)) & (~lo | (~(vlo ^ b.vlo) & ~(rlo ^ b.rlo) & ~(xlo ^ b.xlo)));
|
|
||||||
var matchHi = (~(hi ^ b.hi)) & (~hi | (~(vhi ^ b.vhi) & ~(rhi ^ b.rhi) & ~(xhi ^ b.xhi)));
|
|
||||||
|
|
||||||
return (bitCount(matchLo & MASK_LO) + bitCount(matchHi & MASK_HI)) / SIZED;
|
|
||||||
}
|
|
||||||
public Grid toGrid() { return new Grid(new byte[SIZE], lo, hi); }
|
|
||||||
|
|
||||||
public void forEachSlot(SlotVisitor visitor) {
|
|
||||||
for (var l = lo & ~xlo & ~rlo & vlo; l != X; l &= l - 1) processSlot(this, visitor, Slot.packSlotKey(numberOfTrailingZeros(l), 1));
|
|
||||||
for (var l = lo & ~xlo & ~rlo & ~vlo; l != X; l &= l - 1) processSlot(this, visitor, Slot.packSlotKey(numberOfTrailingZeros(l), 0));
|
|
||||||
for (var l = lo & ~xlo & rlo & ~vlo; l != X; l &= l - 1) processSlotRev(this, visitor, Slot.packSlotKey(numberOfTrailingZeros(l), 2));
|
|
||||||
for (var l = lo & ~xlo & rlo & vlo; l != X; l &= l - 1) processSlotRev(this, visitor, Slot.packSlotKey(numberOfTrailingZeros(l), 3));
|
|
||||||
for (var l = lo & xlo & ~rlo & ~vlo; l != X; l &= l - 1) processSlot(this, visitor, Slot.packSlotKey(numberOfTrailingZeros(l), 4));
|
|
||||||
for (var l = lo & xlo & ~rlo & vlo; l != X; l &= l - 1) processSlot(this, visitor, Slot.packSlotKey(numberOfTrailingZeros(l), 5));
|
|
||||||
|
|
||||||
for (var h = hi & ~xhi & ~rhi & vhi; h != X; h &= h - 1) processSlot(this, visitor, Slot.packSlotKey(64 | numberOfTrailingZeros(h), 1));
|
|
||||||
for (var h = hi & ~xhi & ~rhi & ~vhi; h != X; h &= h - 1) processSlot(this, visitor, Slot.packSlotKey(64 | numberOfTrailingZeros(h), 0));
|
|
||||||
for (var h = hi & ~xhi & rhi & ~vhi; h != X; h &= h - 1) processSlotRev(this, visitor, Slot.packSlotKey((64 | numberOfTrailingZeros(h)), 2));
|
|
||||||
for (var h = hi & ~xhi & rhi & vhi; h != X; h &= h - 1) processSlotRev(this, visitor, Slot.packSlotKey((64 | numberOfTrailingZeros(h)), 3));
|
|
||||||
for (var h = hi & xhi & ~rhi & ~vhi; h != X; h &= h - 1) processSlot(this, visitor, Slot.packSlotKey(64 | numberOfTrailingZeros(h), 4));
|
|
||||||
for (var h = hi & xhi & ~rhi & vhi; h != X; h &= h - 1) processSlot(this, visitor, Slot.packSlotKey(64 | numberOfTrailingZeros(h), 5));
|
|
||||||
}
|
|
||||||
public Clues from(Clues best) {
|
|
||||||
lo = best.lo;
|
|
||||||
hi = best.hi;
|
|
||||||
vlo = best.vlo;
|
|
||||||
vhi = best.vhi;
|
|
||||||
rlo = best.rlo;
|
|
||||||
rhi = best.rhi;
|
|
||||||
xlo = best.xlo;
|
|
||||||
xhi = best.xhi;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
public byte getDir(int index) {
|
|
||||||
if ((index & 64) == 0) {
|
|
||||||
var v = (vlo & (1L << index)) != 0 ? 1 : 0;
|
|
||||||
var r = (rlo & (1L << index)) != 0 ? 1 : 0;
|
|
||||||
var x = (xlo & (1L << index)) != 0 ? 1 : 0;
|
|
||||||
return (byte) ((x << 2) | (r << 1) | v);
|
|
||||||
} else {
|
|
||||||
var v = (vhi & (1L << (index & 63))) != 0 ? 1 : 0;
|
|
||||||
var r = (rhi & (1L << (index & 63))) != 0 ? 1 : 0;
|
|
||||||
var x = (xhi & (1L << (index & 63))) != 0 ? 1 : 0;
|
|
||||||
return (byte) ((x << 2) | (r << 1) | v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public record Slot(int key, long lo, long hi, DictEntry entry) {
|
public record Slot(int key, long lo, long hi, DictEntry entry) {
|
||||||
|
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ public class MainTest {
|
|||||||
@Test
|
@Test
|
||||||
void testForEachSlot() {
|
void testForEachSlot() {
|
||||||
var count = new AtomicInteger(0);
|
var count = new AtomicInteger(0);
|
||||||
Signa.of(r0c0d1).forEachSlot((key, lo, hi) -> {
|
Masker.forEachSlot(Signa.of(r0c0d1).c(), (key, lo, hi) -> {
|
||||||
count.incrementAndGet();
|
count.incrementAndGet();
|
||||||
assertEquals(8, Long.bitCount(lo) + Long.bitCount(hi));
|
assertEquals(8, Long.bitCount(lo) + Long.bitCount(hi));
|
||||||
assertEquals(0, Masker.IT[Long.numberOfTrailingZeros(lo)].r());
|
assertEquals(0, Masker.IT[Long.numberOfTrailingZeros(lo)].r());
|
||||||
@@ -181,7 +181,7 @@ public class MainTest {
|
|||||||
);
|
);
|
||||||
var slotInfo = mask.slots(DictData950.DICT950);
|
var slotInfo = mask.slots(DictData950.DICT950);
|
||||||
var grid = Slotinfo.grid(slotInfo);
|
var grid = Slotinfo.grid(slotInfo);
|
||||||
var filled = fillMask(rng, slotInfo, grid.lo,grid.hi, grid.g);
|
var filled = fillMask(rng, slotInfo, grid.lo, grid.hi, grid.g);
|
||||||
Assertions.assertTrue(filled.ok(), "Puzzle generation failed (not ok)");
|
Assertions.assertTrue(filled.ok(), "Puzzle generation failed (not ok)");
|
||||||
Assertions.assertEquals(17, Slotinfo.wordCount(0, slotInfo), "Number of assigned words changed");
|
Assertions.assertEquals(17, Slotinfo.wordCount(0, slotInfo), "Number of assigned words changed");
|
||||||
Assertions.assertEquals("BEADEMT", Lemma.asWord(slotInfo[0].assign().w, Export.BYTES.get()));
|
Assertions.assertEquals("BEADEMT", Lemma.asWord(slotInfo[0].assign().w, Export.BYTES.get()));
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import puzzle.Export.Puzzle;
|
|||||||
import puzzle.Export.Placed;
|
import puzzle.Export.Placed;
|
||||||
import puzzle.Export.PuzzleResult;
|
import puzzle.Export.PuzzleResult;
|
||||||
import puzzle.Export.Rewards;
|
import puzzle.Export.Rewards;
|
||||||
import puzzle.Masker.Clues;
|
|
||||||
import puzzle.SwedishGenerator.Assign;
|
import puzzle.SwedishGenerator.Assign;
|
||||||
import puzzle.SwedishGenerator.FillResult;
|
import puzzle.SwedishGenerator.FillResult;
|
||||||
import puzzle.SwedishGenerator.Lemma;
|
import puzzle.SwedishGenerator.Lemma;
|
||||||
@@ -52,7 +51,7 @@ public class MarkerTest {
|
|||||||
val orig = cache.from(clues);
|
val orig = cache.from(clues);
|
||||||
simCount++;
|
simCount++;
|
||||||
masker.mutate(clues);
|
masker.mutate(clues);
|
||||||
sim += orig.similarity(clues);
|
sim += Masker.similarity(orig, clues);
|
||||||
assertTrue(masker.isValid(clues), "Mask should be valid for length \n" + new Signa(clues).gridToString());
|
assertTrue(masker.isValid(clues), "Mask should be valid for length \n" + new Signa(clues).gridToString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -71,7 +70,7 @@ public class MarkerTest {
|
|||||||
var clues2 = masker.randomMask(j);
|
var clues2 = masker.randomMask(j);
|
||||||
simCount++;
|
simCount++;
|
||||||
var cross = masker.crossover(clues, clues2);
|
var cross = masker.crossover(clues, clues2);
|
||||||
sim += Math.max(cross.similarity(clues), cross.similarity(clues2));
|
sim += Math.max(Masker.similarity(cross, clues), Masker.similarity(cross, clues2));
|
||||||
assertTrue(masker.isValid(cross), "Mask should be valid for length \n" + new Signa(cross).gridToString());
|
assertTrue(masker.isValid(cross), "Mask should be valid for length \n" + new Signa(cross).gridToString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -83,17 +82,17 @@ public class MarkerTest {
|
|||||||
var b = Signa.of(r0c0d1, r2c1d0).c();
|
var b = Signa.of(r0c0d1, r2c1d0).c();
|
||||||
|
|
||||||
// Identity
|
// Identity
|
||||||
assertEquals(1.0, a.similarity(b), 0.001);
|
assertEquals(1.0, Masker.similarity(a, b), 0.001);
|
||||||
|
|
||||||
// Different direction
|
// Different direction
|
||||||
var c = Signa.of(r0c0d0, r2c1d0);
|
var c = Signa.of(r0c0d0, r2c1d0);
|
||||||
assertTrue(a.similarity(c.c()) < 1.0);
|
assertTrue(Masker.similarity(a, c.c()) < 1.0);
|
||||||
|
|
||||||
// Completely different
|
// Completely different
|
||||||
var d = Clues.createEmpty();
|
var d = Clues.createEmpty();
|
||||||
// Matching empty cells count towards similarity.
|
// Matching empty cells count towards similarity.
|
||||||
// a has 2 clues, d has 0. They match on 70 empty cells.
|
// a has 2 clues, d has 0. They match on 70 empty cells.
|
||||||
assertEquals(70.0 / 72.0, a.similarity(d), 0.001);
|
assertEquals(70.0 / 72.0, Masker.similarity(a, d), 0.001);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -113,22 +112,22 @@ public class MarkerTest {
|
|||||||
var g = Clues.createEmpty();
|
var g = Clues.createEmpty();
|
||||||
|
|
||||||
// Room for Right clue at (0,0) (length 8)
|
// Room for Right clue at (0,0) (length 8)
|
||||||
assertTrue(g.hasRoomForClue(r0c0d1.slotKey));
|
assertTrue(Masker.hasRoomForClue(g,r0c0d1.slotKey));
|
||||||
|
|
||||||
// No room for Right clue at (0,8) (length 0 < MIN_LEN)
|
// No room for Right clue at (0,8) (length 0 < MIN_LEN)
|
||||||
assertFalse(g.hasRoomForClue(r0c8d1.slotKey));
|
assertFalse(Masker.hasRoomForClue(g,r0c8d1.slotKey));
|
||||||
|
|
||||||
// Blocked room
|
// Blocked room
|
||||||
// Let's place a clue that leaves only 1 cell for another clue.
|
// Let's place a clue that leaves only 1 cell for another clue.
|
||||||
g.setClue(r0c2d1);
|
g.setClue(r0c2d1);
|
||||||
// Now Right at (0,0) only has (0,1) available -> length 1 < MIN_LEN (which is 2)
|
// Now Right at (0,0) only has (0,1) available -> length 1 < MIN_LEN (which is 2)
|
||||||
assertFalse(g.hasRoomForClue(r0c0d1.slotKey));
|
assertFalse(Masker.hasRoomForClue(g,r0c0d1.slotKey));
|
||||||
|
|
||||||
// But enough room
|
// But enough room
|
||||||
g.clearClueLo(0L);
|
g.clearClueLo(0L);
|
||||||
g.setClue(r0c3d1);
|
g.setClue(r0c3d1);
|
||||||
// Now Right at (0,0) has (0,1), (0,2) -> length 2 == MIN_LEN
|
// Now Right at (0,0) has (0,1), (0,2) -> length 2 == MIN_LEN
|
||||||
assertTrue(g.hasRoomForClue(r0c0d1.slotKey));
|
assertTrue(Masker.hasRoomForClue(g,r0c0d1.slotKey));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -239,7 +238,7 @@ public class MarkerTest {
|
|||||||
|
|
||||||
// Controleer of forEachSlot het slot vindt
|
// Controleer of forEachSlot het slot vindt
|
||||||
final var found = new boolean[]{ false };
|
final var found = new boolean[]{ false };
|
||||||
clues.forEachSlot((key, lo, hi) -> {
|
Masker.forEachSlot(clues.c(), (key, lo, hi) -> {
|
||||||
if (key == r0c0d4.slotKey) {
|
if (key == r0c0d4.slotKey) {
|
||||||
found[0] = true;
|
found[0] = true;
|
||||||
// Woord zou moeten starten op (0,1)
|
// Woord zou moeten starten op (0,1)
|
||||||
@@ -269,7 +268,7 @@ public class MarkerTest {
|
|||||||
|
|
||||||
// Controleer of forEachSlot het slot vindt
|
// Controleer of forEachSlot het slot vindt
|
||||||
final var found = new boolean[]{ false };
|
final var found = new boolean[]{ false };
|
||||||
clues.forEachSlot((key, lo, hi) -> {
|
Masker.forEachSlot(clues.c(), (key, lo, hi) -> {
|
||||||
if (key == r0c1d5.slotKey) {
|
if (key == r0c1d5.slotKey) {
|
||||||
found[0] = true;
|
found[0] = true;
|
||||||
// Woord zou moeten starten op (0,0)
|
// Woord zou moeten starten op (0,0)
|
||||||
|
|||||||
@@ -8,8 +8,6 @@ import org.junit.jupiter.api.Test;
|
|||||||
import puzzle.Export.Clue;
|
import puzzle.Export.Clue;
|
||||||
import puzzle.Export.Signa;
|
import puzzle.Export.Signa;
|
||||||
import puzzle.Export.Puzzle;
|
import puzzle.Export.Puzzle;
|
||||||
import puzzle.Masker.Clues;
|
|
||||||
import puzzle.SwedishGenerator.Grid;
|
|
||||||
import puzzle.SwedishGenerator.Rng;
|
import puzzle.SwedishGenerator.Rng;
|
||||||
import puzzle.SwedishGenerator.Slotinfo;
|
import puzzle.SwedishGenerator.Slotinfo;
|
||||||
|
|
||||||
@@ -50,7 +48,7 @@ public class PerformanceTest {
|
|||||||
var c = 0;
|
var c = 0;
|
||||||
for (var size : clueSizes) {
|
for (var size : clueSizes) {
|
||||||
var t0 = System.currentTimeMillis();
|
var t0 = System.currentTimeMillis();
|
||||||
val masker = new Masker(rng, new int[Masker.STACK_SIZE], Masker.Clues.createEmpty());
|
val masker = new Masker(rng, new int[Masker.STACK_SIZE], Clues.createEmpty());
|
||||||
// Increased population and generations for stress
|
// Increased population and generations for stress
|
||||||
arr[c++] = masker.generateMask(size, 200, 100, 50);
|
arr[c++] = masker.generateMask(size, 200, 100, 50);
|
||||||
var t1 = System.currentTimeMillis();
|
var t1 = System.currentTimeMillis();
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ import puzzle.DictJavaGeneratorMulti.DictEntryDTO.IntListDTO;
|
|||||||
import puzzle.Export.Signa;
|
import puzzle.Export.Signa;
|
||||||
import puzzle.Export.Puzzle;
|
import puzzle.Export.Puzzle;
|
||||||
import puzzle.Export.Lettrix;
|
import puzzle.Export.Lettrix;
|
||||||
import puzzle.Masker.Clues;
|
|
||||||
import puzzle.Masker.Slot;
|
import puzzle.Masker.Slot;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.*;
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
@@ -220,8 +219,8 @@ public class SwedishGeneratorTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testMaskFitnessBasic() {
|
void testMaskFitnessBasic() {
|
||||||
var gen = new Masker(new Rng(0), new int[Masker.STACK_SIZE], Masker.Clues.createEmpty());
|
var gen = new Masker(new Rng(0), new int[Masker.STACK_SIZE], Clues.createEmpty());
|
||||||
var grid = Masker.Clues.createEmpty();
|
var grid = Clues.createEmpty();
|
||||||
// Empty grid should have high penalty (no slots)
|
// Empty grid should have high penalty (no slots)
|
||||||
var f1 = gen.maskFitness(grid, 18);
|
var f1 = gen.maskFitness(grid, 18);
|
||||||
assertTrue(f1 >= 1_000_000_000L);
|
assertTrue(f1 >= 1_000_000_000L);
|
||||||
@@ -234,7 +233,7 @@ public class SwedishGeneratorTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testGeneticAlgorithmComponents() {
|
void testGeneticAlgorithmComponents() {
|
||||||
var gen = new Masker(new Rng(42), new int[Masker.STACK_SIZE], Masker.Clues.createEmpty());
|
var gen = new Masker(new Rng(42), new int[Masker.STACK_SIZE], Clues.createEmpty());
|
||||||
var c1 = new Signa(gen.randomMask(18));
|
var c1 = new Signa(gen.randomMask(18));
|
||||||
assertNotNull(c1);
|
assertNotNull(c1);
|
||||||
var g2 = new Signa(gen.mutate(c1.deepCopyGrid().c()));
|
var g2 = new Signa(gen.mutate(c1.deepCopyGrid().c()));
|
||||||
@@ -332,8 +331,8 @@ public class SwedishGeneratorTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testMaskFitnessDetailed() {
|
void testMaskFitnessDetailed() {
|
||||||
var gen = new Masker(new Rng(42), new int[Masker.STACK_SIZE], Masker.Clues.createEmpty());
|
var gen = new Masker(new Rng(42), new int[Masker.STACK_SIZE], Clues.createEmpty());
|
||||||
var grid = Masker.Clues.createEmpty();
|
var grid = Clues.createEmpty();
|
||||||
// Empty grid: huge penalty
|
// Empty grid: huge penalty
|
||||||
var fitEmpty = gen.maskFitness(grid, 18);
|
var fitEmpty = gen.maskFitness(grid, 18);
|
||||||
assertTrue(fitEmpty >= 1_000_000_000L);
|
assertTrue(fitEmpty >= 1_000_000_000L);
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package puzzle;
|
package puzzle;
|
||||||
|
|
||||||
|
import puzzle.Masker_Neighbors4x3;
|
||||||
import gen.Test123X_Neighbors4x3;
|
import gen.Test123X_Neighbors4x3;
|
||||||
import gen.Test123X_Neighbors9x8;
|
import gen.Test123X_Neighbors9x8;
|
||||||
import lombok.val;
|
import lombok.val;
|
||||||
@@ -32,7 +33,7 @@ public class TestDuplication {
|
|||||||
Assertions.assertEquals(4, mask.clueCount());
|
Assertions.assertEquals(4, 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(4, map.size());
|
Assertions.assertEquals(4, map.size());
|
||||||
var slots = mask.slots(DictData800.DICT800);
|
var slots = Masker_Neighbors4x3.slots(mask.c(), DictData800.DICT800);
|
||||||
// var filled = fillMask(rng, slotInfo, grid, false);
|
// var filled = fillMask(rng, slotInfo, grid, false);
|
||||||
// val res = new PuzzleResult(new Clued(mask), new Gridded(grid), slotInfo, filled).exportFormatFromFilled(0, new Rewards(0, 0, 0));
|
// val res = new PuzzleResult(new Clued(mask), new Gridded(grid), slotInfo, filled).exportFormatFromFilled(0, new Rewards(0, 0, 0));
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user