introduce bitloops
This commit is contained in:
@@ -6,7 +6,6 @@ import lombok.experimental.Delegate;
|
||||
import lombok.val;
|
||||
import puzzle.Export.Gridded.Replacar.Cell;
|
||||
import puzzle.SwedishGenerator.Clues;
|
||||
import puzzle.SwedishGenerator.Dict;
|
||||
import puzzle.SwedishGenerator.FillResult;
|
||||
import puzzle.SwedishGenerator.Grid;
|
||||
import java.util.ArrayList;
|
||||
@@ -47,7 +46,7 @@ public record Export() {
|
||||
for (var c = 0; c < C; c++) {
|
||||
val idx = Grid.offset(r, c);
|
||||
if (mask.isClue(idx))
|
||||
sb.append((char) mask.digitAt(idx));
|
||||
sb.append((char) (mask.digitAt(idx) | 48));
|
||||
else {
|
||||
sb.append(' ');
|
||||
}
|
||||
@@ -182,7 +181,7 @@ public record Export() {
|
||||
|
||||
public record ExportedPuzzle(String[] grid, WordOut[] words, int difficulty, Rewards rewards) { }
|
||||
|
||||
public record PuzzleResult(SwedishGenerator swe, Dict dict, Clued mask, FillResult filled) {
|
||||
public record PuzzleResult(Clued mask, FillResult filled) {
|
||||
|
||||
boolean inBounds(int idx) { return idx >= 0 && idx < SwedishGenerator.SIZE; }
|
||||
Placed extractPlacedFromSlot(Slot s, long lemma) { return new Placed(lemma, s.key(), s.walk().toArray()); }
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
package puzzle;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.val;
|
||||
import lombok.NoArgsConstructor;
|
||||
import puzzle.SwedishGenerator.Rng;
|
||||
|
||||
import java.io.IOException;
|
||||
@@ -38,17 +39,18 @@ public class Main {
|
||||
static final AtomicLong TOTAL_SIMPLICITY = new AtomicLong(0); // Scaled by 100 for precision
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public static class Opts {
|
||||
|
||||
public int seed = (int) (System.nanoTime() ^ System.currentTimeMillis());
|
||||
public int pop = 18;
|
||||
public int seed = (int) (System.nanoTime() ^ System.currentTimeMillis());
|
||||
public int pop = 18;
|
||||
public int gens = 1200;
|
||||
public String wordsPath = "nl_score_hints_v3.csv";
|
||||
public double minSimplicity = 0; // 0 means no limit
|
||||
public int threads = Math.max(1, Runtime.getRuntime().availableProcessors());
|
||||
public int tries = threads;
|
||||
public boolean reindex = false;
|
||||
public int fillTimeout = 20_000;
|
||||
public boolean verbose = false;
|
||||
|
||||
}
|
||||
@@ -356,9 +358,9 @@ public class Main {
|
||||
}
|
||||
static PuzzleResult _attempt(Rng rng, Dict dict, Opts opts) {
|
||||
TOTAL_ATTEMPTS.incrementAndGet();
|
||||
val stack = new int[STACK_SIZE];
|
||||
var swe = new SwedishGenerator(rng, stack, Clues.createEmpty());
|
||||
var swe = new SwedishGenerator(rng, new int[STACK_SIZE], Clues.createEmpty());
|
||||
var mask = swe.generateMask(opts.pop, opts.gens, Math.max(opts.pop, (int) Math.floor(opts.pop * 1.5)));
|
||||
|
||||
var filled = fillMask(rng, extractSlots(mask), mask.toGrid(), dict.index());
|
||||
|
||||
TOTAL_NODES.addAndGet(filled.stats().nodes);
|
||||
@@ -380,7 +382,7 @@ public class Main {
|
||||
);
|
||||
|
||||
if (filled.ok() && (opts.minSimplicity <= 0 || filled.stats().simplicity >= opts.minSimplicity)) {
|
||||
return new PuzzleResult(swe, dict, new Clued(mask), filled);
|
||||
return new PuzzleResult(new Clued(mask), filled);
|
||||
}
|
||||
|
||||
if (opts.verbose && filled.ok()) {
|
||||
|
||||
@@ -148,14 +148,6 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
||||
}
|
||||
}
|
||||
|
||||
static final record Context(long[] bitset) {
|
||||
|
||||
public Context() { this(new long[2500]); }
|
||||
private static final ThreadLocal<Context> CTX = ThreadLocal.withInitial(Context::new);
|
||||
|
||||
public static Context get() { return CTX.get(); }
|
||||
}
|
||||
|
||||
static final class Rng {
|
||||
|
||||
@Getter private int x;
|
||||
@@ -315,8 +307,6 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
||||
|
||||
static record DictEntry(long[] words, long[][] posBitsets, int length, int numlong) { }
|
||||
|
||||
static int LEMMA_COUNTER = 0;
|
||||
|
||||
public static interface Lemma {
|
||||
|
||||
static final long LETTER_MASK = (1L << 40) - 1; // low 40 bits
|
||||
@@ -329,12 +319,12 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
||||
for (var i = 0; i < b.length; i++) w |= ((long) b[i] & 63) << (i * 5);
|
||||
return w;
|
||||
}
|
||||
static public long from(String word) { return pack(LEMMA_COUNTER++, word.getBytes(US_ASCII)); }
|
||||
static byte byteAt(long word, int idx) { return (byte) ((word >>> (idx * 5)) & 0b11111 | B64); }// word[]; }
|
||||
static int intAt(long word, int idx) { return (int) (((word >>> (idx * 5))) & 0b11111); }// word[]; }
|
||||
static String[] clue(long w) { return CsvIndexService.clues(unpackIndex(w)); }
|
||||
static int simpel(long w) { return CsvIndexService.simpel(unpackIndex(w)); }
|
||||
static int length(long word) { return ((63 - Long.numberOfLeadingZeros(word & LETTER_MASK)) / 5) + 1; }
|
||||
static public long from(int index, String word) { return pack(index, word.getBytes(US_ASCII)); }
|
||||
static byte byteAt(long word, int idx) { return (byte) ((word >>> (idx * 5)) & 0b11111 | B64); }// word[]; }
|
||||
static int intAt(long word, int idx) { return (int) (((word >>> (idx * 5))) & 0b11111); }// word[]; }
|
||||
static String[] clue(long w) { return CsvIndexService.clues(unpackIndex(w)); }
|
||||
static int simpel(long w) { return CsvIndexService.simpel(unpackIndex(w)); }
|
||||
static int length(long word) { return ((63 - Long.numberOfLeadingZeros(word & LETTER_MASK)) / 5) + 1; }
|
||||
public static String asWord(long word) {
|
||||
var b = new byte[Lemma.length(word)];
|
||||
for (var i = 0; i < b.length; i++) b[i] = (byte) ((word >>> (i * 5)) & 0b11111 | B64);
|
||||
@@ -851,14 +841,13 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static int[] candidateInfoForPattern(long[] res, long pattern, DictEntry entry, int lenb) {
|
||||
int numLongs = entry.numlong;
|
||||
static int[] candidateInfoForPattern(long[] res, long pattern, long[][] posBitsets, int numLongs) {
|
||||
boolean first = true;
|
||||
|
||||
for (long p = pattern; p != 0; ) {
|
||||
int combined = (int) (p & 0xFF);
|
||||
if (combined != 0) {
|
||||
long[] bs = entry.posBitsets[combined - 1];
|
||||
long[] bs = posBitsets[combined - 1];
|
||||
if (first) {
|
||||
System.arraycopy(bs, 0, res, 0, numLongs);
|
||||
first = false;
|
||||
@@ -888,8 +877,7 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
||||
return indices;
|
||||
}
|
||||
|
||||
static int candidateCountForPattern(final long[] res, final long pattern, final DictEntry entry, final int lenb) {
|
||||
val numLongs = entry.numlong;
|
||||
static int candidateCountForPattern(final long[] res, final long pattern, final DictEntry entry, final int numLongs) {
|
||||
val posBitsets = entry.posBitsets;
|
||||
boolean first = true;
|
||||
|
||||
@@ -975,7 +963,7 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
||||
if (assigned[s.key] != X) continue;
|
||||
var pattern = patternForSlot(grid, s);
|
||||
var index = dictIndex[s.length()];
|
||||
count = pattern == X ? index.length : candidateCountForPattern(bitset, pattern, index, s.length());
|
||||
count = pattern == X ? index.length : candidateCountForPattern(bitset, pattern, index, index.numlong);
|
||||
|
||||
if (count == 0) {
|
||||
current = PICK_NOT_DONE;
|
||||
@@ -1004,7 +992,7 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
||||
current.indices = null;
|
||||
return;
|
||||
}
|
||||
current.indices = candidateInfoForPattern(bitset, pattern, index, best.length());
|
||||
current.indices = candidateInfoForPattern(bitset, pattern, index.posBitsets, index.numlong);
|
||||
}
|
||||
boolean backtrack(int depth) {
|
||||
if (Thread.currentThread().isInterrupted()) return false;
|
||||
|
||||
Reference in New Issue
Block a user