184 lines
8.3 KiB
Java
184 lines
8.3 KiB
Java
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<Vestigium> stream() {
|
|
val stream = Stream.<Vestigium>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)]; }
|
|
}
|
|
}
|