introduce bitloops

This commit is contained in:
mike
2026-01-17 13:22:04 +01:00
parent 0c56fafeaa
commit 9102dcb922
10 changed files with 706 additions and 82 deletions

View File

@@ -4,6 +4,7 @@ import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.val;
import puzzle.Masker.Clues;
import puzzle.SwedishGenerator.Rng;
import java.io.IOException;
@@ -15,11 +16,10 @@ import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Collectors;
import static puzzle.CsvIndexService.SC;
import static puzzle.Export.*;
import static puzzle.SwedishGenerator.*;
import static puzzle.Export.Dicts.loadDict;
public class Main {
@@ -44,11 +44,12 @@ public class Main {
@NoArgsConstructor
public static class Opts {
static int SSIZE = 20;
public int seed = (int) (System.nanoTime() ^ System.currentTimeMillis());
public int clueSize = 20;
public int pop = 40;
public int offspring = 60;
public int gens = 500;
public int clueSize = SSIZE;
public int pop = SSIZE * 2;
public int offspring = SSIZE * 3;
public int gens = 600;
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());
@@ -59,16 +60,7 @@ public class Main {
}
void main(String[] args) {
var csv = Paths.get("nl_score_hints_v3.csv");
var idx = Paths.get("nl_score_hints_v3.idx");
try {
val scv = new CsvIndexService(csv, idx);
scv.ensureLoaded();
ScopedValue.where(SC, scv).run(() -> _main(args));
} catch (IOException e) {
throw new RuntimeException(e);
}
_main(args);
}
public void _main(String[] args) {
var opts = parseArgs(args);
@@ -274,7 +266,7 @@ public class Main {
PuzzleResult generatePuzzle(Opts opts) {
var tLoad0 = System.nanoTime();
var dict = loadDict(opts.wordsPath);
var dict = DictData.DICT;//loadDict(opts.wordsPath);
var tLoad1 = System.nanoTime();
section("Load");
@@ -294,10 +286,9 @@ public class Main {
try {
// Keep at least some tasks in flight
final var service = CsvIndexService.SC.get();
for (int i = 0; i < opts.threads; i++) {
final int attemptIdx = ++submitted;
completionService.submit(() -> ScopedValue.where(CsvIndexService.SC, service).call(() -> attempt(new Rng(opts.seed + attemptIdx), dict, opts)));
completionService.submit(() -> attempt(new Rng(opts.seed + attemptIdx), dict, opts));
}
while (System.currentTimeMillis() < deadline) {
@@ -314,7 +305,7 @@ public class Main {
// Submit another task if we still have time
if (System.currentTimeMillis() < deadline) {
final int attemptIdx = ++submitted;
completionService.submit(() -> ScopedValue.where(CsvIndexService.SC, service).call(() -> attempt(new Rng(opts.seed + attemptIdx), dict, opts)));
completionService.submit(() -> attempt(new Rng(opts.seed + attemptIdx), dict, opts));
}
}
if (resFinal == null) warn("status : UNSOLVED (timeout)");
@@ -381,11 +372,44 @@ public class Main {
return null;
}
}
static Clues generateClues() {
String simple = "000 3000\n" +
" 3 \n" +
" 31 \n" +
" 3\n" +
"1 \n" +
"1 \n" +
"1 2\n" +
"1 222 3";
String sampleComplex = "1 0000\n" +
"1 \n" +
"00 01 \n" +
" 1 \n" +
" 1 \n" +
" 2 1 \n" +
" 1 \n" +
"221 22\n";
String def = " 30000\n" +
"0 001 \n" +
" 1 \n" +
" 3 \n" +
" 3 \n" +
" 32 \n" +
" 32 2\n" +
"2222 3";
return Clues.parse(sampleComplex
);
}
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;
}
static PuzzleResult _attempt(Rng rng, Dict dict, Opts opts) {
long t0 = System.currentTimeMillis();
TOTAL_ATTEMPTS.incrementAndGet();
var masker = new Masker(rng, new int[STACK_SIZE], Masker.Clues.createEmpty());
var mask = masker.generateMask(opts.clueSize, opts.pop, opts.gens, opts.offspring);
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());
@@ -423,7 +447,9 @@ public class Main {
"[ATTEMPT] thread=%s | status=%s | nodes=%d | backtracks=%d | nps=%d | simplicity=%s | time=%.1fs%n",
name, status, filled.nodes(), filled.backtracks(), nps, simplicity, totalTime
);
if (!filled.ok()) {
System.out.println(Arrays.stream(new Clued(mask).gridToString().split("\n")).map(s -> "\"" + s + "\\n\" +").collect(Collectors.joining("\n")));
}
if (filled.ok() && (opts.minSimplicity <= 0 || filled.stats().simplicity >= opts.minSimplicity)) {
return new PuzzleResult(new Clued(mask), new Gridded(grid), slotInfo, filled);
}
@@ -441,7 +467,7 @@ public class Main {
record JsonExportedPuzzle(String date, String theme, int difficulty, Rewards rewards, String[] grid, WordOut[] words) { }
private static String toJson(ExportedPuzzle puzzle, String date, String theme) {
return CsvIndexService.GSON.toJson(new JsonExportedPuzzle(date, theme, puzzle.difficulty(), puzzle.rewards(), puzzle.grid(), puzzle.words()));
return Meta.GSON.toJson(new JsonExportedPuzzle(date, theme, puzzle.difficulty(), puzzle.rewards(), puzzle.grid(), puzzle.words()));
}
private static String escapeJson(String s) {