package puzzle; import lombok.AllArgsConstructor; import lombok.experimental.Delegate; import lombok.val; import precomp.Mask; import puzzle.Masker.Slot; 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 java.util.stream.Stream; import static precomp.Const9x8.CLUE_DOWN0; import static precomp.Const9x8.CLUE_LEFT3; import static precomp.Const9x8.CLUE_LEFT_TOP4; import static precomp.Const9x8.CLUE_NONE; import static precomp.Const9x8.CLUE_RIGHT1; import static precomp.Const9x8.CLUE_RIGHT_TOP5; import static precomp.Const9x8.CLUE_UP2; import static puzzle.Clues.createEmpty; import static puzzle.Masker.isLo; import static puzzle.SwedishGenerator.X; 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'), RIGHT1(CLUE_RIGHT1, 'A', 'a'), UP2(CLUE_UP2, 'C', 'c'), LEFT3(CLUE_LEFT3, 'D', 'd'), LEFT_TOP4(CLUE_LEFT_TOP4, 'E', 'e'), RIGHT_TOP5(CLUE_RIGHT_TOP5, 'F', 'f'), NONE(CLUE_NONE, '?', '?'); final byte dir; final char slotChar, clueChar; private static final Clue[] CLUES = new Clue[]{ DOWN0, RIGHT1, UP2, LEFT3, LEFT_TOP4, RIGHT_TOP5, NONE, NONE, NONE }; public static Clue from(int dir) { return CLUES[dir]; } } public record Vestigium(int index, int clue) { public int cellIndex() { return index * 33 + 27 + Slot.dir(clue); } } public record ExportedPuzzle(String[] grid, WordOut[] words, int difficulty, Rewards rewards) { } public record Rewards(int coins, int stars, int hints) { } public record WordOut(String word, int[] cell, int startRow, int startCol, char direction, int arrowRow, int arrowCol, boolean isReversed, int complex, String[] clue) { record ShaLemma(String word, @Delegate ShardLem rec) { } private static ShaLemma lookup(long w, byte[] bytes) { try { val rec = Meta.lookupSilent(w); System.out.println("\nQuery: w=" + w + " -> i=" + rec.mmap()); var word1 = Lemma.asWord(w, bytes); System.out.println(" word=" + word1 + "\n" + " simpel=" + rec.simpel() + "\n" + " clues=" + Arrays.toString(rec.clues())); return new ShaLemma(word1, rec); } catch (Exception e) { throw new RuntimeException(e); } } static long reverse(long w) { int L = Lemma.unpackSize(w) + 1; long letters = w & Lemma.LETTER_MASK; long rev = 0; for (int i = 0; i < L; i++) { long letter = (letters >>> (5 * i)) & 31; rev |= (letter << (5 * (L - 1 - i))); } return (w & ~Lemma.LETTER_MASK) | rev; } public WordOut(long l, int startRow, int startCol, char d, int arrowRow, int arrowCol, boolean isReversed, byte[] bytes) { val meta = lookup(isReversed ? reverse(l) : l, bytes); this(meta.word, new int[]{ arrowRow, arrowCol, startRow, startCol }, startRow, startCol, d, arrowRow, arrowCol, isReversed, meta.simpel(), meta.clues()); } } @FunctionalInterface public interface ClueSign { byte replace(byte data); } public record Signa(@Delegate Clues c) { public static Signa of(Mask... cells) { return new Signa(createEmpty()).setClue(cells); } public Signa setClue(Mask... cells) { for (var cell : cells) { if (isLo((cell.index()))) setClueLo(cell.lo(), cell.d()); else setClueHi(cell.hi(), cell.d()); } return this; } public Signa deepCopyGrid() { return new Signa(new Clues(c.lo, c.hi, c.vlo, c.vhi, c.rlo, c.rhi, c.xlo, c.xhi)); } @Delegate public Stream stream() { val stream = Stream.builder(); for (var l = c.lo & ~c.xlo & ~c.rlo & c.vlo; l != X; l &= l - 1) stream.accept(new Vestigium(Long.numberOfTrailingZeros(l), CLUE_RIGHT1)); for (var l = c.lo & ~c.xlo & ~c.rlo & ~c.vlo; l != X; l &= l - 1) stream.accept(new Vestigium(Long.numberOfTrailingZeros(l), CLUE_DOWN0)); for (var l = c.lo & ~c.xlo & c.rlo & ~c.vlo; l != X; l &= l - 1) stream.accept(new Vestigium(Long.numberOfTrailingZeros(l), CLUE_UP2)); for (var l = c.lo & ~c.xlo & c.rlo & c.vlo; l != X; l &= l - 1) stream.accept(new Vestigium(Long.numberOfTrailingZeros(l), CLUE_LEFT3)); for (var l = c.lo & c.xlo & ~c.rlo & ~c.vlo; l != X; l &= l - 1) stream.accept(new Vestigium(Long.numberOfTrailingZeros(l), CLUE_LEFT_TOP4)); for (var l = c.lo & c.xlo & ~c.rlo & c.vlo; l != X; l &= l - 1) stream.accept(new Vestigium(Long.numberOfTrailingZeros(l), CLUE_RIGHT_TOP5)); for (var h = c.hi & ~c.xhi & ~c.rhi & c.vhi; h != X; h &= h - 1) stream.accept(new Vestigium(Export.HI(Long.numberOfTrailingZeros(h)), CLUE_RIGHT1)); for (var h = c.hi & ~c.xhi & ~c.rhi & ~c.vhi; h != X; h &= h - 1) stream.accept(new Vestigium(Export.HI(Long.numberOfTrailingZeros(h)), CLUE_DOWN0)); for (var h = c.hi & ~c.xhi & c.rhi & ~c.vhi; h != X; h &= h - 1) stream.accept(new Vestigium(Export.HI(Long.numberOfTrailingZeros(h)), CLUE_UP2)); for (var h = c.hi & ~c.xhi & c.rhi & c.vhi; h != X; h &= h - 1) stream.accept(new Vestigium(Export.HI(Long.numberOfTrailingZeros(h)), CLUE_LEFT3)); for (var h = c.hi & c.xhi & ~c.rhi & ~c.vhi; h != X; h &= h - 1) stream.accept(new Vestigium(Export.HI(Long.numberOfTrailingZeros(h)), CLUE_LEFT_TOP4)); for (var h = c.hi & c.xhi & ~c.rhi & c.vhi; h != X; h &= h - 1) stream.accept(new Vestigium(Export.HI(Long.numberOfTrailingZeros(h)), CLUE_RIGHT_TOP5)); return stream.build(); } } public record Placed(long lemma, int slotKey, Mask[] cells) { public static final char HORIZONTAL = 'h'; static final char VERTICAL = 'v'; static final char[] DIRECTION = { Placed.VERTICAL, Placed.HORIZONTAL, Placed.VERTICAL, Placed.HORIZONTAL, Placed.VERTICAL, Placed.VERTICAL }; public int arrowCol() { return cells[0].c(); } public int arrowRow() { return cells[0].r(); } public int startRow() { return cells[1].r(); } public int startCol() { return cells[1].c(); } public boolean isReversed() { return !Slotinfo.increasing(slotKey); } public char direction() { return DIRECTION[Slot.dir(slotKey)]; } } }