From e9d787bbb95c6b60015250ea639fa055233974b6 Mon Sep 17 00:00:00 2001 From: mike Date: Fri, 23 Jan 2026 21:20:08 +0100 Subject: [PATCH] redo --- src/main/java/puzzle/Export.java | 114 +++++------------- src/main/java/puzzle/Replacar.java | 9 -- src/main/java/puzzle/Riddle.java | 56 +++++++++ src/test/java/puzzle/MainTest.java | 2 +- src/test/java/puzzle/PerformanceTest.java | 3 +- .../java/puzzle/SwedishGeneratorTest.java | 2 +- 6 files changed, 91 insertions(+), 95 deletions(-) delete mode 100644 src/main/java/puzzle/Replacar.java diff --git a/src/main/java/puzzle/Export.java b/src/main/java/puzzle/Export.java index 231b759..dc34eb5 100644 --- a/src/main/java/puzzle/Export.java +++ b/src/main/java/puzzle/Export.java @@ -6,7 +6,7 @@ import anno.Shaped; import lombok.experimental.Delegate; import lombok.val; import precomp.Const9x8; -import puzzle.Replacar.Rell; +import puzzle.Riddle.ClueSign; import puzzle.Riddle.ExportedPuzzle; import puzzle.Riddle.Placed; import puzzle.Riddle.Rewards; @@ -23,6 +23,7 @@ import static precomp.Const9x8.CLUE_RIGHT_TOP5; import static precomp.Const9x8.CLUE_UP2; import static puzzle.Clues.createEmpty; import static puzzle.Masker.Slot; +import static puzzle.Masker.isLo; import static puzzle.SwedishGenerator.X; @GenerateShapedCopies( @@ -32,13 +33,14 @@ import static puzzle.SwedishGenerator.X; ) public record Export() { - public static final ThreadLocal BYTES = ThreadLocal.withInitial(() -> new byte[8]); - @Shaped static final String INIT_GRID_OUTPUT = Const9x8.INIT_GRID_OUTPUT; - @Shaped static final int R = Const9x8.R; - @Shaped static final int C = Const9x8.C; - @Shaped static final byte[] INIT_GRID_OUTPUT_ARR = Const9x8.INIT_GRID_OUTPUT_ARR; - @Shaped static final long MASK_HI = Const9x8.MASK_HI; - @Shaped static final long MASK_LO = Const9x8.MASK_LO; + public static final ThreadLocal BYTES = ThreadLocal.withInitial(() -> new byte[8]); + @Shaped static final String INIT_GRID_OUTPUT = Const9x8.INIT_GRID_OUTPUT; + @Shaped static final int R = Const9x8.R; + @Shaped static final int C = Const9x8.C; + @Shaped static final byte[] INIT_GRID_OUTPUT_ARR = Const9x8.INIT_GRID_OUTPUT_ARR; + @Shaped static final byte[] INIT_GRID_OUTPUT_DASH_ARR = Const9x8.INIT_GRID_OUTPUT_DASH_ARR; + @Shaped static final long MASK_HI = Const9x8.MASK_HI; + @Shaped static final long MASK_LO = Const9x8.MASK_LO; static int HI(int in) { return in | 64; } static char LETTER(int in) { return (char) (in | 64); } @@ -46,19 +48,24 @@ public record Export() { static int INDEX_ROW(int idx) { return idx % R; } static int INDEX_COL(int idx) { return idx / R; } static int INDEX(int r, int cols, int c) { return r * cols + c; } + record Lettrix(int index, byte letter) { + + public int row() { return INDEX_ROW(index); } + public int col() { return INDEX_COL(index); } + public char human() { return LETTER(letter); } + static Lettrix from(int index, byte[] bytes) { return new Lettrix(index, bytes[index]); } + public int index(int cols) { return (row() * cols) + col(); } + } public record Signa(@Delegate Clues c) { public static Signa of(Mask... cells) { - var c = createEmpty(); - for (var cell : cells) { - if ((cell.index() & 64) == 0) c.setClueLo(cell.lo(), cell.d()); - else c.setClueHi(cell.hi(), cell.d()); - } - return new Signa(c); + var signa = new Signa(createEmpty()); + Arrays.stream(cells).forEach(signa::setClue); + return signa; } public Signa setClue(Mask cell) { - if ((cell.index() & 64) == 0) setClueLo(cell.lo(), cell.d()); + if (isLo((cell.index()))) setClueLo(cell.lo(), cell.d()); else setClueHi(cell.hi(), cell.d()); return this; } @@ -100,75 +107,27 @@ public record Export() { for (var h = grid.hi & MASK_HI & ~cl.hi; h != X; h &= h - 1) stream.accept(Lettrix.from(HI(Long.numberOfTrailingZeros(h)), grid.g)); return stream.build(); } - public String[] exportGrid(Slotinfo[] slots, Replacar clueChar, char emptyFallback) { - var sb = INIT_GRID_OUTPUT_ARR.clone(); + public String[] exportGrid(Slotinfo[] slots, ClueSign clueChar, byte[] template) { + var sb = template.clone(); for (var slot : slots) { val idx = Slot.clueIndex(slot.key()); val r = INDEX_ROW(idx); val c = INDEX_COL(idx); val dir = Slot.dir(slot.key()); - sb[r * (C + 1) + c] = (byte) clueChar.replace(new Rell(grid, cl, idx, (byte) (dir | 48))); + sb[r * (C + 1) + c] = (byte) clueChar.replace((byte) (dir | 48)); } stream().forEach((l) -> sb[l.index(C + 1)] = (byte) l.human()); - return new String(sb).replaceAll(" ", String.valueOf(emptyFallback)).split("\n"); + return new String(sb) .split("\n"); } - public static IntStream cellWalk(int base, long lo, long hi) { - if (Slotinfo.increasing(base)) { - return IntStream.concat(IntStream.of(Slot.clueIndex(base)), IntStream.concat( - IntStream.generate(new IntSupplier() { - - long temp = lo; - @Override - public int getAsInt() { - int res = Long.numberOfTrailingZeros(temp); - temp &= temp - 1; - return res; - } - }).limit(Long.bitCount(lo)), - IntStream.generate(new IntSupplier() { - - long temp = hi; - @Override - public int getAsInt() { - int res = 64 | Long.numberOfTrailingZeros(temp); - temp &= temp - 1; - return res; - } - }).limit(Long.bitCount(hi)))); - } else { - return IntStream.concat(IntStream.of(Slot.clueIndex(base)), IntStream.concat( - IntStream.generate(new IntSupplier() { - - long temp = hi; - @Override - public int getAsInt() { - int msb = 63 - Long.numberOfLeadingZeros(temp); - temp &= ~(1L << msb); - return 64 | msb; - } - }).limit(Long.bitCount(hi)), - IntStream.generate(new IntSupplier() { - - long temp = lo; - @Override - public int getAsInt() { - int msb = 63 - Long.numberOfLeadingZeros(temp); - temp &= ~(1L << msb); - return msb; - } - }).limit(Long.bitCount(lo)))); - } - } - } - public record PuzzleResult(Signa clues, Puzzle grid, Slotinfo[] slots, FillResult filled) { + public record PuzzleResult(Signa clues, Puzzle puzzle, Slotinfo[] slots, FillResult filled) { public String cluesGridToString() { return clues.gridToString(); } public String gridRenderHuman() { - return String.join("\n", grid.exportGrid(slots, _ -> ' ', '#')); + return String.join("\n", puzzle.exportGrid(slots, _ -> ' ', INIT_GRID_OUTPUT_DASH_ARR)); } public String gridGridToString() { var sb = INIT_GRID_OUTPUT_ARR.clone(); @@ -179,17 +138,16 @@ public record Export() { val dir = Slot.dir(slot.key()); sb[r * (C + 1) + c] = (byte) (dir | 48); } - grid.stream().forEach((l) -> sb[l.index(C + 1)] = (byte) l.human()); + puzzle.stream().forEach((l) -> sb[l.index(C + 1)] = (byte) l.human()); return new String(sb); } public ExportedPuzzle exportFormatFromFilled(Rewards rewards, rci[] rcis) { - // If nothing placed: return full grid mapped to letters/# only if (slots.length == 0) { - return new ExportedPuzzle(grid.exportGrid(slots, _ -> '#', '#'), new WordOut[0], 1, rewards); + return new ExportedPuzzle(puzzle.exportGrid(slots, _ -> '#', INIT_GRID_OUTPUT_DASH_ARR), new WordOut[0], 1, rewards); } var placed = Arrays.stream(slots) - .map(slot -> new Placed(slot.assign().w, slot.key(), Puzzle.cellWalk(slot.key(), slot.lo(), slot.hi()).mapToObj(i -> rcis[i]).toArray(rci[]::new))) + .map(slot -> new Placed(slot.assign().w, slot.key(), Riddle.cellWalk(slot.key(), slot.lo(), slot.hi()).mapToObj(i -> rcis[i]).toArray(rci[]::new))) .toArray(Placed[]::new); // 2) bounding box around all word cells + arrow cells, with 1-cell margin @@ -213,7 +171,7 @@ public record Export() { Arrays.fill(template, (byte) '#'); for (int i = width; i < template.length; i += width + 1) template[i] = (byte) '\n'; - grid.forEach(l -> { + puzzle.forEach(l -> { int rr = l.row() - MINR; int cc = l.col() - MINC; if (rr >= 0 && rr < height && cc >= 0 && cc < width) { @@ -239,12 +197,4 @@ public record Export() { } - record Lettrix(int index, byte letter) { - - public int row() { return INDEX_ROW(index); } - public int col() { return INDEX_COL(index); } - public char human() { return LETTER(letter); } - static Lettrix from(int index, byte[] bytes) { return new Lettrix(index, bytes[index]); } - public int index(int cols) { return (row() * cols) + col(); } - } } diff --git a/src/main/java/puzzle/Replacar.java b/src/main/java/puzzle/Replacar.java deleted file mode 100644 index 0a54e08..0000000 --- a/src/main/java/puzzle/Replacar.java +++ /dev/null @@ -1,9 +0,0 @@ -package puzzle; - -import puzzle.SwedishGenerator.Grid; -@FunctionalInterface -interface Replacar { - - record Rell(Grid grid, Clues clues, int index, byte data) { } - char replace(Rell c); -} diff --git a/src/main/java/puzzle/Riddle.java b/src/main/java/puzzle/Riddle.java index 3665173..46f28fe 100644 --- a/src/main/java/puzzle/Riddle.java +++ b/src/main/java/puzzle/Riddle.java @@ -8,6 +8,8 @@ import puzzle.Meta.ShardLem; import puzzle.SwedishGenerator.Lemma; import puzzle.SwedishGenerator.Slotinfo; import java.util.Arrays; +import java.util.function.IntSupplier; +import java.util.stream.IntStream; import static precomp.Const9x8.CLUE_DOWN0; import static precomp.Const9x8.CLUE_LEFT3; import static precomp.Const9x8.CLUE_LEFT_TOP4; @@ -17,6 +19,53 @@ import static precomp.Const9x8.CLUE_RIGHT_TOP5; import static precomp.Const9x8.CLUE_UP2; public class Riddle { + public static IntStream cellWalk(int base, long lo, long hi) { + if (Slotinfo.increasing(base)) { + return IntStream.concat(IntStream.of(Slot.clueIndex(base)), IntStream.concat( + IntStream.generate(new IntSupplier() { + + long temp = lo; + @Override + public int getAsInt() { + int res = Long.numberOfTrailingZeros(temp); + temp &= temp - 1; + return res; + } + }).limit(Long.bitCount(lo)), + IntStream.generate(new IntSupplier() { + + long temp = hi; + @Override + public int getAsInt() { + int res = 64 | Long.numberOfTrailingZeros(temp); + temp &= temp - 1; + return res; + } + }).limit(Long.bitCount(hi)))); + } else { + return IntStream.concat(IntStream.of(Slot.clueIndex(base)), IntStream.concat( + IntStream.generate(new IntSupplier() { + + long temp = hi; + @Override + public int getAsInt() { + int msb = 63 - Long.numberOfLeadingZeros(temp); + temp &= ~(1L << msb); + return 64 | msb; + } + }).limit(Long.bitCount(hi)), + IntStream.generate(new IntSupplier() { + + long temp = lo; + @Override + public int getAsInt() { + int msb = 63 - Long.numberOfLeadingZeros(temp); + temp &= ~(1L << msb); + return msb; + } + }).limit(Long.bitCount(lo)))); + } + } @AllArgsConstructor enum Clue { DOWN0(CLUE_DOWN0, 'B', 'b'), @@ -83,4 +132,11 @@ public class Riddle { meta.simpel(), meta.clues()); } } + + @FunctionalInterface + static + interface ClueSign { + + char replace(byte data); + } } diff --git a/src/test/java/puzzle/MainTest.java b/src/test/java/puzzle/MainTest.java index c3293a0..d613fed 100644 --- a/src/test/java/puzzle/MainTest.java +++ b/src/test/java/puzzle/MainTest.java @@ -106,7 +106,7 @@ public class MainTest { assertEquals(1, slots.length); var s = slots[0]; assertEquals(8, Masker.Slot.length(s.lo(), s.hi())); - var cells = Puzzle.cellWalk(s.key(), s.lo(), s.hi()).mapToObj(c -> Masker.IT[c]).toArray(rci[]::new); + var cells = Riddle.cellWalk(s.key(), s.lo(), s.hi()).mapToObj(c -> Masker.IT[c]).toArray(rci[]::new); assertEquals(0, cells[1].r()); assertEquals(1, cells[1].c()); assertEquals(0, cells[2].r()); diff --git a/src/test/java/puzzle/PerformanceTest.java b/src/test/java/puzzle/PerformanceTest.java index 3e156b8..69895c9 100644 --- a/src/test/java/puzzle/PerformanceTest.java +++ b/src/test/java/puzzle/PerformanceTest.java @@ -5,7 +5,6 @@ import anno.DictGen; import anno.Dictionaries; import lombok.val; import org.junit.jupiter.api.Test; -import puzzle.Export.Puzzle; import puzzle.Export.Signa; import puzzle.SwedishGenerator.Rng; import puzzle.SwedishGenerator.Slotinfo; @@ -202,7 +201,7 @@ public class PerformanceTest { var slotChar = dir.slotChar; display[cr][cc] = clueChar; - Puzzle.cellWalk(slot.key(), slot.lo(), slot.hi()) + Riddle.cellWalk(slot.key(), slot.lo(), slot.hi()) .skip(1) .forEach(idx -> { var r = Masker.IT[idx].r(); diff --git a/src/test/java/puzzle/SwedishGeneratorTest.java b/src/test/java/puzzle/SwedishGeneratorTest.java index 80cb9ba..a7d71f0 100644 --- a/src/test/java/puzzle/SwedishGeneratorTest.java +++ b/src/test/java/puzzle/SwedishGeneratorTest.java @@ -207,7 +207,7 @@ public class SwedishGeneratorTest { assertEquals(OFF_2_3, Slot.clueIndex(r2c3d0.slotKey)); assertEquals(CLUE_DOWN0, Slot.dir(r2c3d0.slotKey)); assertFalse(Slot.horiz(r2c3d0.slotKey)); - var cells = Puzzle.cellWalk( r2c3d0.slotKey, r2c5.or(r3c5).or(r4c5).lo(), 0L).mapToObj(i -> Masker.IT[i]).toArray(rci[]::new); + var cells = Riddle.cellWalk(r2c3d0.slotKey, r2c5.or(r3c5).or(r4c5).lo(), 0L).mapToObj(i -> Masker.IT[i]).toArray(rci[]::new); assertEquals(2, cells[1].r()); assertEquals(5, cells[1].c()); assertEquals(3, cells[2].r());