diff --git a/src/main/java/puzzle/Export.java b/src/main/java/puzzle/Export.java index 56a8ab0..d6ac995 100644 --- a/src/main/java/puzzle/Export.java +++ b/src/main/java/puzzle/Export.java @@ -58,7 +58,11 @@ public record Export() { } record Gridded(@Delegate Grid grid) { - + public boolean lisLetterAt(int pos) { + if ((pos & 64) == 0) + return lisLetterAtLo(pos); + return lisLetterAtHi(pos); + } public static IntStream walk(byte base, long lo, long hi) { if (Slot.increasing(base)) { return IntStream.concat( @@ -119,7 +123,7 @@ public record Export() { var offset = Grid.offset(r, c); if (clues.isClue(offset)) sb.append((char) (48 | clues.digitAt(offset))); - else if (grid.lisLetterAt(offset)) + else if (lisLetterAt(offset)) sb.append((char) (64 | grid.letter32At(offset))); else sb.append(' '); @@ -144,7 +148,7 @@ public record Export() { var offset = Grid.offset(r, c); if (clues.isClue(offset)) { sb.append(clueChar.replace(new Cell(grid, clues, offset, clues.digitAt(offset)))); - } else if (grid.lisLetterAt(offset)) { + } else if (lisLetterAt(offset)) { sb.append(NOT_CLUE_NOT_LETTER_TO(grid.letter32At(offset))); } else { sb.append(emptyFallback); @@ -192,7 +196,6 @@ public record Export() { public record PuzzleResult(Clued mask, FillResult filled) { - boolean inBounds(int idx) { return idx >= 0 && idx < SwedishGenerator.SIZE; } Placed extractPlacedFromSlot(Slot s, long lemma) { return new Placed(lemma, s.key(), s.walk().toArray()); } public ExportedPuzzle exportFormatFromFilled(int difficulty, Rewards rewards) { var g = filled().grid(); @@ -236,7 +239,6 @@ public record Export() { var letterAt = new HashMap(); for (var p : placed) { for (var c : p.cells) { - if (!inBounds(c)) throw new RuntimeException(); if (mask.notClue(c) && g.lisLetterAt(c)) { letterAt.put(c, (char) (64 | g.letter32At(c))); } diff --git a/src/main/java/puzzle/SwedishGenerator.java b/src/main/java/puzzle/SwedishGenerator.java index 15273c6..656e4fd 100644 --- a/src/main/java/puzzle/SwedishGenerator.java +++ b/src/main/java/puzzle/SwedishGenerator.java @@ -277,12 +277,6 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) { static int offset(int r, int c) { return r | (c << 3); } /// the pos will never target a clue public byte letter32At(int pos) { return g[pos]; } - public boolean lisLetterAt(int pos) { - if ((pos & 64) == 0) - return lisLetterAtLo(pos); - return lisLetterAtHi(pos); - } - public boolean lisLetterAtLo(int pos) { return (lo & (1L << pos)) != X; } public boolean lisLetterAtHi(int pos) { return (hi & (1L << (pos & 63))) != X; } void setLetterLo(int idx, byte ch) { @@ -387,11 +381,11 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) { public static boolean increasing(int dir) { return (dir & 2) == 0; } public IntStream walk() { return Gridded.walk((byte) key, lo, hi); } public static boolean horiz(int d) { return (d & 1) != 0; } - public static int packSlotDir(int idx, int d) { return (idx << BIT_FOR_DIR) | d; } + public static int packSlotKey(int idx, int d) { return (idx << BIT_FOR_DIR) | d; } } private static void processSlot(Clues grid, SlotVisitor visitor, int idx) { - int key = Slot.packSlotDir(idx, grid.digitAt(idx)); // 0..3 + int key = Slot.packSlotKey(idx, grid.digitAt(idx)); // 0..3 long rayLo = PATH_LO[key]; long rayHi = PATH_HI[key]; @@ -451,7 +445,7 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) { int clueIdx = Long.numberOfTrailingZeros(lsb); int v = (grid.vlo & lsb) != 0 ? 1 : 0; int r = (grid.rlo & lsb) != 0 ? 1 : 0; - int key = Slot.packSlotDir(clueIdx, (r << 1) | v); + int key = Slot.packSlotKey(clueIdx, (r << 1) | v); long rLo = PATH_LO[key], rHi = PATH_HI[key]; long hLo = rLo & lo_cl, hHi = rHi & hi_cl; if (Slot.increasing(key)) { @@ -488,7 +482,7 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) { int clueIdx = Long.numberOfTrailingZeros(lsb); int v = (grid.vhi & lsb) != 0 ? 1 : 0; int r = (grid.rhi & lsb) != 0 ? 1 : 0; - int key = Slot.packSlotDir(64 | clueIdx, (r << 1) | v); + int key = Slot.packSlotKey(64 | clueIdx, (r << 1) | v); long rLo = PATH_LO[key], rHi = PATH_HI[key]; long hLo = rLo & lo_cl, hHi = rHi & hi_cl; if (Slot.increasing(key)) { @@ -612,7 +606,7 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) { idx = rng.randint(0, SIZE_MIN_1); if (g.isClue(idx)) continue; var d_idx = rng.randint2bitByte(); - if (g.hasRoomForClue(OFFSETS_D_IDX[Slot.packSlotDir(idx, d_idx)])) { + if (g.hasRoomForClue(OFFSETS_D_IDX[Slot.packSlotKey(idx, d_idx)])) { g.setClue(idx, d_idx); placed++; } @@ -626,7 +620,7 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) { ri = bytes[rng.randint(0, 624)]; if (!c.clueless(ri)) { var d_idx = rng.randint2bitByte(); - if (c.hasRoomForClue(OFFSETS_D_IDX[Slot.packSlotDir(ri, d_idx)])) c.setClue(ri, d_idx); + if (c.hasRoomForClue(OFFSETS_D_IDX[Slot.packSlotKey(ri, d_idx)])) c.setClue(ri, d_idx); } } return c; @@ -657,7 +651,7 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) { for (var hi = out.hi; hi != X; hi &= hi - 1L) clearClues(out, 64 | Long.numberOfTrailingZeros(hi)); return out; } - public static void clearClues(Clues out, int idx) { if (!out.hasRoomForClue(OFFSETS_D_IDX[Slot.packSlotDir(idx, out.digitAt(idx))])) out.clearClue(idx); } + public static void clearClues(Clues out, int idx) { if (!out.hasRoomForClue(OFFSETS_D_IDX[Slot.packSlotKey(idx, out.digitAt(idx))])) out.clearClue(idx); } Clues hillclimb(Clues start, int limit) { var best = start; diff --git a/src/test/java/puzzle/SwedishGeneratorTest.java b/src/test/java/puzzle/SwedishGeneratorTest.java index b43f1e1..7d9f7ca 100644 --- a/src/test/java/puzzle/SwedishGeneratorTest.java +++ b/src/test/java/puzzle/SwedishGeneratorTest.java @@ -82,7 +82,7 @@ public class SwedishGeneratorTest { grid.setLetterLo(0, LETTER_A); grid.setLetterLo(1, LETTER_B); grid.setLetterLo(2, LETTER_C); - var key = 18 << Slot.BIT_FOR_DIR | (CLUE_RIGHT); + var key = Slot.packSlotKey(18, CLUE_RIGHT); var pattern = patternForSlot(grid, key, 7L, 0L); assertEquals(1L | (28L << 8) | (55L << 16), pattern); } @@ -92,7 +92,7 @@ public class SwedishGeneratorTest { var grid = createEmpty(); grid.setLetterLo(OFF_0_0, LETTER_A); grid.setLetterLo(2, LETTER_C); - var key = 1 << Slot.BIT_FOR_DIR | (CLUE_RIGHT); + var key = Slot.packSlotKey(1, CLUE_RIGHT); var pattern = patternForSlot(grid, key, 7L, 0L); assertEquals(1L | (0L) | (55L << 16), pattern); } @@ -100,7 +100,7 @@ public class SwedishGeneratorTest { @Test void testPatternForSlotAllDashes() { var grid = createEmpty(); - var key = 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); assertEquals(0L, pattern); } @@ -109,7 +109,7 @@ public class SwedishGeneratorTest { void testPatternForSlotSingleLetter() { var grid = createEmpty(); grid.setLetterLo(OFF_0_0, LETTER_A); - var key = 1 << Slot.BIT_FOR_DIR | (CLUE_RIGHT); + var key = Slot.packSlotKey(1, CLUE_RIGHT); var pattern = patternForSlot(grid, key, 7L, 0L); assertEquals(1L, pattern); } @@ -164,12 +164,6 @@ public class SwedishGeneratorTest { var entry3 = dict.index()[3]; assertEquals(1, entry3.words().length); assertEquals(Lemma.pack("AXE".getBytes(StandardCharsets.US_ASCII)), Lemma.unpackLetters(entry3.words()[0])); - - // Check pos indexing - // AXE: A at 0, X at 1, E at 2 -/* assertTrue(entry3.pos()[0][0].size() > 0); - assertTrue(entry3.pos()[1]['X' - 'A'].size() > 0); - assertTrue(entry3.pos()[2]['E' - 'A'].size() > 0);*/ } @Test @@ -178,7 +172,7 @@ public class SwedishGeneratorTest { // key = (r << 8) | (c << 4) | d var offset = OFF_2_3; System.out.println("[DEBUG_LOG] Grid.offset(2, 3) = " + offset); - var key = (offset << Slot.BIT_FOR_DIR) | (CLUE_DOWN); + var key = Slot.packSlotKey(offset, CLUE_DOWN); System.out.println("[DEBUG_LOG] key = " + key); long lo = 0; // pos 0: (2, 5) @@ -203,54 +197,6 @@ public class SwedishGeneratorTest { assertTrue(Slot.horiz(CLUE_RIGHT)); // right assertFalse(Slot.horiz(CLUE_DOWN)); // down } - static int intersectSorted(int[] a, int aLen, int[] b, int bLen, int[] out) { - if (aLen == 0 || bLen == 0) return 0; - if (aLen < bLen >>> 4) { - var k = 0; - for (var i = 0; i < aLen; i++) { - var x = a[i]; - if (Arrays.binarySearch(b, 0, bLen, x) >= 0) out[k++] = x; - } - return k; - } - if (bLen < aLen >>> 4) { - var k = 0; - for (var i = 0; i < bLen; i++) { - var y = b[i]; - if (Arrays.binarySearch(a, 0, aLen, y) >= 0) out[k++] = y; - } - return k; - } - int i = 0, j = 0, k = 0, x, y; - while (i < aLen && j < bLen) { - x = a[i]; - y = b[j]; - if (x == y) { - out[k++] = x; - i++; - j++; - } else if (x < y) i++; - else j++; - } - return k; - } - - @Test - void testIntersectSorted() { - var buff = new int[10]; - var a = new int[]{ 1, 3, 5, 7, 9 }; - var b = new int[]{ 2, 3, 6, 7, 10 }; - - var count = intersectSorted(a, a.length, b, b.length, buff); - assertEquals(2, count); - assertEquals(3, buff[0]); - assertEquals(7, buff[1]); - - var c = new int[]{ 1, 2, 3 }; - var d = new int[]{ 4, 5, 6 }; - count = intersectSorted(c, c.length, d, d.length, buff); - assertEquals(0, count); - } static long packPattern(String s) { long p = 0; @@ -258,7 +204,7 @@ public class SwedishGeneratorTest { for (var i = 0; i < b.length; i++) { var val = b[i] & 31; if (val != 0) { - p |= (long) (i * 26 + val) << (i << 3); + p |= (i * 26L + val) << (i << 3); } } return p; @@ -326,7 +272,7 @@ public class SwedishGeneratorTest { void testPlaceWord() { var grid = createEmpty(); // Slot at OFF_0_0 length 3, horizontal (right) - var key = (OFF_0_0 << Slot.BIT_FOR_DIR) | (CLUE_RIGHT); + var key = Slot.packSlotKey(0, CLUE_RIGHT); var lo = (1L << OFF_0_0) | (1L << OFF_0_1) | (1L << OFF_0_2); val hi = 0L; var w1 = ABC; @@ -362,7 +308,7 @@ public class SwedishGeneratorTest { void testBacktrackingHelpers() { var grid = createEmpty(); // Slot at 0,1 length 2 - var key = (OFF_0_0 << Slot.BIT_FOR_DIR) | (CLUE_RIGHT); + var key = Slot.packSlotKey(0, CLUE_RIGHT); var lo = (1L << OFF_0_1) | (1L << OFF_0_2); var w = AZ; val low = grid.lo; @@ -387,8 +333,8 @@ public class SwedishGeneratorTest { assertTrue(Slot.increasing(CLUE_DOWN)); // Down assertFalse(Slot.increasing(CLUE_UP)); // Up - assertTrue(Slot.increasing((0) | CLUE_RIGHT)); - assertFalse(Slot.increasing((0) | CLUE_LEFT)); + assertTrue(Slot.increasing(Slot.packSlotKey(0, CLUE_RIGHT))); + assertFalse(Slot.increasing(Slot.packSlotKey(0, CLUE_LEFT))); // 2. Test slotScore val counts = new byte[SIZE];