introduce bitloops

This commit is contained in:
mike
2026-01-12 06:42:22 +01:00
parent b7b66b5cd6
commit f655f70ab8
5 changed files with 38 additions and 36 deletions

View File

@@ -81,7 +81,7 @@ public record Export() {
public void clear() { Arrays.fill(bits, 0L); }
}
record Placed(Lemma lemma, int startRow, int startCol, char direction, int arrowRow, int arrowCol, int[] cells, boolean isReversed) {
record Placed(long lemma, int startRow, int startCol, char direction, int arrowRow, int arrowCol, int[] cells, boolean isReversed) {
public static final char HORIZONTAL = 'h';
static final char VERTICAL = 'v';
@@ -91,8 +91,8 @@ 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(l.asWord(), new int[]{ arrowRow, arrowCol, startRow, startCol }, startRow, startCol, d, arrowRow, arrowCol, isReversed, l.simpel(), l.clue());
public WordOut(long l, int startRow, int startCol, char d, int arrowRow, int arrowCol, boolean isReversed) {
this(Lemma.asWord(l), new int[]{ arrowRow, arrowCol, startRow, startCol }, startRow, startCol, d, arrowRow, arrowCol, isReversed, Lemma.simpel(l), Lemma.clue(l));
}
}
@@ -101,7 +101,7 @@ public record Export() {
public record PuzzleResult(SwedishGenerator swe, Dict dict, Gridded mask, FillResult filled) {
boolean inBounds(int r, int c) { return r >= 0 && r < SwedishGenerator.R && c >= 0 && c < SwedishGenerator.C; }
Placed extractPlacedFromSlot(Slot s, Lemma lemma) {
Placed extractPlacedFromSlot(Slot s, long lemma) {
var d = s.dir();
var cells = new int[s.len()];

View File

@@ -108,12 +108,12 @@ public record SwedishGenerator(Rng rng) {
public static record FillResult(boolean ok,
Gridded grid,
Map<Integer, Lemma> clueMap,
Map<Integer, Long> clueMap,
FillStats stats) {
public void calcSimpel() {
if (ok) {
clueMap.forEach((k, v) -> stats.simplicity += v.simpel());
clueMap.forEach((k, v) -> stats.simplicity += Lemma.simpel(v));
stats.simplicity = clueMap.isEmpty() ? 0 : stats.simplicity / clueMap.size();
}
}
@@ -243,7 +243,7 @@ public record SwedishGenerator(Rng rng) {
}
}
static record DictEntry(Lemma[] words, long[][] posBitsets) { }
static record DictEntry(long[] words, long[][] posBitsets) { }
public static record Lemma(long word) {
@@ -261,13 +261,15 @@ public record SwedishGenerator(Rng rng) {
}
public Lemma(int index, String word) { this(pack(index, word.getBytes(US_ASCII))); }
public Lemma(String word) { this(LEMMA_COUNTER++, word); }
byte byteAt(int idx) { return (byte) ((word >>> (idx * 5)) & 0b11111 | B64); }// word[]; }
byte byteAt(int idx) { return Lemma.byteAt(word, idx); }// word[]; }
static byte byteAt(long word, int idx) { return (byte) ((word >>> (idx * 5)) & 0b11111 | B64); }// word[]; }
int intAt(int idx) { return (int) (((word >>> (idx * 5))) & 0b11111); }// word[]; }
@Override public int hashCode() { return unpackIndex(word); }
@Override public boolean equals(Object o) { return (o == this) || (o instanceof Lemma l && l.word == word); }
String[] clue() { return CsvIndexService.clues(unpackIndex(word)); }
int simpel() { return CsvIndexService.simpel(unpackIndex(word)); }
int length() {
static String[] clue(long w) { return CsvIndexService.clues(unpackIndex(w)); }
static int simpel(long w) { return CsvIndexService.simpel(unpackIndex(w)); }
int length() { return Lemma.length(word); }
static int length(long word) {
if (word == 0) return 0;
int highestBit = 63 - Long.numberOfLeadingZeros(word & LETTER_MASK);
return (highestBit / 5) + 1;
@@ -277,9 +279,9 @@ public record SwedishGenerator(Rng rng) {
int highestBit = 63 - Long.numberOfLeadingZeros(p & LETTER_MASK); // 0-based
return (highestBit / 5) + 1;
}
public String asWord() {
var b = new byte[length()];
for (var i = 0; i < length(); i++) b[i] = (byte) ((word >>> (i * 5)) & 0b11111 | B64);
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);
return new String(b, US_ASCII);
}
static int unpackIndex(long w) {
@@ -312,7 +314,7 @@ public record SwedishGenerator(Rng rng) {
}
for (int i = MIN_LEN; i < index.length; i++) if (index[i].words().size() <= 0) throw new RuntimeException("No words for length " + i);
this(Arrays.stream(index).map(i -> {
var words = i.words().toArray(Lemma[]::new);
var words = i.words().stream().mapToLong(ww -> ww.word).toArray();
int numWords = words.length;
int numLongs = (numWords + 63) >>> 6;
var bitsets = new long[i.pos().length * 26][numLongs];
@@ -677,13 +679,13 @@ public record SwedishGenerator(Rng rng) {
for (int i = 0; i < len; i++) cross += (count[s.pos(i)] - 1);
return cross * 10 + len;
}
static boolean placeWord(Grid grid, Slot s, Lemma w, int[] undoBuffer, int offset) {
static boolean placeWord(Grid grid, Slot s, long w, int[] undoBuffer, int offset) {
int mask = 0;
byte cur, ch;
for (int i = 0, leng = s.len(), idx; i < leng; i++) {
idx = s.pos(i);
cur = grid.byteAt(idx);
ch = w.byteAt(i);
ch = Lemma.byteAt(w, i);
if (cur == DASH) {
mask |= (1 << i);
grid.setByteAt(idx, ch);
@@ -778,9 +780,9 @@ public record SwedishGenerator(Rng rng) {
val used = new Bit1029();
// val assigned = new HashMap<Integer, Lemma>();
Lemma[] assigned = new Lemma[BIGG];
val ctx = CTX.get();
val count = ctx.cellCount;
long[] assigned = new long[BIGG];
val ctx = CTX.get();
val count = ctx.cellCount;
Arrays.fill(count, 0, SIZE, 0);
val slots = extractSlots(grid);
@@ -803,7 +805,7 @@ public record SwedishGenerator(Rng rng) {
lastLog = (now);
var done = 0;
for (var lemma : assigned) {
if (lemma != null) done++;
if (lemma != X) done++;
}
var pct = (TOTAL == 0) ? 100 : (int) Math.floor((done / (double) TOTAL) * 100);
var filled = Math.min(BAR_LEN, (int) Math.floor((pct / 100.0) * BAR_LEN));
@@ -824,7 +826,7 @@ public record SwedishGenerator(Rng rng) {
int bestScore = -1;
for (int i = 0, n = slots.size(); i < n; i++) {
var s = slots.get(i);
if (assigned[s.key()] != null) continue;
if (assigned[s.key()] != X) continue;
var entry = dictIndex[s.len()];
if (entry == null) return PICK_NOT_DONE;
ctx.pattern = patternForSlot(grid, s);
@@ -880,7 +882,7 @@ public record SwedishGenerator(Rng rng) {
int idxInArray = (int) (r * r * r * L);
var idx = idxs[idxInArray];
var w = entry.words[idx];
var lemIdx = Lemma.unpackIndex(w.word);
var lemIdx = Lemma.unpackIndex(w);
if (used.get(lemIdx)) continue;
if (!placeWord(grid, s, w, ctx.undo, depth)) continue;
@@ -890,7 +892,7 @@ public record SwedishGenerator(Rng rng) {
if (backtrack(depth + 1)) return true;
assigned[k] = null;
assigned[k] = X;
used.clear(lemIdx);
s.undoPlace(grid, ctx.undo[depth]);
}
@@ -909,7 +911,7 @@ public record SwedishGenerator(Rng rng) {
double r = rng.nextFloat();
int idxInArray = (int) (r * r * r * N);
var w = entry.words[idxInArray];
var lemIdx = Lemma.unpackIndex(w.word);
var lemIdx = Lemma.unpackIndex(w);
if (used.get(lemIdx)) continue;
if (!placeWord(grid, s, w, ctx.undo, depth)) continue;
@@ -919,7 +921,7 @@ public record SwedishGenerator(Rng rng) {
if (backtrack(depth + 1)) return true;
assigned[k] = null;
assigned[k] = X;
used.clear(lemIdx);
s.undoPlace(grid, ctx.undo[depth]);
}
@@ -940,9 +942,9 @@ public record SwedishGenerator(Rng rng) {
}
stats.seconds = (System.currentTimeMillis() - t0) / 1000.0;
Map<Integer, Lemma> lemmaMap = new HashMap<>();
Map<Integer, Long> lemmaMap = new HashMap<>();
for (var i = 0; i < assigned.length; i++) {
if (assigned[i] != null) {
if (assigned[i] != X) {
lemmaMap.put(i, assigned[i]);
}
}