From 84ba4c9c63ea859a10f983051fde0e3a03078a6a Mon Sep 17 00:00:00 2001 From: mike Date: Mon, 12 Jan 2026 00:47:38 +0100 Subject: [PATCH] introduce bitloops --- src/main/java/puzzle/CsvIndexService.java | 33 ++-- src/main/java/puzzle/Export.java | 32 ++- src/main/java/puzzle/Main.java | 4 +- src/main/java/puzzle/SwedishGenerator.java | 182 +++++++++--------- src/test/java/puzzle/ExportFormatTest.java | 2 +- src/test/java/puzzle/MainTest.java | 3 +- .../java/puzzle/SwedishGeneratorTest.java | 51 ++--- 7 files changed, 164 insertions(+), 143 deletions(-) diff --git a/src/main/java/puzzle/CsvIndexService.java b/src/main/java/puzzle/CsvIndexService.java index 44dcddd..6e7fee6 100644 --- a/src/main/java/puzzle/CsvIndexService.java +++ b/src/main/java/puzzle/CsvIndexService.java @@ -8,19 +8,18 @@ import java.nio.channels.FileChannel; import java.nio.charset.StandardCharsets; import java.nio.file.*; import java.util.Arrays; -import java.util.Locale; import java.util.function.Consumer; public final class CsvIndexService implements Closeable { - static final ScopedValue SC = ScopedValue.newInstance(); - static final Gson GSON = new Gson(); - private static final int MAGIC = 0x4C494458; // "LIDX" - private static final int VERSION = 1; - - private final Path csvPath; - private final Path idxPath; + static final ScopedValue SC = ScopedValue.newInstance(); + static final Gson GSON = new Gson(); + private static final int MAGIC = 0x4C494458; // "LIDX" + private static final int VERSION = 1; + static int SIMPEL_IDX = 3; + private final Path csvPath; + private final Path idxPath; private volatile long[] offsets; // lazy private volatile FileChannel csvChannel; // open once @@ -30,7 +29,10 @@ public final class CsvIndexService this.csvPath = csvPath; this.idxPath = idxPath; } - + public static int lineToSimpel(String line) { + var parts = line.split(",", 5); + return Integer.parseInt(parts[SIMPEL_IDX].trim()); + } public static String[] lineToClue(String line) { if (line.isBlank()) throw new RuntimeException("Empty line"); var parts = line.split(",", 5); @@ -51,16 +53,23 @@ public final class CsvIndexService throw new RuntimeException("Invalid word:" + line); } - // CSV has level 1-10. llmScores use 10-level. int score = Integer.parseInt(parts[2].trim()); if (score < 1) { if (Main.VERBOSE) System.err.println("Word too complex: " + line); return; } - int simpel = Integer.parseInt(parts[3].trim()); - ok.accept(new Lemma(id, word, simpel)); + ok.accept(new Lemma(id, word)); } + public static int simpel(int index) { + try { + if (SC.isBound()) + return lineToSimpel(SC.get().getLine(index)); + return -1; + } catch (Exception e) { + throw new RuntimeException("Failed to get clues for index " + index, e); + } + } public static String[] clues(int index) { try { if (SC.isBound()) diff --git a/src/main/java/puzzle/Export.java b/src/main/java/puzzle/Export.java index 9f32996..71ecdc1 100644 --- a/src/main/java/puzzle/Export.java +++ b/src/main/java/puzzle/Export.java @@ -7,7 +7,6 @@ import puzzle.SwedishGenerator.Grid; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; -import static java.nio.charset.StandardCharsets.*; import static puzzle.SwedishGenerator.R; import static puzzle.SwedishGenerator.Lemma; import static puzzle.SwedishGenerator.Slot; @@ -82,10 +81,10 @@ 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(Lemma 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'; + static final char VERTICAL = 'v'; } public record Rewards(int coins, int stars, int hints) { } @@ -109,9 +108,9 @@ public record Export() { for (int i = 0, len = s.len(); i < len; i++) cells[i] = s.pos(i); char direction; - var isReversed = false; - var startRow = Grid.r(cells[0]); - var startCol = Grid.c(cells[0]); + var isReversed = false; + var startRow = Grid.r(cells[0]); + var startCol = Grid.c(cells[0]); if (d == 2) { // right -> horizontal direction = Placed.HORIZONTAL; } else if (d == 3 || d == 5) { // down or down-bent -> vertical @@ -215,4 +214,25 @@ public record Export() { return new ExportedPuzzle(gridv2, wordsOut, difficulty, rewards); } } + + static record DictEntryDTO(ArrayList words, IntListDTO[][] pos) { + + public DictEntryDTO(int L) { + this(new ArrayList<>(), new IntListDTO[L][26]); + for (var i = 0; i < L; i++) for (var j = 0; j < 26; j++) pos[i][j] = new IntListDTO(); + } + } + + static final class IntListDTO { + + int[] a = new int[8]; + int n = 0; + void add(int v) { + if (n >= a.length) a = Arrays.copyOf(a, a.length * 2); + a[n++] = v; + } + int size() { return n; } + int[] data() { return a; } + } + } diff --git a/src/main/java/puzzle/Main.java b/src/main/java/puzzle/Main.java index 808ec2c..febd3d2 100644 --- a/src/main/java/puzzle/Main.java +++ b/src/main/java/puzzle/Main.java @@ -74,8 +74,6 @@ public class Main { section("Settings"); printSettings(opts); - var csv = Paths.get("nl_score_hints_v3.csv"); - var idx = Paths.get("nl_score_hints_v3.idx"); var res = generatePuzzle(opts); if (res == null) { @@ -86,6 +84,7 @@ public class Main { } section("Result"); + res.filled().calcSimpel(); info(String.format(Locale.ROOT, "simplicity : %.2f", res.filled().stats().simplicity)); section("Mask"); @@ -353,6 +352,7 @@ public class Main { TOTAL_NODES.addAndGet(filled.stats().nodes); TOTAL_BACKTRACKS.addAndGet(filled.stats().backtracks); if (filled.ok()) { + filled.calcSimpel(); TOTAL_SUCCESS.incrementAndGet(); TOTAL_SIMPLICITY.addAndGet((long) (filled.stats().simplicity * 100)); } diff --git a/src/main/java/puzzle/SwedishGenerator.java b/src/main/java/puzzle/SwedishGenerator.java index 0bc6b46..052fc19 100644 --- a/src/main/java/puzzle/SwedishGenerator.java +++ b/src/main/java/puzzle/SwedishGenerator.java @@ -8,10 +8,10 @@ import precomp.Neighbors9x8.nbrs_8; import precomp.Neighbors9x8.rci; import puzzle.Export.Bit; import puzzle.Export.Bit1029; +import puzzle.Export.DictEntryDTO; import puzzle.Export.Gridded; import puzzle.Export.Strings; import java.io.IOException; -import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; @@ -37,6 +37,8 @@ public record SwedishGenerator(Rng rng) { public CandidateInfo(int n) { this(null, n); } } + static final CandidateInfo[] CANDIDATES = IntStream.range(0, 10192 << 2).mapToObj(CandidateInfo::new).toArray(CandidateInfo[]::new); + //@formatter:off @FunctionalInterface interface SlotVisitor { void visit(int key, long packedPos, int len); } //@formatter:on @@ -67,6 +69,9 @@ public record SwedishGenerator(Rng rng) { static int clamp(int x, int a, int b) { return Math.max(a, Math.min(b, x)); } record Pick(Slot slot, CandidateInfo info, boolean done) { } + static final byte B0 = (byte) 0; + static final byte B64 = (byte) 64; + static final byte B48 = (byte) 48; // Directions for '1'..'6' static final nbrs_16[] OFFSETS = Neighbors9x8.OFFSETS; static final nbrs_16[] OFFSETS_FOUR = Neighbors9x8.OFFSETS_FOUR; @@ -75,6 +80,7 @@ public record SwedishGenerator(Rng rng) { static final rci[] IT = Neighbors9x8.IT; static final long[] INBR8_PACKEDT = Neighbors9x8.NBR8_PACKED; static final int[][] MUTATE_RI = new int[SIZE][625]; + static final long[] NBR8_PACKED = Neighbors9x8.NBR8_PACKED; static { for (int i = 0; i < SIZE; i++) { @@ -87,28 +93,6 @@ public record SwedishGenerator(Rng rng) { clamp(Grid.c(i) + dc1 + dc2, 0, C - 1)); } } - /*static { - Rng trng = new Rng(1); - for (int i = 0; i < SIZE; i++) { - int[] neighborhood = new int[625]; - int k = 0; - for (int dr1 = -2; dr1 <= 2; dr1++) - for (int dr2 = -2; dr2 <= 2; dr2++) - for (int dc1 = -2; dc1 <= 2; dc1++) - for (int dc2 = -2; dc2 <= 2; dc2++) - neighborhood[k++] = Grid.offset(clamp(Grid.r(i) + dr1 + dr2, 0, R - 1), - clamp(Grid.c(i) + dc1 + dc2, 0, C - 1)); - for (k = 0; k < 625; k++) { - long packed = 0; - for (int s = 0; s < 4; s++) { - int ri = neighborhood[trng.randint(0, 624)]; - int d = trng.randint(1, 4); - packed |= ((long) ri | ((long) d << 8)) << (s << 4); - } - MUTATE_RI[i][k] = packed; - } - } - }*/ static final Pick PICK_DONE = new Pick(null, null, true); static final Pick PICK_NOT_DONE = new Pick(null, null, false); @@ -127,9 +111,9 @@ public record SwedishGenerator(Rng rng) { HashMap clueMap, FillStats stats) { - public FillResult { + public void calcSimpel() { if (ok) { - clueMap.forEach((k, v) -> stats.simplicity += v.simpel); + clueMap.forEach((k, v) -> stats.simplicity += v.simpel()); stats.simplicity = clueMap.isEmpty() ? 0 : stats.simplicity / clueMap.size(); } } @@ -247,9 +231,7 @@ public record SwedishGenerator(Rng rng) { } return true; } - static final byte B0 = (byte) 0; - static final byte B64 = (byte) 64; - static final byte B48 = (byte) 48; + static boolean isLetter(byte b) { return (b & B64) != B0; } public boolean isLetterSet(int idx) { return isLetter(g[idx]); } static boolean notDigit(byte b) { return (b & B48) != B48; } @@ -268,27 +250,11 @@ public record SwedishGenerator(Rng rng) { } } - static final class IntList { - - int[] a = new int[8]; - int n = 0; - void add(int v) { - if (n >= a.length) a = Arrays.copyOf(a, a.length * 2); - a[n++] = v; - } - int size() { return n; } - int[] data() { return a; } - } + static final record IntList(int[] data, int size) { } - static record DictEntry(ArrayList words, IntList[][] pos) { - - public DictEntry(int L) { - this(new ArrayList<>(), new IntList[L][26]); - for (var i = 0; i < L; i++) for (var j = 0; j < 26; j++) pos[i][j] = new IntList(); - } - } + static record DictEntry(Lemma[] words, IntList[][] pos) { } - public static record Lemma(int index, long word, byte len, short simpel) { + public static record Lemma(int index, long word, byte len) { static int LEMMA_COUNTER = 0; static long pack(byte[] b) { @@ -296,15 +262,17 @@ public record SwedishGenerator(Rng rng) { 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 (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 Lemma(int index, String word) { this(index, pack(word.getBytes(US_ASCII)), (byte) word.length()); } + public Lemma(String word) { this(LEMMA_COUNTER++, word); } + byte byteAt(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 index; } + @Override public boolean equals(Object o) { return (o == this) || (o instanceof Lemma l && l.index == index); } + String[] clue() { return CsvIndexService.clues(index); } + int simpel() { return CsvIndexService.simpel(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); + for (var i = 0; i < len; i++) b[i] = (byte) ((word >>> (i * 5)) & 0b11111 | B64); return new String(b, US_ASCII); } } @@ -314,23 +282,29 @@ public record SwedishGenerator(Rng rng) { int length) { public Dict(Lemma[] wordz) { - var index = new DictEntry[MAX_WORD_LENGTH_PLUS_ONE]; - Arrays.setAll(index, i -> new DictEntry(i)); + var index = new DictEntryDTO[MAX_WORD_LENGTH_PLUS_ONE]; + Arrays.setAll(index, i -> new DictEntryDTO(i)); for (var lemma : wordz) { var L = lemma.len; var entry = index[L]; - var idx = entry.words.size(); - entry.words.add(lemma); + var idx = entry.words().size(); + entry.words().add(lemma); for (var i = 0; i < L; i++) { - var letter = lemma.byteAt(i) - 'A'; + var letter = lemma.intAt(i) - 1; if (letter < 0 || letter >= 26) throw new RuntimeException("Illegal letter: " + letter + " in word " + lemma); - entry.pos[i][letter].add(idx); + 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); - this(index, Arrays.stream(index).mapToInt(i -> i.words.size()).sum()); + 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 -> new DictEntry(i.words().toArray(Lemma[]::new), + Arrays.stream(i.pos()) + .map(ii -> Arrays.stream(ii).map(dto -> new IntList(dto.data(), dto.size())) + .toArray(IntList[]::new)) + .toArray(IntList[][]::new))) + .toArray(DictEntry[]::new), + Arrays.stream(index).mapToInt(i -> i.words().size()).sum()); } static Dict loadDict(String wordsPath) { try { @@ -394,12 +368,12 @@ public record SwedishGenerator(Rng rng) { private static void processSlot(Grid grid, SlotVisitor visitor, int idx) { var d = grid.digitAt(idx); var packed = OFFSETS[d].path()[idx]; - long packedPos = 0; + long packedPos = 0L; int k = 0; - for (int n = (int) (packed >>> 56), iidx; k < n && k < MAX_WORD_LENGTH; k++) { - iidx = (int) ((packed >>> (k * 7)) & 0x7F); + for (long n = (packed >>> 56), offset = 0L, iidx; k < n; k++, offset += 7L) { + iidx = ((packed >>> offset) & 0x7FL); if (grid.isClue(iidx)) break; - packedPos |= (long) iidx << (k * 7); + packedPos |= iidx << offset; } if (k > 0) { visitor.visit((idx << 4) | d, packedPos, k); @@ -412,52 +386,68 @@ public record SwedishGenerator(Rng rng) { return slots; } + static long fitting(Grid grid, int clueIdx, int[] covH, int[] covV) { + var d = grid.digitAt(clueIdx); + var nbrs16 = OFFSETS[d]; + long packed = nbrs16.path()[clueIdx]; + int n = (int) (packed >>> 56) * 7, k, idx; + var horiz = Slot.horiz(d) ? covH : covV; + for (k = 0; k < n && k < MAX_WORD_LENGTH7; k += 7) { + idx = (int) ((packed >>> (k)) & 0x7F); + if (grid.isClue(idx)) break; + horiz[idx] += 1; + } + if (k > 0) { + if (k < MIN_LEN7) return 8001L; + return 1L; + } + return 0L; + } + long maskFitness(Grid grid) { var ctx = CTX.get(); var covH = ctx.covH; var covV = ctx.covV; Arrays.fill(covH, 0, SIZE, 0); Arrays.fill(covV, 0, SIZE, 0); - - long lo_cl = grid.lo, hi_cl = grid.hi; - long penalty = (((long) Math.abs(grid.clueCount() - TARGET_CLUES)) << 3); - boolean hasSlots = false; - + int clueIdx; + long lo_cl = grid.lo, hi_cl = grid.hi; + long penalty = 0L; for (int i = 0; i < 65; i += 64) { for (long bits = (i == 0 ? lo_cl : hi_cl); bits != X; bits &= bits - 1) { - int clueIdx = i + Long.numberOfTrailingZeros(bits); - var d = grid.digitAt(clueIdx); - var nbrs16 = OFFSETS[d]; - long packed = nbrs16.path()[clueIdx]; - int n = (int) (packed >>> 56) * 7, k, idx; - var horiz = Slot.horiz(d) ? covH : covV; + clueIdx = i + Long.numberOfTrailingZeros(bits); + var d = grid.digitAt(clueIdx); + var nbrs16 = OFFSETS[d]; + long packed = nbrs16.path()[clueIdx]; + int n = (int) (packed >>> 56) * 7, k, idx; + var horiz = Slot.horiz(d) ? covH : covV; for (k = 0; k < n && k < MAX_WORD_LENGTH7; k += 7) { idx = (int) ((packed >>> (k)) & 0x7F); if (grid.isClue(idx)) break; horiz[idx] += 1; } if (k > 0) { - hasSlots = true; if (k < MIN_LEN7) penalty += 8000; + penalty |= 1; } } } - if (!hasSlots) return 1_000_000_000L; - + if ((penalty & 1) == 0) return 1_000_000_000L; + penalty = (penalty & ~3L) + (((long) Math.abs(grid.clueCount() - TARGET_CLUES)) << 3); var seen = ctx.seen; var stack = ctx.stack; seen.clear(); for (int i = 0; i < 65; i += 64) { for (long bits = (i == 0 ? lo_cl : hi_cl); bits != X; bits &= bits - 1) { - int clueIdx = i + Long.numberOfTrailingZeros(bits); + clueIdx = i + Long.numberOfTrailingZeros(bits); if (seen.get(clueIdx)) continue; int size = 0; stack[0] = clueIdx; seen.set(clueIdx); for (int sp = 1; sp > 0; size++) { - long packed = Neighbors9x8.NBR8_PACKED[stack[--sp]]; + long packed = NBR8_PACKED[stack[--sp]]; for (int k = 0, n = (int) (packed >>> 56) * 7; k < n; k += 7) { int nidx = (int) ((packed >>> k) & 0x7F); if (seen.get(nidx) || grid.notClue(nidx)) continue; @@ -472,11 +462,11 @@ public record SwedishGenerator(Rng rng) { for (int i = 0; i < 65; i += 64) { long bits = (i == 0 ? ~lo_cl : (~hi_cl & 0xFFL)); for (; bits != X; bits &= bits - 1) { - int idx = i + Long.numberOfTrailingZeros(bits); - var rci = IT[idx]; + clueIdx = i + Long.numberOfTrailingZeros(bits); + var rci = IT[clueIdx]; if ((4 - rci.nbrCount()) + Long.bitCount(rci.n1() & lo_cl) + Long.bitCount(rci.n2() & hi_cl) >= 3) penalty += 400; - var h = covH[idx]; - var v = covV[idx]; + var h = covH[clueIdx]; + var v = covV[clueIdx]; if (h == 0 && v == 0) penalty += 1500; else if (h > 0 && v > 0) { /* ok */ } else if (h + v == 1) penalty += 200; else penalty += 600; @@ -650,7 +640,7 @@ 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; @@ -665,7 +655,7 @@ public record SwedishGenerator(Rng rng) { } if (listCount == 0) { - return CANDIDATES[entry.words.size()]; + return CANDIDATES[entry.words.length]; } // Sort constraints by size to optimize intersection @@ -801,26 +791,26 @@ public record SwedishGenerator(Rng rng) { double r = rng.nextFloat(); int idxInArray = (int) (r * r * r * L); var idx = idxs[idxInArray]; - var w = entry.words.get(idx); + var w = entry.words[idx]; - if (used.get(w.index())) continue; + if (used.get(w.index)) continue; if (!placeWord(grid, s, w, ctx.undo, depth)) continue; - used.set(w.index()); + used.set(w.index); assigned.put(k, w); if (backtrack(depth + 1)) return true; assigned.remove(k); - used.clear(w.index()); + used.clear(w.index); s.undoPlace(grid, ctx.undo[depth]); } stats.backtracks++; return false; } - var N = entry.words.size(); + var N = entry.words.length; if (N == 0) { stats.backtracks++; return false; @@ -830,13 +820,13 @@ public record SwedishGenerator(Rng rng) { for (var t = 0; t < tries; t++) { double r = rng.nextFloat(); int idxInArray = (int) (r * r * r * N); - var w = entry.words.get(idxInArray); + var w = entry.words[idxInArray]; - if (used.get(w.index())) continue; + if (used.get(w.index)) continue; if (!placeWord(grid, s, w, ctx.undo, depth)) continue; - used.set(w.index()); + used.set(w.index); assigned.put(k, w); if (backtrack(depth + 1)) return true; diff --git a/src/test/java/puzzle/ExportFormatTest.java b/src/test/java/puzzle/ExportFormatTest.java index dd6e37b..66b76db 100644 --- a/src/test/java/puzzle/ExportFormatTest.java +++ b/src/test/java/puzzle/ExportFormatTest.java @@ -31,7 +31,7 @@ public class ExportFormatTest { var clueMap = new HashMap(); // key = (cellIndex << 4) | direction var key = (0 << 4) | 2; - var lemma = new Lemma("TEST", 1); + var lemma = new Lemma("TEST"); clueMap.put(key, lemma); // Manually fill the grid letters for "TEST" at (0,1), (0,2), (0,3), (0,4) diff --git a/src/test/java/puzzle/MainTest.java b/src/test/java/puzzle/MainTest.java index ad01396..1de566a 100644 --- a/src/test/java/puzzle/MainTest.java +++ b/src/test/java/puzzle/MainTest.java @@ -167,8 +167,9 @@ public class MainTest { // Regression baseline for seed search starting at 12347, pop 4, gens 20 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.assertEquals(Lemma.pack(new byte[]{ 'I', 'E', 'M', 'A', 'N', 'D', 'S' }), res.filled().clueMap().get(515).word()); + Assertions.assertEquals(648985643903632391L, res.filled().grid().grid().lo); + Assertions.assertEquals(140L, res.filled().grid().grid().hi); } @Test public void testIsLetterA() { diff --git a/src/test/java/puzzle/SwedishGeneratorTest.java b/src/test/java/puzzle/SwedishGeneratorTest.java index cd374b2..81c40d6 100644 --- a/src/test/java/puzzle/SwedishGeneratorTest.java +++ b/src/test/java/puzzle/SwedishGeneratorTest.java @@ -2,6 +2,7 @@ package puzzle; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import puzzle.Export.IntListDTO; import java.nio.charset.StandardCharsets; import java.util.Arrays; @@ -91,7 +92,7 @@ public class SwedishGeneratorTest { @Test void testIntList() { - var list = new IntList(); + var list = new IntListDTO(); assertEquals(0, list.size()); for (var i = 0; i < 10; i++) { list.add(i); @@ -103,27 +104,27 @@ public class SwedishGeneratorTest { @Test void testLemmaAndDict() { - var l2a = new Lemma("IN", 1); - var l4a = new Lemma("INER", 1); - var l6a = new Lemma("INEREN", 1); - var l7a = new Lemma("INERENA", 1); - var l8a = new Lemma("INERENAE", 1); + var l2a = new Lemma("IN"); + var l4a = new Lemma("INER"); + var l6a = new Lemma("INEREN"); + var l7a = new Lemma("INERENA"); + var l8a = new Lemma("INERENAE"); - var l1 = new Lemma("APPLE", 5); + var l1 = new Lemma("APPLE"); 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)); + assertEquals(1, l1.intAt(0)); - var l2 = new Lemma("AXE", 2); + var l2 = new Lemma("AXE"); var dict = new Dict(new Lemma[]{ l1, l2, l2a, l4a, l6a, l7a, l8a }); - assertEquals(1, dict.index()[3].words().size()); - assertEquals(1, dict.index()[5].words().size()); + assertEquals(1, dict.index()[3].words().length); + assertEquals(1, dict.index()[5].words().length); var entry3 = dict.index()[3]; - assertEquals(1, entry3.words().size()); - assertEquals(Lemma.pack("AXE".getBytes(StandardCharsets.US_ASCII)), entry3.words().getFirst().word()); + assertEquals(1, entry3.words().length); + assertEquals(Lemma.pack("AXE".getBytes(StandardCharsets.US_ASCII)), entry3.words()[0].word()); // Check pos indexing // AXE: A at 0, X at 1, E at 2 @@ -179,15 +180,15 @@ public class SwedishGeneratorTest { @Test void testCandidateInfoForPattern() { - var l0 = new Lemma("IN", 1); - var l3a = new Lemma("INE", 1); - var l4a = new Lemma("INER", 1); - var l6a = new Lemma("INEREN", 1); - var l7a = new Lemma("INERENA", 1); - var l8a = new Lemma("INERENAE", 1); - var l1 = new Lemma("APPLE", 1); - var l2 = new Lemma("APPLY", 1); - var l3 = new Lemma("BANAN", 1); + var l0 = new Lemma("IN"); + var l3a = new Lemma("INE"); + var l4a = new Lemma("INER"); + var l6a = new Lemma("INEREN"); + var l7a = new Lemma("INERENA"); + var l8a = new Lemma("INERENAE"); + var l1 = new Lemma("APPLE"); + var l2 = new Lemma("APPLY"); + var l3 = new Lemma("BANAN"); var dict = new Dict(new Lemma[]{ l0, l1, l2, l3, l3a, l4a, l6a, l7a, l8a }); // Pattern "APP--" for length 5 @@ -274,7 +275,7 @@ public class SwedishGeneratorTest { // r(i) and c(i) are used by placeWord. var packedPos = ((long) Grid.offset(0, 0)) | (((long) Grid.offset(0, 1)) << 7) | (((long) Grid.offset(0, 2)) << 14); var s = Slot.from(0, packedPos, 3); - var w1 = new Lemma("ABC", 1); + var w1 = new Lemma("ABC"); var undoBuffer = new int[10]; // 1. Successful placement in empty grid @@ -289,7 +290,7 @@ public class SwedishGeneratorTest { assertEquals(0L, undoBuffer[1]); // 0 new characters placed // 3. Conflict: place "ABD" where "ABC" is - var w2 = new Lemma("ABD", 1); + var w2 = new Lemma("ABD"); assertFalse(placeWord(grid, s, w2, undoBuffer, 2)); // Verify grid is unchanged (still "ABC") assertEquals('A', grid.byteAt(Grid.offset(0, 0))); @@ -312,7 +313,7 @@ public class SwedishGeneratorTest { // Slot at 0,1 length 2 var packedPos = ((long) Grid.offset(0, 1)) | (((long) Grid.offset(0, 2)) << 7); var s = Slot.from((0 << 8) | (1 << 4) | 2, packedPos, 2); - var w = new Lemma("AZ", 1); + var w = new Lemma("AZ"); var undoBuffer = new int[10]; var placed = placeWord(grid, s, w, undoBuffer, 0);