redo
This commit is contained in:
@@ -1,10 +1,11 @@
|
||||
package puzzle;
|
||||
|
||||
import module java.base;
|
||||
import anno.Shaped;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.experimental.Delegate;
|
||||
import lombok.val;
|
||||
import precomp.Const9x8.Cell;
|
||||
import precomp.Const9x8;
|
||||
import puzzle.Export.Puzzle.Replacar.Rell;
|
||||
import puzzle.Meta.ShardLem;
|
||||
import puzzle.SwedishGenerator.Dict;
|
||||
@@ -12,14 +13,16 @@ import puzzle.SwedishGenerator.FillResult;
|
||||
import puzzle.SwedishGenerator.Grid;
|
||||
import puzzle.SwedishGenerator.Slotinfo;
|
||||
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.INIT_GRID_OUTPUT;
|
||||
import static precomp.Const9x8.INIT_GRID_OUTPUT_ARR;
|
||||
import static precomp.Const9x8.CLUE_RIGHT_TOP5;
|
||||
import static precomp.Const9x8.CLUE_UP2;
|
||||
import static puzzle.Export.Clue.DOWN0;
|
||||
import static puzzle.Export.Clue.RIGHT1;
|
||||
import static puzzle.Clues.createEmpty;
|
||||
import static puzzle.Masker.Slot;
|
||||
import static puzzle.Masker.C;
|
||||
import static puzzle.SwedishGenerator.Lemma;
|
||||
import static puzzle.SwedishGenerator.X;
|
||||
|
||||
@@ -34,26 +37,30 @@ import static puzzle.SwedishGenerator.X;
|
||||
*/
|
||||
public record Export() {
|
||||
|
||||
public static final ThreadLocal<byte[]> BYTES = ThreadLocal.withInitial(() -> new byte[8]);
|
||||
static final byte CLUE_UP = 2;
|
||||
static final byte CLUE_LEFT = 3;
|
||||
static final byte CLUE_LEFT_TOP = 4;
|
||||
static final byte CLUE_RIGHT_TOP = 5;
|
||||
public static final ThreadLocal<byte[]> BYTES = ThreadLocal.withInitial(() -> new byte[8]);
|
||||
static final byte CLUE_UP = 2;
|
||||
static final byte CLUE_LEFT = 3;
|
||||
static final byte CLUE_LEFT_TOP = 4;
|
||||
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 char LETTER(int in) { return (char) (in | 64); }
|
||||
static char CLUE_CHAR(int s) { return (char) (s | 48); }
|
||||
static int INDEX_ROW(int idx) { return idx & 7; }
|
||||
static int INDEX_COL(int idx) { return idx >>> 3; }
|
||||
static int INDEX_ROW(int idx) { return idx % R; }
|
||||
static int INDEX_COL(int idx) { return idx / R; }
|
||||
static int INDEX(int r, int cols, int c) { return r * cols + c; }
|
||||
@AllArgsConstructor
|
||||
enum Clue {
|
||||
DOWN0(CLUE_DOWN0, 'B', 'b'),
|
||||
RIGHT1(CLUE_RIGHT1, 'A', 'a'),
|
||||
UP2(CLUE_UP, 'C', 'c'),
|
||||
LEFT3(CLUE_LEFT, 'D', 'd'),
|
||||
LEFT_TOP4(CLUE_LEFT_TOP, 'E', 'e'),
|
||||
RIGHT_TOP5(CLUE_RIGHT_TOP, 'F', 'f'),
|
||||
NONE(CLUE_LEFT, '?', '?');
|
||||
UP2(CLUE_UP2, 'C', 'c'),
|
||||
LEFT3(CLUE_LEFT3, 'D', 'd'),
|
||||
LEFT_TOP4(CLUE_LEFT_TOP4, 'E', 'e'),
|
||||
RIGHT_TOP5(CLUE_RIGHT_TOP5, 'F', 'f'),
|
||||
NONE(CLUE_NONE, '?', '?');
|
||||
final byte dir;
|
||||
final char slotChar, clueChar;
|
||||
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));
|
||||
return stream.build();
|
||||
}
|
||||
String gridToString() {
|
||||
String gridToString(Slotinfo[] slots) {
|
||||
var sb = INIT_GRID_OUTPUT_ARR.clone();
|
||||
Masker.forEachSlot(cl, (s, _, _) -> {
|
||||
val idx = Slot.clueIndex(s);
|
||||
for (var slot : slots) {
|
||||
val idx = Slot.clueIndex(slot.key());
|
||||
val r = idx & 7;
|
||||
val c = idx >>> 3;
|
||||
val dir = Slot.dir(s);
|
||||
val dir = Slot.dir(slot.key());
|
||||
sb[r * (C + 1) + c] = (byte) (dir | 48);
|
||||
});
|
||||
}
|
||||
stream().forEach((l) -> sb[l.index(C + 1)] = (byte) l.human());
|
||||
return new String(sb);
|
||||
}
|
||||
@@ -137,9 +144,9 @@ public record Export() {
|
||||
stream().forEach((l) -> sb[l.index(C + 1)] = (byte) l.human());
|
||||
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)) {
|
||||
return IntStream.concat(
|
||||
return IntStream.concat(IntStream.of(Slot.clueIndex(base)), IntStream.concat(
|
||||
IntStream.generate(new IntSupplier() {
|
||||
|
||||
long temp = lo;
|
||||
@@ -159,9 +166,9 @@ public record Export() {
|
||||
temp &= temp - 1;
|
||||
return res;
|
||||
}
|
||||
}).limit(Long.bitCount(hi)));
|
||||
}).limit(Long.bitCount(hi))));
|
||||
} else {
|
||||
return IntStream.concat(
|
||||
return IntStream.concat(IntStream.of(Slot.clueIndex(base)), IntStream.concat(
|
||||
IntStream.generate(new IntSupplier() {
|
||||
|
||||
long temp = hi;
|
||||
@@ -181,11 +188,10 @@ public record Export() {
|
||||
temp &= ~(1L << msb);
|
||||
return msb;
|
||||
}
|
||||
}).limit(Long.bitCount(lo)));
|
||||
}).limit(Long.bitCount(lo))));
|
||||
}
|
||||
}
|
||||
|
||||
public String renderHuman() { return String.join("\n", exportGrid(_ -> ' ', '#')); }
|
||||
@FunctionalInterface
|
||||
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';
|
||||
static final char VERTICAL = 'v';
|
||||
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 arrowRow() { return rcis[Slot.clueIndex(slotKey)].r(); }
|
||||
public int startRow() { return rcis[cells[0]].r(); }
|
||||
public int startCol() { return rcis[cells[0]].c(); }
|
||||
public int arrowCol() { return cells[0].c()/*rcis[Slot.clueIndex(slotKey)].c()*/; }
|
||||
public int arrowRow() { return cells[0].r()/*rcis[Slot.clueIndex(slotKey)].r()*/; }
|
||||
public int startRow() { return cells[1].r(); }
|
||||
public int startCol() { return cells[1].c(); }
|
||||
public boolean isReversed() { return !Slotinfo.increasing(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 String gridRenderHuman() {
|
||||
return String.join("\n", grid.exportGrid(_ -> ' ', '#'));
|
||||
}
|
||||
public String gridGridToString() {
|
||||
return grid.gridToString(slots);
|
||||
}
|
||||
public ExportedPuzzle exportFormatFromFilled(Rewards rewards, rci[] rcis, int bits) {
|
||||
// If nothing placed: return full grid mapped to letters/# only
|
||||
if (slots.length == 0) {
|
||||
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(
|
||||
Placed[]::new);
|
||||
var placed = Arrays.stream(slots)
|
||||
.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
|
||||
int minR = Integer.MAX_VALUE, minC = Integer.MAX_VALUE;
|
||||
int maxR = Integer.MIN_VALUE, maxC = Integer.MIN_VALUE;
|
||||
|
||||
for (var rc : placed) {
|
||||
for (var c : rc.cells) {
|
||||
val it = rcis[c];
|
||||
for (var it : rc.cells) {
|
||||
minR = Math.min(minR, it.r());
|
||||
minC = Math.min(minC, it.c());
|
||||
maxR = Math.max(maxR, it.r());
|
||||
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 '#')
|
||||
@@ -299,6 +307,8 @@ public record Export() {
|
||||
var total = 0.0001d + Arrays.stream(wordsOut).mapToDouble(WordOut::complex).sum();
|
||||
return new ExportedPuzzle(gridv2, wordsOut, (int) (total / wordsOut.length), rewards);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
record Lettrix(int index, byte letter) {
|
||||
|
||||
@@ -96,10 +96,10 @@ public class Main {
|
||||
System.out.print(indentLines(res.clues().gridToString()));
|
||||
|
||||
section("Grid (raw)");
|
||||
System.out.print(indentLines(res.grid().gridToString()));
|
||||
System.out.print(indentLines(res.gridGridToString()));
|
||||
|
||||
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);
|
||||
|
||||
|
||||
@@ -11,35 +11,37 @@ import static puzzle.SwedishGenerator.*;
|
||||
@GenerateShapedCopies(
|
||||
packageName = "puzzle",
|
||||
className = "Masker",
|
||||
shapes = { "precomp.Neighbors9x8", "precomp.Neighbors4x3" , "precomp.Neighbors3x4" }
|
||||
shapes = { "precomp.Neighbors9x8", "precomp.Neighbors4x3", "precomp.Neighbors3x4" }
|
||||
)
|
||||
public final class Masker {
|
||||
|
||||
@Shaped public static final int SIZE = Neighbors9x8.SIZE;
|
||||
@Shaped public static final rci[] IT = Neighbors9x8.IT;
|
||||
@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 MASK_LO = Neighbors9x8.MASK_LO;
|
||||
@Shaped public static final long MASK_HI = Neighbors9x8.MASK_HI;//(1L << (SIZE - 64)) - 1;
|
||||
@Shaped public static final int MIN_LEN = Neighbors9x8.MIN_LEN;//Config.MIN_LEN;
|
||||
@Shaped public static final int C = Neighbors9x8.C;
|
||||
@Shaped public static final int R = Neighbors9x8.R;
|
||||
@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_HI = Neighbors9x8.NBR_HI;
|
||||
public static final int[][] MUTATE_RI = new int[SIZE][625];
|
||||
private static final boolean VERBOSE = false;
|
||||
private final int[] activeCIdx = new int[SIZE];
|
||||
private final long[] activeSLo = new long[SIZE];
|
||||
private final long[] activeSHi = new long[SIZE];
|
||||
private final long[] adjLo = new long[SIZE];
|
||||
private final long[] adjHi = new long[SIZE];
|
||||
private final int[] rCount = new int[R];
|
||||
private final int[] cCount = new int[C];
|
||||
@Shaped public static final int SIZE = Neighbors9x8.SIZE;
|
||||
@Shaped public static final rci[] IT = Neighbors9x8.IT;
|
||||
@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 MASK_LO = Neighbors9x8.MASK_LO;
|
||||
@Shaped public static final long RANGE_0_SIZE = Neighbors9x8.RANGE_0_SIZE;
|
||||
@Shaped public static final long RANGE_0_624 = Neighbors9x8.RANGE_0_624;
|
||||
@Shaped public static final long MASK_HI = Neighbors9x8.MASK_HI;//(1L << (SIZE - 64)) - 1;
|
||||
@Shaped public static final int MIN_LEN = Neighbors9x8.MIN_LEN;//Config.MIN_LEN;
|
||||
@Shaped public static final int C = Neighbors9x8.C;
|
||||
@Shaped public static final int R = Neighbors9x8.R;
|
||||
@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_HI = Neighbors9x8.NBR_HI;
|
||||
public static final int[][] MUTATE_RI = new int[SIZE][625];
|
||||
private static final boolean VERBOSE = false;
|
||||
private final int[] activeCIdx = new int[SIZE];
|
||||
private final long[] activeSLo = new long[SIZE];
|
||||
private final long[] activeSHi = new long[SIZE];
|
||||
private final long[] adjLo = new long[SIZE];
|
||||
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 int[] stack;
|
||||
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) {
|
||||
this.rng = rng;
|
||||
this.stack = stack;
|
||||
@@ -75,7 +77,7 @@ public final class Masker {
|
||||
|
||||
if (num == 0) return -1;
|
||||
|
||||
var start = rng.randint0_SIZE() % num;
|
||||
var start = rng.randint0_SIZE(RANGE_0_SIZE) % num;
|
||||
var n = 0;
|
||||
for (var i = 0; i < num; i++) {
|
||||
var idx = activeCIdx[(start + i) % num];
|
||||
@@ -470,7 +472,7 @@ public final class Masker {
|
||||
var g = Clues.createEmpty();
|
||||
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 (g.isClueLo(ri)) continue;
|
||||
var d_idx = rng.randomClueDir();
|
||||
@@ -496,9 +498,9 @@ public final class Masker {
|
||||
}
|
||||
|
||||
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++) {
|
||||
ri = bytes[rng.randint0_624()];
|
||||
ri = bytes[rng.randint0_624(RANGE_0_624)];
|
||||
if (c.notClue(ri)) { // ADD
|
||||
var d = rng.randomClueDir();
|
||||
var key = Slot.packSlotKey(ri, d);
|
||||
@@ -543,7 +545,7 @@ public final class Masker {
|
||||
}
|
||||
}
|
||||
} // MOVE
|
||||
var nri = bytes[rng.randint0_624()];
|
||||
var nri = bytes[rng.randint0_624(RANGE_0_624)];
|
||||
if (c.notClue(nri)) {
|
||||
var d = c.getDir(ri);
|
||||
var nkey = Slot.packSlotKey(nri, d);
|
||||
|
||||
@@ -3,11 +3,9 @@ package puzzle;
|
||||
import anno.ConstGen;
|
||||
import anno.GenerateNeighbor;
|
||||
import anno.GenerateNeighbors;
|
||||
import anno.Shaped;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.val;
|
||||
import precomp.Neighbors9x8;
|
||||
import static java.lang.Long.bitCount;
|
||||
import static java.lang.Long.numberOfLeadingZeros;
|
||||
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 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 {
|
||||
|
||||
@@ -80,8 +75,8 @@ public record SwedishGenerator() {
|
||||
public byte randomClueDir() { return rand(BYTE); }
|
||||
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 int randint0_SIZE() { return (int) (((nextU32() & 0xFFFFFFFFL) % RANGE_0_SIZE)); }
|
||||
public int randint0_624() { return (int) (((nextU32() & 0xFFFFFFFFL) % RANGE_0_624)); }
|
||||
public int randint0_SIZE(long range0size) { return (int) (((nextU32() & 0xFFFFFFFFL) % range0size)); }
|
||||
public int randint0_624(long range0624) { return (int) (((nextU32() & 0xFFFFFFFFL) % range0624)); }
|
||||
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); }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user