introduce bitloops
This commit is contained in:
@@ -93,7 +93,7 @@ public record Export() {
|
||||
public record WordOut(String word, int[] cell, int startRow, int startCol, char direction, int arrowRow, int arrowCol, boolean isReversed, int complex, String[] clue) {
|
||||
|
||||
public WordOut(Lemma l, int startRow, int startCol, char d, int arrowRow, int arrowCol, boolean isReversed) {
|
||||
this(new String(l.word(), US_ASCII), new int[]{ arrowRow, arrowCol, startRow, startCol }, startRow, startCol, d, arrowRow, arrowCol, isReversed, l.simpel(), l.clue());
|
||||
this(l.asWord(), new int[]{ arrowRow, arrowCol, startRow, startCol }, startRow, startCol, d, arrowRow, arrowCol, isReversed, l.simpel(), l.clue());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -347,7 +347,7 @@ public class Main {
|
||||
static PuzzleResult attempt(Rng rng, Dict dict, Opts opts) {
|
||||
TOTAL_ATTEMPTS.incrementAndGet();
|
||||
var swe = new SwedishGenerator(rng);
|
||||
var mask = swe.generateMask(opts.pop, opts.gens);
|
||||
var mask = swe.generateMask(opts.pop, opts.gens, Math.max(opts.pop, (int) Math.floor(opts.pop * 1.5)));
|
||||
var filled = swe.fillMask(mask, dict.index(), opts.fillTimeout);
|
||||
|
||||
TOTAL_NODES.addAndGet(filled.stats().nodes);
|
||||
|
||||
@@ -19,6 +19,8 @@ import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.stream.IntStream;
|
||||
import static java.nio.charset.StandardCharsets.*;
|
||||
|
||||
/**
|
||||
* SwedishGenerator.java
|
||||
@@ -30,7 +32,10 @@ import java.util.Locale;
|
||||
@SuppressWarnings("ALL")
|
||||
public record SwedishGenerator(Rng rng) {
|
||||
|
||||
record CandidateInfo(int[] indices, int count) { }
|
||||
record CandidateInfo(int[] indices, int count) {
|
||||
|
||||
public CandidateInfo(int n) { this(null, n); }
|
||||
}
|
||||
|
||||
//@formatter:off
|
||||
@FunctionalInterface interface SlotVisitor { void visit(int key, long packedPos, int len); }
|
||||
@@ -283,15 +288,25 @@ public record SwedishGenerator(Rng rng) {
|
||||
}
|
||||
}
|
||||
|
||||
public static record Lemma(int index, byte[] word, int simpel) {
|
||||
public static record Lemma(int index, long word, byte len, short simpel) {
|
||||
|
||||
static int LEMMA_COUNTER = 0;
|
||||
public Lemma(int index, String word, int simpel) { this(index, word.getBytes(StandardCharsets.US_ASCII), simpel); }
|
||||
static long pack(byte[] b) {
|
||||
long w = 0;
|
||||
for (var i = 0; i < b.length; i++) w |= ((long) b[i] & ~64) << (i * 5);
|
||||
return w;
|
||||
}
|
||||
public Lemma(int index, String word, int simpel) { this(index, pack(word.getBytes(US_ASCII)), (byte) word.length(), (short) simpel); }
|
||||
public Lemma(String word, int simpel) { this(LEMMA_COUNTER++, word, simpel); }
|
||||
byte byteAt(int idx) { return word[idx]; }
|
||||
byte byteAt(int idx) { return (byte) ((word >>> (idx * 5)) & 0b11111 | Grid.B64); }// word[]; }
|
||||
@Override public int hashCode() { return index; }
|
||||
@Override public boolean equals(Object o) { return (o == this) || (o instanceof Lemma l && l.index == index); }
|
||||
String[] clue() { return CsvIndexService.clues(index); }
|
||||
public String asWord() {
|
||||
var b = new byte[len];
|
||||
for (var i = 0; i < len; i++) b[i] = (byte) ((word >>> (i * 5)) & 0b11111 | Grid.B64);
|
||||
return new String(b, US_ASCII);
|
||||
}
|
||||
}
|
||||
|
||||
public static record Dict(
|
||||
@@ -302,7 +317,7 @@ public record SwedishGenerator(Rng rng) {
|
||||
var index = new DictEntry[MAX_WORD_LENGTH_PLUS_ONE];
|
||||
Arrays.setAll(index, i -> new DictEntry(i));
|
||||
for (var lemma : wordz) {
|
||||
var L = lemma.word.length;
|
||||
var L = lemma.len;
|
||||
|
||||
var entry = index[L];
|
||||
var idx = entry.words.size();
|
||||
@@ -320,7 +335,7 @@ public record SwedishGenerator(Rng rng) {
|
||||
static Dict loadDict(String wordsPath) {
|
||||
try {
|
||||
var map = new ArrayList<Lemma>();
|
||||
Files.lines(Path.of(wordsPath), StandardCharsets.UTF_8).forEach(line -> CsvIndexService.lineToLemma(line, map::add));
|
||||
Files.lines(Path.of(wordsPath), UTF_8).forEach(line -> CsvIndexService.lineToLemma(line, map::add));
|
||||
return new Dict(map.toArray(Lemma[]::new));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
@@ -549,7 +564,7 @@ public record SwedishGenerator(Rng rng) {
|
||||
return best;
|
||||
}
|
||||
|
||||
public Grid generateMask(int popSize, int gens) {
|
||||
public Grid generateMask(int popSize, int gens, int pairs) {
|
||||
class GridAndFit {
|
||||
|
||||
Grid grid;
|
||||
@@ -569,7 +584,6 @@ public record SwedishGenerator(Rng rng) {
|
||||
for (var gen = 0; gen < gens; gen++) {
|
||||
if (Thread.currentThread().isInterrupted()) break;
|
||||
var children = new ArrayList<GridAndFit>();
|
||||
var pairs = Math.max(popSize, (int) Math.floor(popSize * 1.5));
|
||||
|
||||
for (var k = 0; k < pairs; k++) {
|
||||
var p1 = pop.get(rng.randint(0, pop.size() - 1));
|
||||
@@ -595,18 +609,16 @@ public record SwedishGenerator(Rng rng) {
|
||||
}
|
||||
pop = next;
|
||||
|
||||
if (Main.VERBOSE && gen % 10 == 0) {
|
||||
var bestF = pop.get(0).fit();
|
||||
System.out.println(" gen " + gen + "/" + gens + " bestFitness=" + bestF);
|
||||
}
|
||||
if (Main.VERBOSE && (gen & 15) == 15) System.out.println(" gen " + gen + "/" + gens + " bestFitness=" + pop.get(0).fit());
|
||||
}
|
||||
|
||||
pop.sort(Comparator.comparingLong(GridAndFit::fit));
|
||||
return pop.get(0).grid;
|
||||
}
|
||||
static void patternForSlot(Grid grid, Slot s, byte[] pat) {
|
||||
byte ch;
|
||||
for (int i = 0, len = s.len(); i < len; i++) {
|
||||
var ch = grid.byteAt(s.pos(i));
|
||||
ch = grid.byteAt(s.pos(i));
|
||||
pat[i] = isLetter(ch) ? ch : DASH;
|
||||
}
|
||||
}
|
||||
@@ -638,26 +650,29 @@ public record SwedishGenerator(Rng rng) {
|
||||
undoBuffer[offset] = mask;
|
||||
return true;
|
||||
}
|
||||
static final CandidateInfo[] CANDIDATES = IntStream.range(0, 10192 << 2).mapToObj(CandidateInfo::new).toArray(CandidateInfo[]::new);
|
||||
static CandidateInfo candidateInfoForPattern(Context ctx, DictEntry entry, int len) {
|
||||
var pattern = ctx.pattern;
|
||||
var listBuffer = ctx.intListBuffer;
|
||||
var listCount = 0;
|
||||
var pattern = ctx.pattern;
|
||||
var listBuffer = ctx.intListBuffer;
|
||||
var listCount = 0;
|
||||
IntList tmp;
|
||||
byte ch;
|
||||
for (var i = 0; i < len; i++) {
|
||||
var ch = pattern[i];
|
||||
ch = pattern[i];
|
||||
if (isLetter(ch)) {
|
||||
listBuffer[listCount++] = entry.pos[i][ch - 'A'];
|
||||
}
|
||||
}
|
||||
|
||||
if (listCount == 0) {
|
||||
return new CandidateInfo(null, entry.words.size());
|
||||
return CANDIDATES[entry.words.size()];
|
||||
}
|
||||
|
||||
// Sort constraints by size to optimize intersection
|
||||
for (int i = 0; i < listCount - 1; i++) {
|
||||
for (int j = i + 1; j < listCount; j++) {
|
||||
for (var i = 0; i < listCount - 1; i++) {
|
||||
for (var j = i + 1; j < listCount; j++) {
|
||||
if (listBuffer[j].size() < listBuffer[i].size()) {
|
||||
var tmp = listBuffer[i];
|
||||
tmp = listBuffer[i];
|
||||
listBuffer[i] = listBuffer[j];
|
||||
listBuffer[j] = tmp;
|
||||
}
|
||||
@@ -668,14 +683,14 @@ public record SwedishGenerator(Rng rng) {
|
||||
var curLen = listBuffer[0].size();
|
||||
if (listCount == 1) return new CandidateInfo(cur, curLen);
|
||||
|
||||
int[] b1 = ctx.inter1;
|
||||
int[] b2 = ctx.inter2;
|
||||
int[] in = cur;
|
||||
int[] out = b1;
|
||||
val b1 = ctx.inter1;
|
||||
val b2 = ctx.inter2;
|
||||
var in = cur;
|
||||
var out = b1;
|
||||
|
||||
for (var k = 1; k < listCount; k++) {
|
||||
var nxt = listBuffer[k];
|
||||
curLen = intersectSorted(in, curLen, nxt.data(), nxt.size(), out);
|
||||
tmp = listBuffer[k];
|
||||
curLen = intersectSorted(in, curLen, tmp.data(), tmp.size(), out);
|
||||
in = out;
|
||||
out = (out == b1) ? b2 : b1;
|
||||
if (curLen == 0) break;
|
||||
|
||||
Reference in New Issue
Block a user