package puzzle; import module java.base; import lombok.val; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import precomp.Neighbors9x8.rci; import puzzle.Export.ClueAt; import puzzle.Export.Clued; import puzzle.Export.Gridded; import puzzle.Export.LetterVisit.LetterAt; import puzzle.Export.PuzzleResult; import puzzle.Export.Rewards; import puzzle.Main.Opts; import puzzle.SwedishGenerator.Rng; 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; import static puzzle.SwedishGeneratorTest.LETTER_A; import static puzzle.SwedishGeneratorTest.LETTER_Z; 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 = Clued.of(r0c0d1); var grid = new Gridded(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 = clues.slots(); assertEquals(1, slots.length); var s = slots[0]; assertEquals(8, Masker.Slot.length(s.lo(), s.hi())); var cells = Gridded.cellWalk((byte) s.key(), s.lo(), s.hi()).mapToObj(c -> Masker.IT[c]).toArray(rci[]::new); assertEquals(0, cells[0].r()); assertEquals(1, cells[0].c()); assertEquals(0, cells[1].r()); assertEquals(2, cells[1].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); Clued.of(r0c0d1).forEachSlot((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 = Clued.of(r2c1d2); var grid = new Gridded(clues); // 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(LetterAt::index, LetterAt::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(ClueAt::index, ClueAt::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(ClueAt::index, ClueAt::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 = Clued.of(r0c0d1, r0c1d2, r1c0d3, r1c1d0); var copy = clues.deepCopyGrid(); var clueMap = clues.stream().collect(Collectors.toMap(ClueAt::index, ClueAt::clue)); Assertions.assertEquals(RIGHT1.dir, clueMap.get(OFF_0_0)); copy.setClue(r0c0d0); var copied = copy.stream().collect(Collectors.toMap(ClueAt::index, ClueAt::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(Clued.of(r1c1d3).isClueLo(OFF_1_1)); } @Test void testFiller2() { val mask = Clued.parse( "1 000000\n" + "1 \n" + "1 \n" + "3 3 \n" + "3 0 3 \n" + "3 \n" + "3 \n" + "222 3"); Assertions.assertEquals(20, mask.clueCount()); val map = mask.stream().collect(Collectors.toMap(ClueAt::index, ClueAt::clue)); Assertions.assertEquals(20, map.size()); var slots = mask.slots(); // 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() { val rng = new Rng(-343913721); val mask = Clued.parse( " 3 300\n" + " 1 \n" + " 1 \n" + " 3 0 \n" + " 31 \n" + " 1 \n" + " 1 2\n" + "21 22 3"); var slotInfo = mask.slots(); var grid = Slotinfo.grid(slotInfo); var filled = fillMask(rng, slotInfo, grid); Assertions.assertTrue(filled.ok(), "Puzzle generation failed (not ok)"); Assertions.assertEquals(17, Slotinfo.wordCount(0, slotInfo), "Number of assigned words changed"); Assertions.assertEquals("VREEMDS", Lemma.asWord(slotInfo[0].assign().w, Export.BYTES.get())); Assertions.assertEquals(-1L, grid.lo); Assertions.assertEquals(-1L, grid.hi); var g = new Gridded(grid, mask.c()); g.gridToString(mask.c()); var aa = new PuzzleResult(mask, g, slotInfo, filled).exportFormatFromFilled(new Rewards(1, 1, 1)); 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), DictData.DICT, 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.grid().renderHuman(res.clues().c())); System.out.println(res.grid().gridToString(res.clues().c())); 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')); } }