package puzzle; import module java.base; import anno.DictGen; import lombok.val; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import puzzle.Export.Vestigium; import puzzle.Export.Signa; import puzzle.Export.Puzzle; import puzzle.Export.Lettrix; import puzzle.Export.PuzzleResult; import puzzle.Export.Rewards; import puzzle.Main.Opts; import puzzle.SwedishGenerator.Rng; import puzzle.dict950.DictData950; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; import static precomp.Const9x8.*; import static precomp.Const9x8.Cell.*; import static puzzle.Export.Clue.*; import static puzzle.LemmaData.AB; import static puzzle.LemmaData.AZ; import static puzzle.SwedishGenerator.Lemma; import static puzzle.SwedishGenerator.Slotinfo; import static puzzle.SwedishGenerator.fillMask; @DictGen( packageName = "puzzle.dict950", className = "DictData950", scv = "/home/mike/dev/puzzle-generator/nl_score_hints_v4.csv", simpleMax = 950, minLen = 2, maxLen = 8 ) public class MainTest { static final Opts opts = new Main.Opts() {{ this.seed = 12348; this.clueSize = 4; this.pop = 4; // Tiny population this.offspring = 18; this.gens = 20; // Very few generations this.minSimplicity = 0; this.threads = 1; this.tries = 1; this.verbose = false; }}; @Test void testExtractSlots() { var clues = Signa.of(r0c0d1); var grid = new Puzzle(clues); val g = grid.grid().g; GridBuilder.placeWord(grid.grid(), g, r0c0d1.slotKey, (1L << OFF_0_1) | (1L << OFF_0_2), 0, AB); var slots = Masker.slots(clues.c(), DictData950.DICT950.index(), DictData950.DICT950.reversed()); 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); assertEquals(0, cells[1].r()); assertEquals(1, cells[1].c()); assertEquals(0, cells[2].r()); assertEquals(2, cells[2].c()); } @Test void testStaticSlotMethods() { // Test static horiz // dir 1 (right) is horizontal assertTrue(Masker.Slot.horiz(1)); // dir 0 (down) is vertical assertFalse(Masker.Slot.horiz(0)); } @Test void testForEachSlot() { var count = new AtomicInteger(0); Masker.forEachSlot(Signa.of(r0c0d1).c(), (key, lo, hi) -> { count.incrementAndGet(); assertEquals(8, Long.bitCount(lo) + Long.bitCount(hi)); assertEquals(0, Masker.IT[Long.numberOfTrailingZeros(lo)].r()); assertEquals(1, Masker.IT[Long.numberOfTrailingZeros(lo)].c()); }); assertEquals(1, count.get()); } @Test public void testHoriz() { assertTrue(Masker.Slot.horiz(1)); // Right assertTrue(Masker.Slot.horiz(3)); // Left assertFalse(Masker.Slot.horiz(0)); // Down assertFalse(Masker.Slot.horiz(2)); // Up assertFalse(Masker.Slot.horiz(4)); // assertFalse(Masker.Slot.horiz(5)); // } @Test public void testGridBasics() { var clues = Signa.of(r2c1d2); var grid = new Puzzle(clues); r1c1.or(r0c1).lo(); // Test set/get GridBuilder.placeWord(grid.grid(), grid.grid().g, r2c1d2.slotKey, (1L << OFF_1_1) | (1L << OFF_0_1), 0, AZ); val map = grid.collect(Collectors.toMap(Lettrix::index, Lettrix::letter)); Assertions.assertEquals(LETTER_A, map.get(OFF_1_1)); Assertions.assertEquals(LETTER_Z, map.get(OFF_0_1)); var clueMap = clues.stream().collect(Collectors.toMap(Vestigium::index, Vestigium::clue)); Assertions.assertEquals(1, clueMap.size()); Assertions.assertEquals(UP2.dir, clueMap.get(OFF_2_1)); // Test isLetterAt Assertions.assertFalse(clueMap.containsKey(OFF_0_0)); Assertions.assertFalse(clueMap.containsKey(OFF_1_2)); Assertions.assertFalse(clueMap.containsKey(OFF_2_3)); Assertions.assertFalse(clueMap.containsKey(OFF_1_1)); // Test isDigitAt Assertions.assertFalse(clues.isClueLo(OFF_0_0)); Assertions.assertTrue(clues.isClueLo(OFF_2_1)); clueMap = clues.stream().collect(Collectors.toMap(Vestigium::index, Vestigium::clue)); Assertions.assertEquals(UP2.dir, clueMap.get(OFF_2_1)); Assertions.assertFalse(clues.isClueLo(OFF_2_3)); Assertions.assertFalse(clues.isClueLo(OFF_1_1)); // Test isLettercell Assertions.assertTrue(clues.notClue(OFF_0_0)); // 'A' is letter Assertions.assertTrue(clues.isClueLo(OFF_2_1)); // digit Assertions.assertTrue(clues.notClue(OFF_1_1)); // '#' is lettercell } @Test public void testCluesDeepCopy() { var clues = Signa.of(r0c0d1, r0c1d2, r1c0d3, r1c1d0); var copy = clues.deepCopyGrid(); var clueMap = clues.stream().collect(Collectors.toMap(Vestigium::index, Vestigium::clue)); Assertions.assertEquals(RIGHT1.dir, clueMap.get(OFF_0_0)); copy.setClue(r0c0d0); var copied = copy.stream().collect(Collectors.toMap(Vestigium::index, Vestigium::clue)); Assertions.assertEquals(DOWN0.dir, copied.get(OFF_0_0)); Assertions.assertEquals(RIGHT1.dir, clueMap.get(OFF_0_0)); } @Test public void testMini() { Assertions.assertTrue(Signa.of(r1c1d3).isClueLo(OFF_1_1)); } @Test void testFiller2() { var mask = Signa.of( r0c0d1, r0c3d0, r0c4d0, r0c5d0, r0c6d0, r0c7d0, r0c8d0, r1c0d1, r2c0d1, r3c0d3, r3c3d3, r4c0d3, r4c3d0, r4c6d3, r5c0d3, r6c0d3, r7c0d2, r7c1d2, r7c2d2, r7c8d3 ); Assertions.assertEquals(20, mask.clueCount()); val map = mask.stream().collect(Collectors.toMap(Vestigium::index, Vestigium::clue)); Assertions.assertEquals(20, map.size()); var slots = Masker.slots(mask.c(), DictData950.DICT950.index(), DictData950.DICT950.reversed()); // var filled = fillMask(rng, slotInfo, grid, false); // val res = new PuzzleResult(new Clued(mask), new Gridded(grid), slotInfo, filled).exportFormatFromFilled(0, new Rewards(0, 0, 0)); } @Test void testFiller() { System.out.println(DictData950.DICT950.index().length); val rng = new Rng(-343913721); var mask = Signa.of( r0c3d3, r0c6d3, r0c7d0, r0c8d0, r1c1d1, r2c1d1, r3c3d3, r3c6d0, r4c2d3, r4c3d1, r5c1d1, r6c1d1, r6c8d2, r7c0d2, r7c1d1, r7c4d2, r7c5d2, r7c8d3 ); var slotInfo = Masker.slots(mask.c(), DictData950.DICT950.index(), DictData950.DICT950.reversed()); var grid = Masker.grid(slotInfo); var filled = fillMask(rng, slotInfo, grid.lo, grid.hi, grid.g); Assertions.assertTrue(filled.ok(), "Puzzle generation failed (not ok)"); Assertions.assertEquals(17, Slotinfo.wordCount(0, slotInfo), "Number of assigned words changed"); Assertions.assertEquals("BEADEMT", Lemma.asWord(slotInfo[0].assign().w, Export.BYTES.get())); Assertions.assertEquals(74732156493031040L, grid.lo); Assertions.assertEquals(193L, grid.hi); var g = new Puzzle(grid, mask.c()); var result = new PuzzleResult(mask, g, slotInfo, filled); var aa = result.exportFormatFromFilled(new Rewards(1, 1, 1), Masker.IT); result.gridGridToString(); System.out.println(String.join("\n", aa.grid())); } @Test public void testAttempt() { PuzzleResult res = null; int foundSeed = -1; for (int i = 0; i < 50; i++) { int seed = opts.seed + i; res = Main.attempt(new Rng(seed), DictData950.DICT950, opts); if (res != null && res.filled().ok()) { foundSeed = seed; System.out.println("[DEBUG_LOG] Seed found: " + seed); System.out.println("[DEBUG_LOG] ClueMap Size: " + Slotinfo.wordCount(0, res.slots())); System.out.println("[DEBUG_LOG] Grid:"); System.out.println(res.gridRenderHuman()); System.out.println(res.gridGridToString()); break; } } Assertions.assertNotNull(res, "Puzzle generation failed (null result)"); Assertions.assertTrue(res.filled().ok(), "Puzzle generation failed (not ok)"); Assertions.assertEquals(12348, foundSeed, "Found seed changed"); } boolean isLetter(byte b) { return (b & 64) != 0; } @Test public void testIsLetterA() { assertTrue(isLetter((byte) 'A')); } @Test public void testIsLetterZ() { assertTrue(isLetter((byte) 'Z')); } }