introduce bitloops
This commit is contained in:
@@ -5,6 +5,7 @@ import lombok.experimental.Accessors;
|
||||
import lombok.experimental.Delegate;
|
||||
import lombok.val;
|
||||
import puzzle.Export.Gridded.Replacar.Cell;
|
||||
import puzzle.Export.LetterVisit.LetterAt;
|
||||
import puzzle.SwedishGenerator.Clues;
|
||||
import puzzle.SwedishGenerator.DictEntry;
|
||||
import puzzle.SwedishGenerator.FillResult;
|
||||
@@ -13,7 +14,9 @@ import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.function.IntSupplier;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
import java.util.stream.Stream;
|
||||
import static puzzle.SwedishGenerator.R;
|
||||
import static puzzle.SwedishGenerator.Lemma;
|
||||
import static puzzle.SwedishGenerator.Slot;
|
||||
@@ -38,30 +41,46 @@ public record Export() {
|
||||
}
|
||||
}
|
||||
|
||||
static final String INIT = IntStream.range(0, R).mapToObj(l_ -> " ").collect(Collectors.joining("\n"));
|
||||
|
||||
public record Clued(@Delegate Clues mask) {
|
||||
|
||||
String gridToString() {
|
||||
var sb = new StringBuilder();
|
||||
for (var r = 0; r < R; r++) {
|
||||
if (r > 0) sb.append('\n');
|
||||
for (var c = 0; c < C; c++) {
|
||||
val idx = Grid.offset(r, c);
|
||||
if (mask.isClue(idx))
|
||||
sb.append((char) (mask.digitAt(idx) | 48));
|
||||
else {
|
||||
sb.append(' ');
|
||||
}
|
||||
}
|
||||
}
|
||||
var sb = new StringBuilder(INIT);
|
||||
forEachSlot((s, l, a) -> {
|
||||
val idx = Slot.clueIndex(s);
|
||||
val r = idx & 7;
|
||||
val c = idx >>> 3;
|
||||
val dir = Slot.dir(s);
|
||||
sb.setCharAt(r * (C + 1) + c, (char) (dir | 48));
|
||||
});
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
interface LetterVisit {
|
||||
|
||||
record LetterAt(int index, byte letter) {
|
||||
|
||||
static LetterAt from(int index, byte[] bytes) { return new LetterAt(index, bytes[index]); }
|
||||
}
|
||||
|
||||
void visit(int index, byte letter);
|
||||
default void visit(int index, byte[] letters) { visit(index, letters[index]); }
|
||||
}
|
||||
|
||||
record Gridded(@Delegate Grid grid) {
|
||||
public boolean lisLetterAt(int pos) {
|
||||
if ((pos & 64) == 0)
|
||||
return lisLetterAtLo(pos);
|
||||
return lisLetterAtHi(pos);
|
||||
|
||||
public Stream<LetterAt> stream(Clues clues) {
|
||||
val stream = Stream.<LetterAt>builder();
|
||||
for (var l = grid.lo & ~clues.lo; l != SwedishGenerator.X; l &= l - 1) stream.accept(LetterAt.from(Long.numberOfTrailingZeros(l), grid.g));
|
||||
for (var h = grid.hi & ~clues.hi; h != SwedishGenerator.X; h &= h - 1) stream.accept(LetterAt.from(64 | Long.numberOfTrailingZeros(h), grid.g));
|
||||
return stream.build();
|
||||
}
|
||||
public void forEachLetter(Clues clues, LetterVisit visitor) {
|
||||
for (var l = grid.lo & ~clues.lo; l != SwedishGenerator.X; l &= l - 1) visitor.visit(Long.numberOfTrailingZeros(l), grid.g);
|
||||
for (var h = grid.hi & ~clues.hi; h != SwedishGenerator.X; h &= h - 1) visitor.visit(64 | Long.numberOfTrailingZeros(h), grid.g);
|
||||
}
|
||||
public static IntStream walk(byte base, long lo, long hi) {
|
||||
if (Slot.increasing(base)) {
|
||||
@@ -116,19 +135,19 @@ public record Export() {
|
||||
return (char) (64 | b);
|
||||
}
|
||||
String gridToString(Clues clues) {
|
||||
var sb = new StringBuilder();
|
||||
for (var r = 0; r < R; r++) {
|
||||
if (r > 0) sb.append('\n');
|
||||
for (var c = 0; c < C; c++) {
|
||||
var offset = Grid.offset(r, c);
|
||||
if (clues.isClue(offset))
|
||||
sb.append((char) (48 | clues.digitAt(offset)));
|
||||
else if (lisLetterAt(offset))
|
||||
sb.append((char) (64 | grid.letter32At(offset)));
|
||||
else
|
||||
sb.append(' ');
|
||||
}
|
||||
}
|
||||
var sb = new StringBuilder(INIT);
|
||||
clues.forEachSlot((s, l, a) -> {
|
||||
val idx = Slot.clueIndex(s);
|
||||
val r = idx & 7;
|
||||
val c = idx >>> 3;
|
||||
val dir = Slot.dir(s);
|
||||
sb.setCharAt(r * (C + 1) + c, (char) (dir | 48));
|
||||
});
|
||||
forEachLetter(clues, (idx, letter) -> {
|
||||
val r = idx & 7;
|
||||
val c = idx >>> 3;
|
||||
sb.setCharAt(r * (C + 1) + c, (char) (letter | 64));
|
||||
});
|
||||
return sb.toString();
|
||||
}
|
||||
public String renderHuman(Clues clues) {
|
||||
@@ -141,6 +160,21 @@ public record Export() {
|
||||
char replace(Cell c);
|
||||
}
|
||||
public String[] exportGrid(Clues clues, Replacar clueChar, char emptyFallback) {
|
||||
var sb = new StringBuilder(INIT);
|
||||
clues.forEachSlot((s, l, a) -> {
|
||||
val idx = Slot.clueIndex(s);
|
||||
val r = idx & 7;
|
||||
val c = idx >>> 3;
|
||||
val dir = Slot.dir(s);
|
||||
sb.setCharAt(r * (C + 1) + c, clueChar.replace(new Cell(grid, clues, idx, (byte) (dir | 48))));
|
||||
});
|
||||
forEachLetter(clues, (idx, letter) -> {
|
||||
val r = idx & 7;
|
||||
val c = idx >>> 3;
|
||||
sb.setCharAt(r * (C + 1) + c, (char) (letter | 64));
|
||||
});
|
||||
return sb.toString().replaceAll(" ", "" + emptyFallback).split("\n");
|
||||
/*
|
||||
var out = new String[R];
|
||||
for (var r = 0; r < R; r++) {
|
||||
var sb = new StringBuilder(C);
|
||||
@@ -156,7 +190,7 @@ public record Export() {
|
||||
}
|
||||
out[r] = sb.toString();
|
||||
}
|
||||
return out;
|
||||
return out;*/
|
||||
}
|
||||
}
|
||||
|
||||
@@ -194,7 +228,7 @@ public record Export() {
|
||||
|
||||
public record ExportedPuzzle(String[] grid, WordOut[] words, int difficulty, Rewards rewards) { }
|
||||
|
||||
public record PuzzleResult(Clued mask, FillResult filled) {
|
||||
public record PuzzleResult(Clued clues, FillResult filled) {
|
||||
|
||||
Placed extractPlacedFromSlot(Slot s, long lemma) { return new Placed(lemma, s.key(), s.walk().toArray()); }
|
||||
public ExportedPuzzle exportFormatFromFilled(int difficulty, Rewards rewards) {
|
||||
@@ -202,7 +236,7 @@ public record Export() {
|
||||
var placed = new ArrayList<Placed>();
|
||||
var clueMap = filled().clueMap();
|
||||
val entries = new DictEntry[10];
|
||||
mask.forEachSlot((int key, long lo, long hi) -> {
|
||||
clues.forEachSlot((int key, long lo, long hi) -> {
|
||||
var word = clueMap[key];
|
||||
if (word != 0L) {
|
||||
placed.add(extractPlacedFromSlot(Slot.from(key, lo, hi, entries[Slot.length(lo, hi)]), word));
|
||||
@@ -213,7 +247,7 @@ public record Export() {
|
||||
|
||||
// If nothing placed: return full grid mapped to letters/# only
|
||||
if (placed.isEmpty()) {
|
||||
return new ExportedPuzzle(g.exportGrid(mask.mask, _ -> '#', '#'), new WordOut[0], difficulty, rewards);
|
||||
return new ExportedPuzzle(g.exportGrid(clues.mask, _ -> '#', '#'), new WordOut[0], difficulty, rewards);
|
||||
}
|
||||
|
||||
// 2) bounding box around all word cells + arrow cells, with 1-cell margin
|
||||
@@ -237,13 +271,17 @@ public record Export() {
|
||||
|
||||
// 3) map of only used letter cells (everything else becomes '#')
|
||||
var letterAt = new HashMap<Integer, Character>();
|
||||
for (var p : placed) {
|
||||
g.forEachLetter(clues.mask(), (idx, letter) -> {
|
||||
if (letter == 0) return;
|
||||
letterAt.put(idx, (char) (64 | letter));
|
||||
});
|
||||
/* for (var p : placed) {
|
||||
for (var c : p.cells) {
|
||||
if (mask.notClue(c) && g.lisLetterAt(c)) {
|
||||
if (clues.notClue(c) && g.lisLetterAt(c)) {
|
||||
letterAt.put(c, (char) (64 | g.letter32At(c)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
// 4) render gridv2 over cropped bounds (out-of-bounds become '#')
|
||||
var gridv2 = new String[Math.max(0, maxR - minR + 1)];
|
||||
|
||||
Reference in New Issue
Block a user