introduce bitloops
This commit is contained in:
@@ -100,7 +100,7 @@ public final class CsvIndexService
|
|||||||
throw new RuntimeException("Index mismatch after rebuild. Requested=" + lineIndex + ", got line=" + preview(line));
|
throw new RuntimeException("Index mismatch after rebuild. Requested=" + lineIndex + ", got line=" + preview(line));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ensureLoaded() throws IOException {
|
public void ensureLoaded() throws IOException {
|
||||||
if (offsets != null && csvChannel != null && csvChannel.isOpen()) return;
|
if (offsets != null && csvChannel != null && csvChannel.isOpen()) return;
|
||||||
|
|
||||||
synchronized (lock) {
|
synchronized (lock) {
|
||||||
|
|||||||
@@ -131,9 +131,6 @@ public record Export() {
|
|||||||
}).limit(Long.bitCount(lo)));
|
}).limit(Long.bitCount(lo)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
char NOT_CLUE_NOT_LETTER_TO(byte b) {
|
|
||||||
return (char) (64 | b);
|
|
||||||
}
|
|
||||||
String gridToString(Clues clues) {
|
String gridToString(Clues clues) {
|
||||||
var sb = new StringBuilder(INIT);
|
var sb = new StringBuilder(INIT);
|
||||||
clues.forEachSlot((s, l, a) -> {
|
clues.forEachSlot((s, l, a) -> {
|
||||||
@@ -174,34 +171,17 @@ public record Export() {
|
|||||||
sb.setCharAt(r * (C + 1) + c, (char) (letter | 64));
|
sb.setCharAt(r * (C + 1) + c, (char) (letter | 64));
|
||||||
});
|
});
|
||||||
return sb.toString().replaceAll(" ", "" + emptyFallback).split("\n");
|
return sb.toString().replaceAll(" ", "" + emptyFallback).split("\n");
|
||||||
/*
|
|
||||||
var out = new String[R];
|
|
||||||
for (var r = 0; r < R; r++) {
|
|
||||||
var sb = new StringBuilder(C);
|
|
||||||
for (var c = 0; c < C; c++) {
|
|
||||||
var offset = Grid.offset(r, c);
|
|
||||||
if (clues.isClue(offset)) {
|
|
||||||
sb.append(clueChar.replace(new Cell(grid, clues, offset, clues.digitAt(offset))));
|
|
||||||
} else if (lisLetterAt(offset)) {
|
|
||||||
sb.append(NOT_CLUE_NOT_LETTER_TO(grid.letter32At(offset)));
|
|
||||||
} else {
|
|
||||||
sb.append(emptyFallback);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
out[r] = sb.toString();
|
|
||||||
}
|
|
||||||
return out;*/
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
record Bit1029(long[] bits) {
|
interface Bit1029 {
|
||||||
|
|
||||||
public Bit1029() { this(new long[2048]); }
|
public static long[] bit1029() { return new long[2048]; }
|
||||||
static int wordIndex(int bitIndex) { return bitIndex >> 6; }
|
static int wordIndex(int bitIndex) { return bitIndex >> 6; }
|
||||||
public boolean get(int bitIndex) { return (this.bits[wordIndex(bitIndex)] & 1L << bitIndex) != 0L; }
|
static public boolean get(long[] bits, int bitIndex) { return (bits[wordIndex(bitIndex)] & 1L << bitIndex) != 0L; }
|
||||||
public void set(int bitIndex) { bits[wordIndex(bitIndex)] |= 1L << bitIndex; }
|
static public void set(long[] bits, int bitIndex) { bits[wordIndex(bitIndex)] |= 1L << bitIndex; }
|
||||||
public void clear(int bitIndex) { this.bits[wordIndex(bitIndex)] &= ~(1L << bitIndex); }
|
static public void clear(long[] bits, int bitIndex) { bits[wordIndex(bitIndex)] &= ~(1L << bitIndex); }
|
||||||
public void clear() { Arrays.fill(bits, 0L); }
|
static public void clear(long[] bits) { Arrays.fill(bits, 0L); }
|
||||||
}
|
}
|
||||||
|
|
||||||
record Placed(long lemma, int slotKey, int[] cells) {
|
record Placed(long lemma, int slotKey, int[] cells) {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package puzzle;
|
|||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.val;
|
||||||
import puzzle.SwedishGenerator.Rng;
|
import puzzle.SwedishGenerator.Rng;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@@ -60,7 +61,14 @@ public class Main {
|
|||||||
public void main(String[] args) {
|
public void main(String[] args) {
|
||||||
var csv = Paths.get("nl_score_hints_v3.csv");
|
var csv = Paths.get("nl_score_hints_v3.csv");
|
||||||
var idx = Paths.get("nl_score_hints_v3.idx");
|
var idx = Paths.get("nl_score_hints_v3.idx");
|
||||||
ScopedValue.where(SC, new CsvIndexService(csv, idx)).run(() -> _main(args));
|
try {
|
||||||
|
val scv = new CsvIndexService(csv, idx);
|
||||||
|
scv.ensureLoaded();
|
||||||
|
ScopedValue.where(SC, scv).run(() -> _main(args));
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
public void _main(String[] args) {
|
public void _main(String[] args) {
|
||||||
var opts = parseArgs(args);
|
var opts = parseArgs(args);
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import puzzle.Export.DictEntryDTO;
|
|||||||
import puzzle.Export.Gridded;
|
import puzzle.Export.Gridded;
|
||||||
import puzzle.Export.Strings;
|
import puzzle.Export.Strings;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -20,7 +21,7 @@ import java.util.Arrays;
|
|||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.stream.IntStream;
|
import java.util.stream.IntStream;
|
||||||
import static java.nio.charset.StandardCharsets.*;
|
import static java.nio.charset.StandardCharsets.US_ASCII;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* NOTE:
|
* NOTE:
|
||||||
@@ -66,6 +67,8 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
|||||||
static final int STACK_SIZE = 64;
|
static final int STACK_SIZE = 64;
|
||||||
static final char C_DASH = '\0';
|
static final char C_DASH = '\0';
|
||||||
static final byte _1 = 49, _9 = 57, A = 65, Z = 90, DASH = (byte) C_DASH;
|
static final byte _1 = 49, _9 = 57, A = 65, Z = 90, DASH = (byte) C_DASH;
|
||||||
|
static final long RANGE_0_SIZE = (long) SIZE_MIN_1 - 0L + 1L;
|
||||||
|
static final long RANGE_0_624 = 624L - 0L + 1L;
|
||||||
//72 << 3;
|
//72 << 3;
|
||||||
static final int CLUE_INDEX_MAX_SIZE = (288 | 3) + 1;
|
static final int CLUE_INDEX_MAX_SIZE = (288 | 3) + 1;
|
||||||
static int clamp(int x, int a, int b) { return Math.max(a, Math.min(b, x)); }
|
static int clamp(int x, int a, int b) { return Math.max(a, Math.min(b, x)); }
|
||||||
@@ -140,11 +143,7 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
|||||||
}
|
}
|
||||||
public int wordCount() {
|
public int wordCount() {
|
||||||
int k = 0;
|
int k = 0;
|
||||||
for (var n = 1; n < clueMap.length; n++) {
|
for (var n = 1; n < clueMap.length; n++) if (clueMap[n] != X) k++;
|
||||||
if (clueMap[n] != X) {
|
|
||||||
k++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return k;
|
return k;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -165,38 +164,26 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
|||||||
x = y;
|
x = y;
|
||||||
return y;
|
return y;
|
||||||
}
|
}
|
||||||
byte randbyte(int min, int max) {
|
|
||||||
var u = (nextU32() & 0xFFFFFFFFL);
|
|
||||||
var range = (long) max - (long) min + 1L;
|
|
||||||
return (byte) (min + (u % range));
|
|
||||||
}
|
|
||||||
int randint2bit() { return nextU32() & 3; }
|
int randint2bit() { return nextU32() & 3; }
|
||||||
byte randint2bitByte() { return (byte) (nextU32() & 3); }
|
byte randint2bitByte() { return (byte) (nextU32() & 3); }
|
||||||
int randint(int min, int max) {
|
int randint(int max) { return (int) (((nextU32() & 0xFFFFFFFFL) % ((long) max - 0L + 1L))); }
|
||||||
var u = (nextU32() & 0xFFFFFFFFL);
|
int randint0_SIZE() { return (int) (((nextU32() & 0xFFFFFFFFL) % RANGE_0_SIZE)); }
|
||||||
var range = (long) max - (long) min + 1L;
|
int randint0_624() { return (int) (((nextU32() & 0xFFFFFFFFL) % RANGE_0_624)); }
|
||||||
return (int) (min + (u % range));
|
|
||||||
}
|
|
||||||
double nextFloat() { return (nextU32() & 0xFFFFFFFFL) / 4294967295.0; }
|
double nextFloat() { return (nextU32() & 0xFFFFFFFFL) / 4294967295.0; }
|
||||||
int biasedIndexPow3(int N) {
|
int biasedIndexPow3(int N) { return (int) (((Math.min(nextU32(), Math.min(nextU32(), nextU32())) & 0xFFFFFFFFL) * (long) N) >>> 32); }
|
||||||
int m = Math.min(nextU32(), Math.min(nextU32(), nextU32()));
|
|
||||||
return (int) (((m & 0xFFFFFFFFL) * (long) N) >>> 32);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
static class Clues {
|
static class Clues {
|
||||||
|
|
||||||
long lo, hi, vlo, vhi, rlo, rhi;
|
long lo, hi, vlo, vhi, rlo, rhi;
|
||||||
public static Clues createEmpty() {
|
public static Clues createEmpty() { return new Clues(0, 0, 0, 0, 0, 0); }
|
||||||
return new Clues(0, 0, 0, 0, 0, 0);
|
|
||||||
}
|
|
||||||
public Clues deepCopyGrid() { return new Clues(lo, hi, vlo, vhi, rlo, rhi); }
|
public Clues deepCopyGrid() { return new Clues(lo, hi, vlo, vhi, rlo, rhi); }
|
||||||
boolean clueless(int idx) {
|
boolean clueless(int idx) {
|
||||||
if (!isClue(idx)) return false;
|
if (!isClue(idx)) return false;
|
||||||
if ((idx & 64) == 0) {
|
if ((idx & 64) == 0) {
|
||||||
clearClueLo(idx);
|
clearClueLo(idx);
|
||||||
}else{
|
} else {
|
||||||
clearClueHi(idx);
|
clearClueHi(idx);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -260,7 +247,7 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
|||||||
return (Long.bitCount(matchLo & MASK_LO) + Long.bitCount(matchHi & MASK_HI)) / SIZED;
|
return (Long.bitCount(matchLo & MASK_LO) + Long.bitCount(matchHi & MASK_HI)) / SIZED;
|
||||||
}
|
}
|
||||||
public Grid toGrid() { return new Grid(new byte[SIZE], lo, hi); }
|
public Grid toGrid() { return new Grid(new byte[SIZE], lo, hi); }
|
||||||
public void forEachSlot(SlotVisitor visitor) {
|
public void forEachSlot(SwedishGenerator.SlotVisitor visitor) {
|
||||||
for (var l = lo & ~rlo & vlo; l != X; l &= l - 1) processSlot(this, visitor, Slot.packSlotKey(Long.numberOfTrailingZeros(l), 1));
|
for (var l = lo & ~rlo & vlo; l != X; l &= l - 1) processSlot(this, visitor, Slot.packSlotKey(Long.numberOfTrailingZeros(l), 1));
|
||||||
for (var l = lo & ~rlo & ~vlo; l != X; l &= l - 1) processSlot(this, visitor, Slot.packSlotKey(Long.numberOfTrailingZeros(l), 0));
|
for (var l = lo & ~rlo & ~vlo; l != X; l &= l - 1) processSlot(this, visitor, Slot.packSlotKey(Long.numberOfTrailingZeros(l), 0));
|
||||||
for (var l = lo & rlo & ~vlo; l != X; l &= l - 1) processSlotRev(this, visitor, Slot.packSlotKey(Long.numberOfTrailingZeros(l), 2));
|
for (var l = lo & rlo & ~vlo; l != X; l &= l - 1) processSlotRev(this, visitor, Slot.packSlotKey(Long.numberOfTrailingZeros(l), 2));
|
||||||
@@ -308,10 +295,12 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
|||||||
static String[] clue(long w) { return CsvIndexService.clues(unpackIndex(w)); }
|
static String[] clue(long w) { return CsvIndexService.clues(unpackIndex(w)); }
|
||||||
static int simpel(long w) { return CsvIndexService.simpel(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 int length(long word) { return ((63 - Long.numberOfLeadingZeros(word & LETTER_MASK)) / 5) + 1; }
|
||||||
|
static ThreadLocal<byte[]> BYTES = ThreadLocal.withInitial(() -> new byte[SwedishGenerator.MAX_WORD_LENGTH]);
|
||||||
public static String asWord(long word) {
|
public static String asWord(long word) {
|
||||||
var b = new byte[Lemma.length(word)];
|
val len = Lemma.length(word);
|
||||||
for (var i = 0; i < b.length; i++) b[i] = (byte) ((word >>> (i * 5)) & 0b11111 | B64);
|
var b = BYTES.get();//new byte[Lemma.length(word)];
|
||||||
return new String(b, US_ASCII);
|
for (int i = 0, bi = 0; i < len * 5; bi++, i += 5) b[bi] = (byte) (((word >>> i) & 31) | 64);
|
||||||
|
return new String(b, 0, 0, len);
|
||||||
}
|
}
|
||||||
static int unpackIndex(long w) { return (int) (w >>> 40); }
|
static int unpackIndex(long w) { return (int) (w >>> 40); }
|
||||||
static int unpackLetters(long w) { return (int) (w & LETTER_MASK); }
|
static int unpackLetters(long w) { return (int) (w & LETTER_MASK); }
|
||||||
@@ -330,12 +319,7 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
|||||||
var entry = index[L];
|
var entry = index[L];
|
||||||
var idx = entry.words().size();
|
var idx = entry.words().size();
|
||||||
entry.words().add(lemma);
|
entry.words().add(lemma);
|
||||||
|
for (var i = 0; i < L; i++) entry.pos()[i][Lemma.byteAt(lemma, i) - 1].add(idx);
|
||||||
for (var i = 0; i < L; i++) {
|
|
||||||
var letter = Lemma.byteAt(lemma, i) - 1;
|
|
||||||
if (letter < 0 || letter >= 26) throw new RuntimeException("Illegal letter: " + letter + " in word " + lemma);
|
|
||||||
entry.pos()[i][letter].add(idx);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
for (int i = MIN_LEN; i < index.length; i++) if (index[i].words().size() <= 0) throw new RuntimeException("No words for length " + i);
|
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 -> {
|
this(Arrays.stream(index).map(i -> {
|
||||||
@@ -360,7 +344,7 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
|||||||
static Dict loadDict(String wordsPath) {
|
static Dict loadDict(String wordsPath) {
|
||||||
try {
|
try {
|
||||||
var map = new LongArrayList(100_000);
|
var map = new LongArrayList(100_000);
|
||||||
Files.lines(Path.of(wordsPath), UTF_8).forEach(line -> CsvIndexService.lineToLemma(line, map::add));
|
Files.lines(Path.of(wordsPath), StandardCharsets.UTF_8).forEach(line -> CsvIndexService.lineToLemma(line, map::add));
|
||||||
return new Dict(map.toArray());
|
return new Dict(map.toArray());
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
@@ -601,7 +585,8 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
|||||||
Clues randomMask(final int clueSize) {
|
Clues randomMask(final int clueSize) {
|
||||||
var g = Clues.createEmpty();
|
var g = Clues.createEmpty();
|
||||||
for (int placed = 0, guard = 0, idx; placed < clueSize && guard < 4000; guard++) {
|
for (int placed = 0, guard = 0, idx; placed < clueSize && guard < 4000; guard++) {
|
||||||
idx = rng.randint(0, SIZE_MIN_1);
|
|
||||||
|
idx = rng.randint0_SIZE();
|
||||||
if (g.isClue(idx)) continue;
|
if (g.isClue(idx)) continue;
|
||||||
var d_idx = rng.randint2bitByte();
|
var d_idx = rng.randint2bitByte();
|
||||||
if (g.hasRoomForClue(OFFSETS_D_IDX[Slot.packSlotKey(idx, d_idx)])) {
|
if (g.hasRoomForClue(OFFSETS_D_IDX[Slot.packSlotKey(idx, d_idx)])) {
|
||||||
@@ -613,9 +598,9 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
|||||||
}
|
}
|
||||||
Clues mutate(Clues c) {
|
Clues mutate(Clues c) {
|
||||||
int ri;
|
int ri;
|
||||||
var bytes = MUTATE_RI[rng.randint(0, SIZE_MIN_1)];
|
var bytes = MUTATE_RI[rng.randint0_SIZE()];
|
||||||
for (var k = 0; k < 4; k++) {
|
for (var k = 0; k < 4; k++) {
|
||||||
ri = bytes[rng.randint(0, 624)];
|
ri = bytes[rng.randint0_624()];
|
||||||
if (!c.clueless(ri)) {
|
if (!c.clueless(ri)) {
|
||||||
var d_idx = rng.randint2bitByte();
|
var d_idx = rng.randint2bitByte();
|
||||||
if (c.hasRoomForClue(OFFSETS_D_IDX[Slot.packSlotKey(ri, d_idx)])) c.setClue(ri, d_idx);
|
if (c.hasRoomForClue(OFFSETS_D_IDX[Slot.packSlotKey(ri, d_idx)])) c.setClue(ri, d_idx);
|
||||||
@@ -697,8 +682,8 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
|||||||
|
|
||||||
for (var k = 0; k < offspring; k++) {
|
for (var k = 0; k < offspring; k++) {
|
||||||
if (Thread.currentThread().isInterrupted()) break;
|
if (Thread.currentThread().isInterrupted()) break;
|
||||||
var p1 = pop.get(rng.randint(0, pop.size() - 1));
|
var p1 = pop.get(rng.randint(pop.size() - 1));
|
||||||
var p2 = pop.get(rng.randint(0, pop.size() - 1));
|
var p2 = pop.get(rng.randint(pop.size() - 1));
|
||||||
var child = crossover(p1.grid, p2.grid);
|
var child = crossover(p1.grid, p2.grid);
|
||||||
children.add(new GridAndFit(hillclimb(child, clueSize, 70)));
|
children.add(new GridAndFit(hillclimb(child, clueSize, 70)));
|
||||||
}
|
}
|
||||||
@@ -731,39 +716,34 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
|||||||
return best.grid;
|
return best.grid;
|
||||||
}
|
}
|
||||||
|
|
||||||
static long patternForSlot(Grid grid, final int key, final long lo, final long hi) {
|
static long patternForSlot(final long glo, final long ghi, final byte[] g, final int key, final long lo, final long hi) {
|
||||||
final long glo = grid.lo, ghi = grid.hi;
|
if (((lo & glo) | (hi & ghi)) == X) {
|
||||||
if ((lo & glo) == X && (hi & ghi) == X) {
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
long p = 0;
|
long p = 0;
|
||||||
if (Slot.increasing(key)) {
|
if (Slot.increasing(key)) {
|
||||||
for (long b = lo & glo; b != X; b &= b - 1) {
|
for (long b = lo & glo; b != X; b &= b - 1) {
|
||||||
int idx = Long.numberOfTrailingZeros(b);
|
int idx = Long.numberOfTrailingZeros(b);
|
||||||
byte val = grid.g[idx];
|
|
||||||
int i = Long.bitCount(lo & ((1L << idx) - 1));
|
int i = Long.bitCount(lo & ((1L << idx) - 1));
|
||||||
p |= ((long) (i * 26 + val)) << (i << 3);
|
p |= ((long) (i * 26 + g[idx])) << (i << 3);
|
||||||
}
|
}
|
||||||
int offset = Long.bitCount(lo);
|
int offset = Long.bitCount(lo);
|
||||||
for (long b = hi & ghi; b != X; b &= b - 1) {
|
for (long b = hi & ghi; b != X; b &= b - 1) {
|
||||||
int idx = Long.numberOfTrailingZeros(b);
|
int idx = Long.numberOfTrailingZeros(b);
|
||||||
byte val = grid.g[64 | idx];
|
|
||||||
int i = offset + Long.bitCount(hi & ((1L << idx) - 1));
|
int i = offset + Long.bitCount(hi & ((1L << idx) - 1));
|
||||||
p |= ((long) (i * 26 + val)) << (i << 3);
|
p |= ((long) (i * 26 + g[64 | idx])) << (i << 3);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
int offset = Long.bitCount(hi);
|
int offset = Long.bitCount(hi);
|
||||||
for (long b = hi & ghi; b != X; b &= b - 1) {
|
for (long b = hi & ghi; b != X; b &= b - 1) {
|
||||||
int idx = Long.numberOfTrailingZeros(b);
|
int idx = Long.numberOfTrailingZeros(b);
|
||||||
byte val = grid.g[64 | idx];
|
|
||||||
int i = Long.bitCount(hi & ~((1L << idx) | ((1L << idx) - 1)));
|
int i = Long.bitCount(hi & ~((1L << idx) | ((1L << idx) - 1)));
|
||||||
p |= ((long) (i * 26 + val)) << (i << 3);
|
p |= ((long) (i * 26 + g[64 | idx])) << (i << 3);
|
||||||
}
|
}
|
||||||
for (long b = lo & glo; b != X; b &= b - 1) {
|
for (long b = lo & glo; b != X; b &= b - 1) {
|
||||||
int idx = Long.numberOfTrailingZeros(b);
|
int idx = Long.numberOfTrailingZeros(b);
|
||||||
byte val = grid.g[idx];
|
|
||||||
int i = offset + Long.bitCount(lo & ~((1L << idx) | ((1L << idx) - 1)));
|
int i = offset + Long.bitCount(lo & ~((1L << idx) | ((1L << idx) - 1)));
|
||||||
p |= ((long) (i * 26 + val)) << (i << 3);
|
p |= ((long) (i * 26 + g[idx])) << (i << 3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return p;
|
return p;
|
||||||
@@ -774,28 +754,28 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
|||||||
for (long b = hi; b != X; b &= b - 1) cross += (count[64 | Long.numberOfTrailingZeros(b)] - 1);
|
for (long b = hi; b != X; b &= b - 1) cross += (count[64 | Long.numberOfTrailingZeros(b)] - 1);
|
||||||
return cross * 10 + Slot.length(lo, hi);
|
return cross * 10 + Slot.length(lo, hi);
|
||||||
}
|
}
|
||||||
static boolean placeWord(Grid grid, final int key, final long lo, final long hi, final long w) {
|
static boolean placeWord(final Grid grid, final byte[] g, final int key, final long lo, final long hi, final long w) {
|
||||||
final long glo = grid.lo, ghi = grid.hi;
|
final long glo = grid.lo, ghi = grid.hi;
|
||||||
if (Slot.increasing(key)) {
|
if (Slot.increasing(key)) {
|
||||||
for (long b = lo & glo; b != X; b &= b - 1) {
|
for (long b = lo & glo; b != X; b &= b - 1) {
|
||||||
int idx = Long.numberOfTrailingZeros(b);
|
int idx = Long.numberOfTrailingZeros(b);
|
||||||
if (grid.g[idx] != Lemma.byteAt(w, Long.bitCount(lo & ((1L << idx) - 1)))) return false;
|
if (g[idx] != Lemma.byteAt(w, Long.bitCount(lo & ((1L << idx) - 1)))) return false;
|
||||||
}
|
}
|
||||||
int bcLo = Long.bitCount(lo);
|
int bcLo = Long.bitCount(lo);
|
||||||
for (long b = hi & ghi; b != X; b &= b - 1) {
|
for (long b = hi & ghi; b != X; b &= b - 1) {
|
||||||
int idx = Long.numberOfTrailingZeros(b);
|
int idx = Long.numberOfTrailingZeros(b);
|
||||||
if (grid.g[64 | idx] != Lemma.byteAt(w, bcLo + Long.bitCount(hi & ((1L << idx) - 1)))) return false;
|
if (g[64 | idx] != Lemma.byteAt(w, bcLo + Long.bitCount(hi & ((1L << idx) - 1)))) return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
long maskLo = lo & ~glo, maskHi = hi & ~ghi;
|
long maskLo = lo & ~glo, maskHi = hi & ~ghi;
|
||||||
if ((maskLo | maskHi) != X) {
|
if ((maskLo | maskHi) != X) {
|
||||||
for (long b = maskLo; b != X; b &= b - 1) {
|
for (long b = maskLo; b != X; b &= b - 1) {
|
||||||
int idx = Long.numberOfTrailingZeros(b);
|
int idx = Long.numberOfTrailingZeros(b);
|
||||||
grid.g[idx] = Lemma.byteAt(w, Long.bitCount(lo & ((1L << idx) - 1)));
|
g[idx] = Lemma.byteAt(w, Long.bitCount(lo & ((1L << idx) - 1)));
|
||||||
}
|
}
|
||||||
for (long b = maskHi; b != X; b &= b - 1) {
|
for (long b = maskHi; b != X; b &= b - 1) {
|
||||||
int idx = Long.numberOfTrailingZeros(b);
|
int idx = Long.numberOfTrailingZeros(b);
|
||||||
grid.g[64 | idx] = Lemma.byteAt(w, bcLo + Long.bitCount(hi & ((1L << idx) - 1)));
|
g[64 | idx] = Lemma.byteAt(w, bcLo + Long.bitCount(hi & ((1L << idx) - 1)));
|
||||||
}
|
}
|
||||||
grid.lo |= maskLo;
|
grid.lo |= maskLo;
|
||||||
grid.hi |= maskHi;
|
grid.hi |= maskHi;
|
||||||
@@ -804,22 +784,22 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
|||||||
int bcHi = Long.bitCount(hi);
|
int bcHi = Long.bitCount(hi);
|
||||||
for (long b = hi & ghi; b != X; b &= b - 1) {
|
for (long b = hi & ghi; b != X; b &= b - 1) {
|
||||||
int idx = Long.numberOfTrailingZeros(b);
|
int idx = Long.numberOfTrailingZeros(b);
|
||||||
if (grid.g[64 | idx] != Lemma.byteAt(w, Long.bitCount(hi & ~((1L << idx) | ((1L << idx) - 1))))) return false;
|
if (g[64 | idx] != Lemma.byteAt(w, Long.bitCount(hi & ~((1L << idx) | ((1L << idx) - 1))))) return false;
|
||||||
}
|
}
|
||||||
for (long b = lo & glo; b != X; b &= b - 1) {
|
for (long b = lo & glo; b != X; b &= b - 1) {
|
||||||
int idx = Long.numberOfTrailingZeros(b);
|
int idx = Long.numberOfTrailingZeros(b);
|
||||||
if (grid.g[idx] != Lemma.byteAt(w, bcHi + Long.bitCount(lo & ~((1L << idx) | ((1L << idx) - 1))))) return false;
|
if (g[idx] != Lemma.byteAt(w, bcHi + Long.bitCount(lo & ~((1L << idx) | ((1L << idx) - 1))))) return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
long maskLo = lo & ~glo, maskHi = hi & ~ghi;
|
long maskLo = lo & ~glo, maskHi = hi & ~ghi;
|
||||||
if ((maskLo | maskHi) != X) {
|
if ((maskLo | maskHi) != X) {
|
||||||
for (long b = maskHi; b != X; b &= b - 1) {
|
for (long b = maskHi; b != X; b &= b - 1) {
|
||||||
int idx = Long.numberOfTrailingZeros(b);
|
int idx = Long.numberOfTrailingZeros(b);
|
||||||
grid.g[64 | idx] = Lemma.byteAt(w, Long.bitCount(hi & ~((1L << idx) | ((1L << idx) - 1))));
|
g[64 | idx] = Lemma.byteAt(w, Long.bitCount(hi & ~((1L << idx) | ((1L << idx) - 1))));
|
||||||
}
|
}
|
||||||
for (long b = maskLo; b != X; b &= b - 1) {
|
for (long b = maskLo; b != X; b &= b - 1) {
|
||||||
int idx = Long.numberOfTrailingZeros(b);
|
int idx = Long.numberOfTrailingZeros(b);
|
||||||
grid.g[idx] = Lemma.byteAt(w, bcHi + Long.bitCount(lo & ~((1L << idx) | ((1L << idx) - 1))));
|
g[idx] = Lemma.byteAt(w, bcHi + Long.bitCount(lo & ~((1L << idx) | ((1L << idx) - 1))));
|
||||||
}
|
}
|
||||||
grid.lo |= maskLo;
|
grid.lo |= maskLo;
|
||||||
grid.hi |= maskHi;
|
grid.hi |= maskHi;
|
||||||
@@ -900,13 +880,14 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
public static FillResult fillMask(Rng rng, Slot[] slots, Grid mask) {
|
public static SwedishGenerator.FillResult fillMask(Rng rng, Slot[] slots, Grid mask) {
|
||||||
val multiThreaded = Thread.currentThread().getName().contains("pool");
|
val multiThreaded = Thread.currentThread().getName().contains("pool");
|
||||||
val NO_LOG = (!Main.VERBOSE || multiThreaded);
|
val NO_LOG = (!Main.VERBOSE || multiThreaded);
|
||||||
val grid = mask;
|
val grid = mask;
|
||||||
val used = new Bit1029();
|
val used = new long[2048];
|
||||||
val assigned = new long[CLUE_INDEX_MAX_SIZE];
|
val assigned = new long[CLUE_INDEX_MAX_SIZE];
|
||||||
val bitset = new long[2500];
|
val bitset = new long[2500];
|
||||||
|
val g = grid.g;
|
||||||
|
|
||||||
val TOTAL = slots.length;
|
val TOTAL = slots.length;
|
||||||
val slotScores = new int[TOTAL];
|
val slotScores = new int[TOTAL];
|
||||||
@@ -917,7 +898,7 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
|||||||
|
|
||||||
class Solver {
|
class Solver {
|
||||||
|
|
||||||
private final Pick CARRIER = new Pick(null, null, 0);
|
private final SwedishGenerator.Pick CARRIER = new Pick(null, null, 0);
|
||||||
long nodes;
|
long nodes;
|
||||||
long backtracks;
|
long backtracks;
|
||||||
int lastMRV;
|
int lastMRV;
|
||||||
@@ -949,7 +930,7 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
|||||||
for (int i = 0, count, count2 = -1, bestScore = -1, n = TOTAL; i < n; i++) {
|
for (int i = 0, count, count2 = -1, bestScore = -1, n = TOTAL; i < n; i++) {
|
||||||
var s = slots[i];
|
var s = slots[i];
|
||||||
if (assigned[s.key] != X) continue;
|
if (assigned[s.key] != X) continue;
|
||||||
var pattern = patternForSlot(grid, s.key, s.lo, s.hi);
|
var pattern = patternForSlot(grid.lo, grid.hi, g, s.key, s.lo, s.hi);
|
||||||
var index = s.entry;
|
var index = s.entry;
|
||||||
count = pattern == X ? index.length : candidateCountForPattern(bitset, pattern, index.posBitsets, index.numlong);
|
count = pattern == X ? index.length : candidateCountForPattern(bitset, pattern, index.posBitsets, index.numlong);
|
||||||
|
|
||||||
@@ -971,7 +952,7 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
|||||||
current = PICK_DONE;
|
current = PICK_DONE;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var pattern = patternForSlot(grid, best.key, best.lo, best.hi);
|
var pattern = patternForSlot(grid.lo, grid.hi, g, best.key, best.lo, best.hi);
|
||||||
var index = best.entry;
|
var index = best.entry;
|
||||||
current = CARRIER;
|
current = CARRIER;
|
||||||
current.slot = best;
|
current.slot = best;
|
||||||
@@ -1017,18 +998,18 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
|||||||
var idx = idxs[idxInArray];
|
var idx = idxs[idxInArray];
|
||||||
var w = entry.words[idx];
|
var w = entry.words[idx];
|
||||||
var lemIdx = Lemma.unpackIndex(w);
|
var lemIdx = Lemma.unpackIndex(w);
|
||||||
if (used.get(lemIdx)) continue;
|
if (Bit1029.get(used, lemIdx)) continue;
|
||||||
low = grid.lo;
|
low = grid.lo;
|
||||||
top = grid.hi;
|
top = grid.hi;
|
||||||
if (!placeWord(grid, k, slo, shi, w)) continue;
|
if (!placeWord(grid, g, k, slo, shi, w)) continue;
|
||||||
|
|
||||||
used.set(lemIdx);
|
Bit1029.set(used, lemIdx);
|
||||||
assigned[k] = w;
|
assigned[k] = w;
|
||||||
|
|
||||||
if (backtrack(depth + 1)) return true;
|
if (backtrack(depth + 1)) return true;
|
||||||
|
|
||||||
assigned[k] = X;
|
assigned[k] = X;
|
||||||
used.clear(lemIdx);
|
Bit1029.clear(used, lemIdx);
|
||||||
grid.lo = low;
|
grid.lo = low;
|
||||||
grid.hi = top;
|
grid.hi = top;
|
||||||
}
|
}
|
||||||
@@ -1044,18 +1025,18 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
|||||||
int idxInArray = (int) (r * r * r * (N - 1));
|
int idxInArray = (int) (r * r * r * (N - 1));
|
||||||
var w = entry.words[idxInArray];
|
var w = entry.words[idxInArray];
|
||||||
var lemIdx = Lemma.unpackIndex(w);
|
var lemIdx = Lemma.unpackIndex(w);
|
||||||
if (used.get(lemIdx)) continue;
|
if (Bit1029.get(used, lemIdx)) continue;
|
||||||
low = grid.lo;
|
low = grid.lo;
|
||||||
top = grid.hi;
|
top = grid.hi;
|
||||||
if (!placeWord(grid, k, slo, shi, w)) continue;
|
if (!placeWord(grid, g, k, slo, shi, w)) continue;
|
||||||
|
|
||||||
used.set(lemIdx);
|
Bit1029.set(used, lemIdx);
|
||||||
assigned[k] = w;
|
assigned[k] = w;
|
||||||
|
|
||||||
if (backtrack(depth + 1)) return true;
|
if (backtrack(depth + 1)) return true;
|
||||||
|
|
||||||
assigned[k] = X;
|
assigned[k] = X;
|
||||||
used.clear(lemIdx);
|
Bit1029.clear(used, lemIdx);
|
||||||
grid.lo = low;
|
grid.lo = low;
|
||||||
grid.hi = top;
|
grid.hi = top;
|
||||||
}
|
}
|
||||||
@@ -1071,7 +1052,8 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) {
|
|||||||
var ok = solver.backtrack(0);
|
var ok = solver.backtrack(0);
|
||||||
// final progress line
|
// final progress line
|
||||||
|
|
||||||
var res = new FillResult(ok, new Gridded(grid), assigned, new FillStats(solver.nodes, solver.backtracks, (System.currentTimeMillis() - t0) / 1000.0, solver.lastMRV));
|
var res = new FillResult(ok, new Gridded(grid), assigned,
|
||||||
|
new SwedishGenerator.FillStats(solver.nodes, solver.backtracks, (System.currentTimeMillis() - t0) / 1000.0, solver.lastMRV));
|
||||||
if (!multiThreaded) {
|
if (!multiThreaded) {
|
||||||
System.out.print("\r" + Strings.padRight("", 120) + "\r");
|
System.out.print("\r" + Strings.padRight("", 120) + "\r");
|
||||||
System.out.flush();
|
System.out.flush();
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ public class ExportFormatTest {
|
|||||||
var key = Slot.packSlotKey(0, CLUE_RIGHT);
|
var key = Slot.packSlotKey(0, CLUE_RIGHT);
|
||||||
var lo = (1L << OFF_0_1) | (1L << OFF_0_2) | (1L << OFF_0_3) | (1L << OFF_0_4);
|
var lo = (1L << OFF_0_1) | (1L << OFF_0_2) | (1L << OFF_0_3) | (1L << OFF_0_4);
|
||||||
clueMap[key] = TEST;
|
clueMap[key] = TEST;
|
||||||
assertTrue(placeWord(grid.grid(), key, lo, 0L, TEST));
|
assertTrue(placeWord(grid.grid(), grid.grid().g, key, lo, 0L, TEST));
|
||||||
|
|
||||||
var fillResult = new FillResult(true, grid, clueMap, new FillStats(0, 0, 0, 0));
|
var fillResult = new FillResult(true, grid, clueMap, new FillStats(0, 0, 0, 0));
|
||||||
var puzzleResult = new PuzzleResult(new Clued(clues), fillResult);
|
var puzzleResult = new PuzzleResult(new Clued(clues), fillResult);
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ import static puzzle.SwedishGeneratorTest.OFF_0_2;
|
|||||||
|
|
||||||
public class MainTest {
|
public class MainTest {
|
||||||
|
|
||||||
|
|
||||||
static final Opts opts = new Main.Opts() {{
|
static final Opts opts = new Main.Opts() {{
|
||||||
this.seed = 12348;
|
this.seed = 12348;
|
||||||
this.clueSize = 4;
|
this.clueSize = 4;
|
||||||
@@ -44,8 +43,8 @@ public class MainTest {
|
|||||||
val key = Slot.packSlotKey(OFF_0_0, CLUE_RIGHT);
|
val key = Slot.packSlotKey(OFF_0_0, CLUE_RIGHT);
|
||||||
clues.setClue(OFF_0_0, CLUE_RIGHT);
|
clues.setClue(OFF_0_0, CLUE_RIGHT);
|
||||||
var grid = new Gridded(clues.toGrid());
|
var grid = new Gridded(clues.toGrid());
|
||||||
|
val g = grid.grid().g;
|
||||||
placeWord(grid.grid(), key, (1L << OFF_0_1) | (1L << OFF_0_2), 0, AB);
|
placeWord(grid.grid(), g, key, (1L << OFF_0_1) | (1L << OFF_0_2), 0, AB);
|
||||||
|
|
||||||
var slots = extractSlots(clues, dict.index());
|
var slots = extractSlots(clues, dict.index());
|
||||||
assertEquals(1, slots.length);
|
assertEquals(1, slots.length);
|
||||||
@@ -95,7 +94,7 @@ public class MainTest {
|
|||||||
var grid = new Gridded(clues.toGrid());
|
var grid = new Gridded(clues.toGrid());
|
||||||
|
|
||||||
// Test set/get
|
// Test set/get
|
||||||
placeWord(grid.grid(), key, (1L << OFF_1_1) | (1L << OFF_0_1), 0, AZ);
|
placeWord(grid.grid(), grid.grid().g, key, (1L << OFF_1_1) | (1L << OFF_0_1), 0, AZ);
|
||||||
val arr = grid.stream(clues).collect(Collectors.toMap(LetterAt::index, LetterAt::letter));
|
val arr = grid.stream(clues).collect(Collectors.toMap(LetterAt::index, LetterAt::letter));
|
||||||
Assertions.assertEquals(LETTER_A, arr.get(OFF_1_1));
|
Assertions.assertEquals(LETTER_A, arr.get(OFF_1_1));
|
||||||
Assertions.assertEquals(LETTER_Z, arr.get(OFF_0_1));
|
Assertions.assertEquals(LETTER_Z, arr.get(OFF_0_1));
|
||||||
@@ -193,6 +192,8 @@ public class MainTest {
|
|||||||
System.out.println("[DEBUG_LOG] ClueMap Size: " + res.filled().wordCount());
|
System.out.println("[DEBUG_LOG] ClueMap Size: " + res.filled().wordCount());
|
||||||
System.out.println("[DEBUG_LOG] Grid:");
|
System.out.println("[DEBUG_LOG] Grid:");
|
||||||
System.out.println(res.filled().grid().renderHuman(res.clues().mask()));
|
System.out.println(res.filled().grid().renderHuman(res.clues().mask()));
|
||||||
|
System.out.println(res.filled().grid().gridToString(res.clues().mask()));
|
||||||
|
System.out.println(res.filled().grid().renderHuman(res.clues().mask()));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ public class SwedishGeneratorTest {
|
|||||||
var key = Slot.packSlotKey(OFF_0_0, CLUE_RIGHT);
|
var key = Slot.packSlotKey(OFF_0_0, CLUE_RIGHT);
|
||||||
val clues = Clues.createEmpty();
|
val clues = Clues.createEmpty();
|
||||||
clues.setClue(OFF_0_0, CLUE_RIGHT);
|
clues.setClue(OFF_0_0, CLUE_RIGHT);
|
||||||
placeWord(grid.grid(), key, (1L << OFF_0_1) | (1L << OFF_0_2) | (1L << OFF_0_3), 0L, ABC);
|
placeWord(grid.grid(), grid.grid().g, key, (1L << OFF_0_1) | (1L << OFF_0_2) | (1L << OFF_0_3), 0L, ABC);
|
||||||
val map = grid.stream(clues).collect(Collectors.toMap(LetterAt::index, LetterAt::letter));
|
val map = grid.stream(clues).collect(Collectors.toMap(LetterAt::index, LetterAt::letter));
|
||||||
assertEquals(LETTER_A, map.get(OFF_0_1));
|
assertEquals(LETTER_A, map.get(OFF_0_1));
|
||||||
assertEquals(LETTER_B, map.get(OFF_0_2));
|
assertEquals(LETTER_B, map.get(OFF_0_2));
|
||||||
@@ -100,10 +100,10 @@ public class SwedishGeneratorTest {
|
|||||||
@Test
|
@Test
|
||||||
void testPatternForSlotMixed() {
|
void testPatternForSlotMixed() {
|
||||||
var grid = createEmpty();
|
var grid = createEmpty();
|
||||||
placeWord(grid, Slot.packSlotKey(0, CLUE_RIGHT), 1L << OFF_0_0, 0, Lemma.from(0, "A"));
|
placeWord(grid, grid.g, Slot.packSlotKey(0, CLUE_RIGHT), 1L << OFF_0_0, 0, Lemma.from(0, "A"));
|
||||||
placeWord(grid, Slot.packSlotKey(0, CLUE_RIGHT), 1L << OFF_2_0, 0, Lemma.from(0, "C"));
|
placeWord(grid, grid.g, Slot.packSlotKey(0, CLUE_RIGHT), 1L << OFF_2_0, 0, Lemma.from(0, "C"));
|
||||||
var key = Slot.packSlotKey(OFF_1_0, CLUE_RIGHT);
|
var key = Slot.packSlotKey(OFF_1_0, CLUE_RIGHT);
|
||||||
var pattern = patternForSlot(grid, key, 7L, 0L);
|
var pattern = patternForSlot(grid.lo, grid.hi, grid.g, key, 7L, 0L);
|
||||||
assertEquals(1L | (55L << 16), pattern);
|
assertEquals(1L | (55L << 16), pattern);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,16 +111,16 @@ public class SwedishGeneratorTest {
|
|||||||
void testPatternForSlotAllDashes() {
|
void testPatternForSlotAllDashes() {
|
||||||
var grid = createEmpty();
|
var grid = createEmpty();
|
||||||
var key = Slot.packSlotKey(1 << Slot.BIT_FOR_DIR, CLUE_RIGHT);
|
var key = Slot.packSlotKey(1 << Slot.BIT_FOR_DIR, CLUE_RIGHT);
|
||||||
var pattern = patternForSlot(grid, key, 7L, 0L);
|
var pattern = patternForSlot(grid.lo, grid.hi, grid.g, key, 7L, 0L);
|
||||||
assertEquals(0L, pattern);
|
assertEquals(0L, pattern);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testPatternForSlotSingleLetter() {
|
void testPatternForSlotSingleLetter() {
|
||||||
var grid = createEmpty();
|
var grid = createEmpty();
|
||||||
placeWord(grid, Slot.packSlotKey(0, CLUE_RIGHT), 1L << OFF_0_0, 0, Lemma.from(0, "A"));
|
placeWord(grid, grid.g, Slot.packSlotKey(0, CLUE_RIGHT), 1L << OFF_0_0, 0, Lemma.from(0, "A"));
|
||||||
var key = Slot.packSlotKey(1, CLUE_RIGHT);
|
var key = Slot.packSlotKey(1, CLUE_RIGHT);
|
||||||
var pattern = patternForSlot(grid, key, 7L, 0L);
|
var pattern = patternForSlot(grid.lo, grid.hi, grid.g, key, 7L, 0L);
|
||||||
assertEquals(1L, pattern);
|
assertEquals(1L, pattern);
|
||||||
}
|
}
|
||||||
@Test
|
@Test
|
||||||
@@ -134,8 +134,8 @@ public class SwedishGeneratorTest {
|
|||||||
assertEquals(val1, rng2.nextU32());
|
assertEquals(val1, rng2.nextU32());
|
||||||
|
|
||||||
for (var i = 0; i < 100; i++) {
|
for (var i = 0; i < 100; i++) {
|
||||||
var r = rng.randint(5, 10);
|
var r = rng.randint(5);
|
||||||
assertTrue(r >= 5 && r <= 10);
|
assertTrue(r >= 0 && r <= 5);
|
||||||
var f = rng.nextFloat();
|
var f = rng.nextFloat();
|
||||||
assertTrue(f >= 0.0 && f <= 1.0);
|
assertTrue(f >= 0.0 && f <= 1.0);
|
||||||
}
|
}
|
||||||
@@ -144,7 +144,7 @@ public class SwedishGeneratorTest {
|
|||||||
@Test
|
@Test
|
||||||
void testGrid() {
|
void testGrid() {
|
||||||
var grid = new Gridded(createEmpty());
|
var grid = new Gridded(createEmpty());
|
||||||
placeWord(grid.grid(), Slot.packSlotKey(0, CLUE_RIGHT), 1L << OFF_0_0, 0, Lemma.from(0, "A"));
|
placeWord(grid.grid(), grid.grid().g, Slot.packSlotKey(0, CLUE_RIGHT), 1L << OFF_0_0, 0, Lemma.from(0, "A"));
|
||||||
val arr = grid.stream(Clues.createEmpty()).collect(Collectors.toMap(LetterAt::index, LetterAt::letter));
|
val arr = grid.stream(Clues.createEmpty()).collect(Collectors.toMap(LetterAt::index, LetterAt::letter));
|
||||||
assertEquals(1, arr.size());
|
assertEquals(1, arr.size());
|
||||||
assertEquals(LETTER_A, arr.get(OFF_0_0));
|
assertEquals(LETTER_A, arr.get(OFF_0_0));
|
||||||
@@ -290,7 +290,7 @@ public class SwedishGeneratorTest {
|
|||||||
var w1 = ABC;
|
var w1 = ABC;
|
||||||
|
|
||||||
// 1. Successful placement in empty grid
|
// 1. Successful placement in empty grid
|
||||||
assertTrue(placeWord(grid.grid(), key, lo, hi, w1));
|
assertTrue(placeWord(grid.grid(), grid.grid().g, key, lo, hi, w1));
|
||||||
var map = grid.stream(Clues.createEmpty()).collect(Collectors.toMap(LetterAt::index, LetterAt::letter));
|
var map = grid.stream(Clues.createEmpty()).collect(Collectors.toMap(LetterAt::index, LetterAt::letter));
|
||||||
assertEquals(3, map.size());
|
assertEquals(3, map.size());
|
||||||
assertEquals(LETTER_A, map.get(OFF_0_0));
|
assertEquals(LETTER_A, map.get(OFF_0_0));
|
||||||
@@ -298,9 +298,9 @@ public class SwedishGeneratorTest {
|
|||||||
assertEquals(LETTER_C, map.get(OFF_0_2));
|
assertEquals(LETTER_C, map.get(OFF_0_2));
|
||||||
|
|
||||||
// 2. Successful placement with partial overlap (same characters)
|
// 2. Successful placement with partial overlap (same characters)
|
||||||
assertTrue(placeWord(grid.grid(), key, lo, hi, w1));
|
assertTrue(placeWord(grid.grid(), grid.grid().g, key, lo, hi, w1));
|
||||||
// 3. Conflict: place "ABD" where "ABC" is
|
// 3. Conflict: place "ABD" where "ABC" is
|
||||||
assertFalse(placeWord(grid.grid(), key, lo, hi, ABD));
|
assertFalse(placeWord(grid.grid(), grid.grid().g, key, lo, hi, ABD));
|
||||||
// Verify grid is unchanged (still "ABC")
|
// Verify grid is unchanged (still "ABC")
|
||||||
map = grid.stream(Clues.createEmpty()).collect(Collectors.toMap(LetterAt::index, LetterAt::letter));
|
map = grid.stream(Clues.createEmpty()).collect(Collectors.toMap(LetterAt::index, LetterAt::letter));
|
||||||
assertEquals(3, map.size());
|
assertEquals(3, map.size());
|
||||||
@@ -310,8 +310,8 @@ public class SwedishGeneratorTest {
|
|||||||
|
|
||||||
// 4. Partial placement then conflict (rollback)
|
// 4. Partial placement then conflict (rollback)
|
||||||
grid = new Gridded(createEmpty());
|
grid = new Gridded(createEmpty());
|
||||||
placeWord(grid.grid(), Slot.packSlotKey(0, CLUE_RIGHT), 1L << OFF_0_2, 0, Lemma.from(0, "X")); // Conflict at the end
|
placeWord(grid.grid(), grid.grid().g, Slot.packSlotKey(0, CLUE_RIGHT), 1L << OFF_0_2, 0, Lemma.from(0, "X")); // Conflict at the end
|
||||||
assertFalse(placeWord(grid.grid(), key, lo, hi, w1));
|
assertFalse(placeWord(grid.grid(), grid.grid().g, key, lo, hi, w1));
|
||||||
map = grid.stream(Clues.createEmpty()).collect(Collectors.toMap(LetterAt::index, LetterAt::letter));
|
map = grid.stream(Clues.createEmpty()).collect(Collectors.toMap(LetterAt::index, LetterAt::letter));
|
||||||
assertEquals(1, map.size());
|
assertEquals(1, map.size());
|
||||||
assertEquals(LETTER_X, map.get(OFF_0_2));
|
assertEquals(LETTER_X, map.get(OFF_0_2));
|
||||||
@@ -326,7 +326,7 @@ public class SwedishGeneratorTest {
|
|||||||
var w = AZ;
|
var w = AZ;
|
||||||
val low = grid.grid().lo;
|
val low = grid.grid().lo;
|
||||||
val top = grid.grid().hi;
|
val top = grid.grid().hi;
|
||||||
var placed = placeWord(grid.grid(), key, lo, 0L, w);
|
var placed = placeWord(grid.grid(), grid.grid().g, key, lo, 0L, w);
|
||||||
assertTrue(placed);
|
assertTrue(placed);
|
||||||
var map = grid.stream(Clues.createEmpty()).collect(Collectors.toMap(LetterAt::index, LetterAt::letter));
|
var map = grid.stream(Clues.createEmpty()).collect(Collectors.toMap(LetterAt::index, LetterAt::letter));
|
||||||
assertEquals(2, map.size());
|
assertEquals(2, map.size());
|
||||||
|
|||||||
Reference in New Issue
Block a user