introduce bitloops

This commit is contained in:
mike
2026-01-17 21:43:17 +01:00
parent 938d2ac66b
commit 19812d81e5
5 changed files with 34 additions and 36 deletions

View File

@@ -83,6 +83,9 @@ public record Export() {
record LetterAt(int index, byte letter) {
public char human() {
return (char) (letter | 64);
}
static LetterAt from(int index, byte[] bytes) { return new LetterAt(index, bytes[index]); }
}
@@ -235,18 +238,14 @@ public record Export() {
return simpel;
}
public ExportedPuzzle exportFormatFromFilled(int difficulty, Rewards rewards) {
var placed = new ArrayList<Placed>();
for (var slot : slots) {
placed.add(new Placed(slot.assign().w, slot.key(), Gridded.walk((byte) slot.key(), slot.lo(), slot.hi()).toArray()));
}
// If nothing placed: return full grid mapped to letters/# only
if (placed.isEmpty()) {
if (slots.length == 0) {
return new ExportedPuzzle(grid.exportGrid(clues.c, _ -> '#', '#'), new WordOut[0], difficulty, rewards);
}
// 2) bounding box around all word cells + arrow cells, with 1-cell margin
var placed = Arrays.stream(slots).map(slot -> new Placed(slot.assign().w, slot.key(), Gridded.walk((byte) slot.key(), slot.lo(), slot.hi()).toArray())).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;
@@ -265,23 +264,18 @@ public record Export() {
}
// 3) map of only used letter cells (everything else becomes '#')
var letterAt = new HashMap<Integer, Character>();
grid.forEachLetter(clues.c(), (idx, letter) -> {
if (letter == 0) return;
letterAt.put(idx, (char) (64 | letter));
});
var map = grid.stream(clues.c()).collect(Collectors.toMap(LetterAt::index, LetterAt::human));
// 4) render gridv2 over cropped bounds (out-of-bounds become '#')
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(Grid.offset(r, c), '#'));
for (var c = minC; c <= maxC; c++) row.append(map.getOrDefault(Grid.offset(r, c), '#'));
gridv2[i] = row.toString();
}
// 5) words output with cropped coordinates
int MIN_R = minR, MIN_C = minC;
var wordsOut = placed.stream().map(p -> new WordOut(
var wordsOut = Arrays.stream(placed).map(p -> new WordOut(
p.lemma,
p.startRow() - MIN_R,
p.startCol() - MIN_C,

View File

@@ -402,20 +402,19 @@ public class Main {
}
static Clues generateNewClues(Rng rng, Opts opts) {
var masker = new Masker(rng, new int[STACK_SIZE], Masker.Clues.createEmpty());
var mask = masker.generateMask(opts.clueSize, opts.pop, opts.gens, opts.offspring);
return mask;
return masker.generateMask(opts.clueSize, opts.pop, opts.gens, opts.offspring);
}
static PuzzleResult _attempt(Rng rng, Dict dict, Opts opts) {
val multiThreaded = Thread.currentThread().getName().contains("pool");
long t0 = System.currentTimeMillis();
TOTAL_ATTEMPTS.incrementAndGet();
val mask = generateNewClues(rng, opts);
//val mask = generateClues();
if (mask == null) return null;
val multiThreaded = Thread.currentThread().getName().contains("pool");
var slots = Masker.extractSlots(mask, dict.index());
val slotInfo = Masker.scoreSlots(slots);
val slotInfo = Masker.slots(mask, dict.index());
var grid = mask.toGrid();
var filled = fillMask(rng, slotInfo, grid, multiThreaded);
var filled = fillMask(rng, slotInfo, grid, (!Main.VERBOSE || multiThreaded));
if (!multiThreaded) {
System.out.print("\r" + Strings.padRight("", 120) + "\r");

View File

@@ -75,6 +75,10 @@ public record Masker(Rng rng, int[] stack, Clues cache) {
grid.forEachSlot((key, lo, hi) -> slots[N[0]++] = Slot.from(key, lo, hi, index[Slot.length(lo, hi)]));
return slots;
}
public static Slotinfo[] slots(Clues mask, DictEntry[] index) {
var slots = Masker.extractSlots(mask, index);
return Masker.scoreSlots(slots);
}
public static Slotinfo[] scoreSlots(Slot[] slots) {
val count = new byte[SwedishGenerator.SIZE];
Slotinfo[] slotInfo = new Slotinfo[slots.length];

View File

@@ -134,6 +134,10 @@ public record SwedishGenerator() {
public final byte[] g;
public long lo, hi;
public static int offset(int r, int c) { return r | (c << 3); }
public Grid copy() {
return new Grid(g.clone(), lo, hi);
}
}
public static record DictEntry(long[] words, long[][] posBitsets, int length, int numlong) { }
@@ -258,8 +262,7 @@ public record SwedishGenerator() {
public static FillResult fillMask(final Rng rng, final Slotinfo[] slots,
final Grid grid,
final boolean multiThreaded) {
val NO_LOG = (!Main.VERBOSE || multiThreaded);
final boolean NO_LOG) {
val used = new long[2048];
val bitset = new long[2500];
val g = grid.g;
@@ -388,11 +391,10 @@ public record SwedishGenerator() {
var tries = Math.min(MAX_TRIES_PER_SLOT, L);
for (var t = 0; t < tries; t++) {
var r = rng.nextFloat();
//int idxInArray = rng.biasedIndexPow3(L - 1);
var arrIndex = (int) (r * r * r * (L - 1));
var shardIdx = idxs[arrIndex];
var w = entry.words[shardIdx];
//var r = rng.nextFloat();
//var idxInArray = (int) (r * r * r * (L - 1));
int idxInArray = rng.biasedIndexPow3(L - 1);
var w = entry.words[idxs[idxInArray/*(int) (r * r * r * (L - 1))*/]];
var lemIdx = Lemma.unpackIndex(w);
if (Bit1029.get(used, lemIdx)) continue;
low = glo;
@@ -419,9 +421,8 @@ public record SwedishGenerator() {
var tries = Math.min(MAX_TRIES_PER_SLOT, N);
for (var t = 0; t < tries; t++) {
double r = rng.nextFloat();
var shardIdx = (int) (r * r * r * (N - 1));
var w = entry.words[shardIdx];
// double r = rng.nextFloat();
var w = entry.words[rng.biasedIndexPow3(N - 1)/*(int) (r * r * r * (N - 1))*/];
var lemIdx = Lemma.unpackIndex(w);
if (Bit1029.get(used, lemIdx)) continue;
low = glo;

View File

@@ -212,7 +212,7 @@ public class MainTest {
var filled = fillMask(rng, slotInfo, grid, false);
Assertions.assertTrue(filled.ok(), "Puzzle generation failed (not ok)");
Assertions.assertEquals(17, Slotinfo.wordCount(0, slotInfo), "Number of assigned words changed");
Assertions.assertEquals("POENIGE", Lemma.asWord(slotInfo[0].assign().w));
Assertions.assertEquals("VREEMDS", Lemma.asWord(slotInfo[0].assign().w));
Assertions.assertEquals(-1L, grid.lo);
Assertions.assertEquals(255L, grid.hi);
var g = new Gridded(grid);