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;
|
||||
|
||||
@@ -168,7 +168,7 @@ public class MainTest {
|
||||
Assertions.assertEquals(12348, foundSeed, "Found seed changed");
|
||||
Assertions.assertEquals(22, res.filled().clueMap().size(), "Number of assigned words changed");
|
||||
Assertions.assertEquals(747.5454545454545, res.filled().stats().simplicity, 1e-9, "Simplicity value changed");
|
||||
Assertions.assertArrayEquals(new byte[]{ 'I', 'E', 'M', 'A', 'N', 'D', 'S' }, res.filled().clueMap().get(515).word());
|
||||
Assertions.assertEquals(Lemma.pack(new byte[]{ 'I', 'E', 'M', 'A', 'N', 'D', 'S' }), res.filled().clueMap().get(515).word());
|
||||
}
|
||||
@Test
|
||||
public void testIsLetterA() {
|
||||
|
||||
@@ -79,7 +79,7 @@ public class SwedishGeneratorTest {
|
||||
assertFalse(grid.isDigitAt(0));
|
||||
assertTrue(grid.isDigitAt(Grid.offset(0, 1)));
|
||||
assertFalse(grid.isLetterAt(Grid.offset(0, 1)));
|
||||
assertTrue(grid.isLetterAt( 0));
|
||||
assertTrue(grid.isLetterAt(0));
|
||||
assertFalse(grid.isLetterAt(Grid.offset(0, 1)));
|
||||
|
||||
var copy = grid.deepCopyGrid();
|
||||
@@ -110,8 +110,8 @@ public class SwedishGeneratorTest {
|
||||
var l8a = new Lemma("INERENAE", 1);
|
||||
|
||||
var l1 = new Lemma("APPLE", 5);
|
||||
Assertions.assertArrayEquals("APPLE".getBytes(StandardCharsets.US_ASCII), l1.word());
|
||||
assertEquals(5, l1.word().length);
|
||||
Assertions.assertEquals(Lemma.pack("APPLE".getBytes(StandardCharsets.US_ASCII)), l1.word());
|
||||
assertEquals(5, l1.len());
|
||||
assertEquals(5, l1.simpel());
|
||||
assertEquals((byte) 'A', l1.byteAt(0));
|
||||
|
||||
@@ -123,7 +123,7 @@ public class SwedishGeneratorTest {
|
||||
|
||||
var entry3 = dict.index()[3];
|
||||
assertEquals(1, entry3.words().size());
|
||||
Assertions.assertArrayEquals("AXE".getBytes(StandardCharsets.US_ASCII), entry3.words().getFirst().word());
|
||||
assertEquals(Lemma.pack("AXE".getBytes(StandardCharsets.US_ASCII)), entry3.words().getFirst().word());
|
||||
|
||||
// Check pos indexing
|
||||
// AXE: A at 0, X at 1, E at 2
|
||||
@@ -279,7 +279,7 @@ public class SwedishGeneratorTest {
|
||||
|
||||
// 1. Successful placement in empty grid
|
||||
assertTrue(placeWord(grid, s, w1, undoBuffer, 0));
|
||||
assertEquals('A', grid.byteAt( 0));
|
||||
assertEquals('A', grid.byteAt(0));
|
||||
assertEquals('B', grid.byteAt(Grid.offset(0, 1)));
|
||||
assertEquals('C', grid.byteAt(Grid.offset(0, 2)));
|
||||
assertEquals(0b111L, undoBuffer[0]);
|
||||
|
||||
Reference in New Issue
Block a user