introduce bitloops
This commit is contained in:
@@ -3,6 +3,7 @@ package puzzle;
|
||||
import lombok.Getter;
|
||||
import lombok.experimental.Accessors;
|
||||
import lombok.experimental.Delegate;
|
||||
import puzzle.Export.Gridded.Replacar.Cell;
|
||||
import puzzle.SwedishGenerator.Dict;
|
||||
import puzzle.SwedishGenerator.FillResult;
|
||||
import puzzle.SwedishGenerator.Grid;
|
||||
@@ -98,17 +99,26 @@ public record Export() {
|
||||
return sb.toString();
|
||||
}
|
||||
public String renderHuman() {
|
||||
return String.join("\n", exportGrid(' ', '#'));
|
||||
return String.join("\n", exportGrid(_ -> ' ', '#'));
|
||||
|
||||
}
|
||||
public String[] exportGrid(char clueChar, char emptyFallback) {
|
||||
public boolean notClue(int c) { return grid.notClue(c); }
|
||||
@FunctionalInterface
|
||||
interface Replacar {
|
||||
|
||||
record Cell(Grid grid, int index, byte data) { }
|
||||
char replace(Cell c);
|
||||
}
|
||||
public String[] exportGrid(Replacar clueChar, char emptyFallback) {
|
||||
var out = new String[R];
|
||||
for (var r = 0; r < R; r++) {
|
||||
var sb = new StringBuilder(C);
|
||||
for (var c = 0; c < C; c++) {
|
||||
if (grid.isClue(Grid.offset(r, c))) {
|
||||
sb.append(clueChar);
|
||||
var offset = Grid.offset(r, c);
|
||||
if (grid.isClue(offset)) {
|
||||
sb.append(clueChar.replace(new Cell(grid, offset, grid.byteAt(offset))));
|
||||
} else {
|
||||
sb.append(NOT_CLUE_NOT_LETTER_TO(grid.byteAt(Grid.offset(r, c)), emptyFallback));
|
||||
sb.append(NOT_CLUE_NOT_LETTER_TO(grid.byteAt(offset), emptyFallback));
|
||||
}
|
||||
}
|
||||
out[r] = sb.toString();
|
||||
@@ -149,10 +159,15 @@ public record Export() {
|
||||
public void clear() { Arrays.fill(bits, 0L); }
|
||||
}
|
||||
|
||||
record Placed(long lemma, int startRow, int startCol, char direction, int arrowRow, int arrowCol, int[] cells, boolean isReversed) {
|
||||
record Placed(long lemma, char direction, int slotKey, int[] cells) {
|
||||
|
||||
public static final char HORIZONTAL = 'h';
|
||||
static final char VERTICAL = 'v';
|
||||
public int arrowCol() { return Grid.c(Slot.clueIndex(slotKey)); }
|
||||
public int arrowRow() { return Grid.r(Slot.clueIndex(slotKey)); }
|
||||
public int startRow() { return Grid.r(cells[0]); }
|
||||
public int startCol() { return Grid.c(cells[0]); }
|
||||
public boolean isReversed() { return !Slot.increasing(slotKey); }
|
||||
}
|
||||
|
||||
public record Rewards(int coins, int stars, int hints) { }
|
||||
@@ -168,36 +183,19 @@ public record Export() {
|
||||
|
||||
public record PuzzleResult(SwedishGenerator swe, Dict dict, Gridded mask, FillResult filled) {
|
||||
|
||||
boolean inBounds(int r, int c) { return r >= 0 && r < SwedishGenerator.R && c >= 0 && c < SwedishGenerator.C; }
|
||||
boolean inBounds(int idx) { return idx >= 0 && idx < SwedishGenerator.SIZE; }
|
||||
Placed extractPlacedFromSlot(Slot s, long lemma) {
|
||||
var d = s.dir();
|
||||
|
||||
var cells = s.walk().toArray();
|
||||
|
||||
char direction;
|
||||
var startRow = Grid.r(cells[0]);
|
||||
var startCol = Grid.c(cells[0]);
|
||||
if (d == 2) { // right -> horizontal
|
||||
direction = Placed.HORIZONTAL;
|
||||
} else if (d == 3 || d == 5) { // down or down-bent -> vertical
|
||||
direction = Placed.VERTICAL;
|
||||
} else if (d == 4) { // left -> horizontal (REVERSED)
|
||||
direction = Placed.HORIZONTAL;
|
||||
} else if (d == 1) { // up -> vertical (REVERSED)
|
||||
direction = Placed.VERTICAL;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
char[] DIRECTION = { '\0', Placed.VERTICAL, Placed.HORIZONTAL, Placed.VERTICAL, Placed.HORIZONTAL, Placed.VERTICAL };
|
||||
|
||||
return new Placed(
|
||||
lemma,
|
||||
startRow,
|
||||
startCol,
|
||||
direction,
|
||||
s.clueR(),
|
||||
s.clueC(),
|
||||
cells,
|
||||
!s.increasing()
|
||||
DIRECTION[d],
|
||||
s.key(),
|
||||
cells
|
||||
);
|
||||
}
|
||||
public ExportedPuzzle exportFormatFromFilled(int difficulty, Rewards rewards) {
|
||||
@@ -207,14 +205,15 @@ public record Export() {
|
||||
g.grid().forEachSlot((int key, long lo, long hi) -> {
|
||||
var word = clueMap.get(key);
|
||||
if (word != null) {
|
||||
var p = extractPlacedFromSlot(Slot.from(key, lo, hi), word);
|
||||
if (p != null) placed.add(p);
|
||||
placed.add(extractPlacedFromSlot(Slot.from(key, lo, hi), word));
|
||||
} else {
|
||||
System.err.println("Could not find clue for slot: " + key);
|
||||
}
|
||||
});
|
||||
|
||||
// If nothing placed: return full grid mapped to letters/# only
|
||||
if (placed.isEmpty()) {
|
||||
return new ExportedPuzzle(g.exportGrid('#', '#'), new WordOut[0], difficulty, rewards);
|
||||
return new ExportedPuzzle(g.exportGrid(_ -> '#', '#'), new WordOut[0], difficulty, rewards);
|
||||
}
|
||||
|
||||
// 2) bounding box around all word cells + arrow cells, with 1-cell margin
|
||||
@@ -229,20 +228,18 @@ public record Export() {
|
||||
maxR = Math.max(maxR, Grid.r(c));
|
||||
maxC = Math.max(maxC, Grid.c(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);
|
||||
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 '#')
|
||||
var letterAt = new HashMap<Long, Character>();
|
||||
var letterAt = new HashMap<Integer, Character>();
|
||||
for (var p : placed) {
|
||||
for (var c : p.cells) {
|
||||
int rr = Grid.r(c), cc = Grid.c(c);
|
||||
int idx = Grid.offset(rr, cc);
|
||||
if (inBounds(rr, cc) && g.isLetterSet(idx)) {
|
||||
letterAt.put(Bit.pack(rr, cc), (char) g.byteAt(idx));
|
||||
if (inBounds(c) && g.notClue(c)) {
|
||||
letterAt.put(c, (char) g.byteAt(c));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -251,7 +248,7 @@ public record Export() {
|
||||
var gridv2 = new String[Math.max(0, maxR - minR + 1)];
|
||||
for (int r = minR, i = 0; r <= maxR; r++, i++) {
|
||||
var row = new StringBuilder(Math.max(0, maxC - minC + 1));
|
||||
for (var c = minC; c <= maxC; c++) row.append(letterAt.getOrDefault(Bit.pack(r, c), '#'));
|
||||
for (var c = minC; c <= maxC; c++) row.append(letterAt.getOrDefault(Grid.offset(r, c), '#'));
|
||||
gridv2[i] = row.toString();
|
||||
}
|
||||
|
||||
@@ -259,12 +256,12 @@ public record Export() {
|
||||
int MIN_R = minR, MIN_C = minC;
|
||||
var wordsOut = placed.stream().map(p -> new WordOut(
|
||||
p.lemma,
|
||||
p.startRow - MIN_R,
|
||||
p.startCol - MIN_C,
|
||||
p.startRow() - MIN_R,
|
||||
p.startCol() - MIN_C,
|
||||
p.direction,
|
||||
p.arrowRow - MIN_R,
|
||||
p.arrowCol - MIN_C,
|
||||
p.isReversed
|
||||
p.arrowRow() - MIN_R,
|
||||
p.arrowCol() - MIN_C,
|
||||
p.isReversed()
|
||||
)).toArray(WordOut[]::new);
|
||||
return new ExportedPuzzle(gridv2, wordsOut, difficulty, rewards);
|
||||
}
|
||||
|
||||
@@ -119,7 +119,7 @@ public record SwedishGenerator(Rng rng) {
|
||||
final int[] stack = new int[SIZE];
|
||||
final Bit seen = new Bit();
|
||||
long pattern;
|
||||
final long[] undo = new long[4096];
|
||||
final long[] undo = new long[128];
|
||||
final long[] bitset = new long[2500];
|
||||
|
||||
void setPattern(long p) { this.pattern = p; }
|
||||
@@ -207,9 +207,6 @@ public record SwedishGenerator(Rng rng) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static boolean isLetter(byte b) { return (b & B64) != B0; }
|
||||
public boolean isLetterSet(int idx) { return isLetter(g[idx]); }
|
||||
|
||||
public double similarity(Grid b) {
|
||||
var same = 0;
|
||||
for (int i = 0; i < SIZE; i++) if (g[i] == b.g[i]) same++;
|
||||
@@ -318,7 +315,8 @@ public record SwedishGenerator(Rng rng) {
|
||||
|
||||
public int len() { return Long.bitCount(lo) + Long.bitCount(hi); }
|
||||
public int clueR() { return Grid.r((key >>> BIT_FOR_DIR)); }
|
||||
public int clueIndex() { return key >>> BIT_FOR_DIR; }
|
||||
public int clueIndex() { return clueIndex(key); }
|
||||
public static int clueIndex(int key) { return key >>> BIT_FOR_DIR; }
|
||||
public int clueC() { return Grid.c((key >>> BIT_FOR_DIR)); }
|
||||
public int dir() { return key & 7; }
|
||||
public boolean horiz() { return horiz(key); }
|
||||
|
||||
Reference in New Issue
Block a user