package puzzle; import lombok.val; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; 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 puzzle.SwedishGenerator.Slot; import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; 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 puzzle.ExportFormatTest.Clue.*; import static puzzle.SwedishGenerator.*; import static puzzle.SwedishGeneratorTest.*; import static puzzle.SwedishGeneratorTest.Idx.IDX_0_0; import static puzzle.SwedishGeneratorTest.Idx.IDX_0_1; import static puzzle.SwedishGeneratorTest.Idx.IDX_1_0; import static puzzle.SwedishGeneratorTest.Idx.IDX_1_1; import static puzzle.SwedishGeneratorTest.Idx.IDX_2_1; import static puzzle.SwedishGeneratorTest.OFF_0_0; import static puzzle.SwedishGeneratorTest.OFF_0_1; import static puzzle.SwedishGeneratorTest.OFF_0_2; 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; }}; static final Dict dict = Dict.loadDict(opts.wordsPath); @Test void testExtractSlots() { var clues = Clues.createEmpty(); val key = Slot.packSlotKey(OFF_0_0, CLUE_RIGHT); clues.setClueLo(IDX_0_0.lo, CLUE_RIGHT); var grid = new Gridded(clues.toGrid()); val g = grid.grid().g; placeWord(grid.grid(), g, key, (1L << OFF_0_1) | (1L << OFF_0_2), 0, AB); var slots = extractSlots(clues, dict.index()); assertEquals(1, slots.length); var s = slots[0]; assertEquals(8, Slot.length(s.lo(), s.hi())); var cells = s.walk().toArray(); assertEquals(0, SwedishGenerator.IT[cells[0]].r()); assertEquals(1, SwedishGenerator.IT[cells[0]].c()); assertEquals(0, SwedishGenerator.IT[cells[1]].r()); assertEquals(2, SwedishGenerator.IT[cells[1]].c()); } @Test void testStaticSlotMethods() { // Test static horiz // dir 1 (right) is horizontal assertTrue(Slot.horiz(1)); // dir 0 (down) is vertical assertFalse(Slot.horiz(0)); } @Test void testForEachSlot() { var clues = Clues.createEmpty(); clues.setClueLo(IDX_0_0.lo, CLUE_RIGHT); var count = new AtomicInteger(0); clues.forEachSlot((key, lo, hi) -> { count.incrementAndGet(); assertEquals(8, Long.bitCount(lo) + Long.bitCount(hi)); assertEquals(0, SwedishGenerator.IT[Long.numberOfTrailingZeros(lo)].r()); assertEquals(1, SwedishGenerator.IT[Long.numberOfTrailingZeros(lo)].c()); }); assertEquals(1, count.get()); } @Test public void testHoriz() { assertTrue(Slot.horiz(1)); // Right assertTrue(Slot.horiz(3)); // Left assertFalse(Slot.horiz(0)); // Down assertFalse(Slot.horiz(2)); // Up } @Test public void testGridBasics() { var clues = new Clued(Clues.createEmpty()); val key = Slot.packSlotKey(OFF_2_1, CLUE_UP); clues.setClueLo(IDX_2_1.lo, CLUE_UP); var grid = new Gridded(clues.toGrid()); // Test set/get placeWord(grid.grid(), grid.grid().g, key, (1L << OFF_1_1) | (1L << OFF_0_1), 0, AZ); val map = grid.stream(clues.c()).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(CLUE_UP, clueMap.get(OFF_2_1)); // Test isLetterAt Assertions.assertTrue(clues.notClue(OFF_0_0)); Assertions.assertTrue(clues.notClue(OFF_1_2)); Assertions.assertTrue(clues.notClue(OFF_2_3)); Assertions.assertFalse(clues.isClueLo(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(CLUE_UP, 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 = new Clued(Clues.createEmpty()); clues.setClueLo(IDX_0_0.lo, RIGHT.dir); clues.setClueLo(IDX_0_1.lo, UP.dir); clues.setClueLo(IDX_1_0.lo, LEFT.dir); clues.setClueLo(IDX_1_1.lo, DOWN.dir); var copy = clues.deepCopyGrid(); var clueMap = clues.stream().collect(Collectors.toMap(ClueAt::index, ClueAt::clue)); Assertions.assertEquals(CLUE_RIGHT, clueMap.get(OFF_0_0)); copy.setClueLo(IDX_0_0.lo, DOWN.dir); var copied = copy.stream().collect(Collectors.toMap(ClueAt::index, ClueAt::clue)); Assertions.assertEquals(DOWN.dir, copied.get(OFF_0_0)); Assertions.assertEquals(RIGHT.dir, clueMap.get(OFF_0_0)); } @Test public void testMini() { val idx = IDX_1_1; var clues = Clues.createEmpty(); clues.setClueLo(idx.lo, CLUE_LEFT); Assertions.assertTrue(clues.isClueLo(idx.index)); } @Test void testMaskerCreation() { var swe = new SwedishGenerator(new Rng(12348), new int[STACK_SIZE], Clues.createEmpty()); var mask = swe.generateMask(opts.clueSize, opts.pop, opts.gens, opts.offspring); val clued = new Clued(mask); val test = clued.gridToString(); val RESULT = "1 \n" + " \n" + " 3\n" + " \n" + " \n" + "1 \n" + " \n" + " 3"; Assertions.assertEquals(4, clued.clueCount(), "Found seed changed"); Assertions.assertEquals(RESULT, test, "Found seed changed"); } @Test void testFiller() { val rng = new Rng(-343913721); val mask = new Clues( 74732156493031040L, 193L, 281475397248512L, 128L, 422762372923520L, 192L); var slots = extractSlots(mask, dict.index()); val slotInfo = scoreSlots(new int[slots.length], slots); var filled = fillMask(rng, slotInfo, mask.toGrid(), false); Assertions.assertTrue(filled.ok(), "Puzzle generation failed (not ok)"); Assertions.assertEquals(18, filled.wordCount(0), "Number of assigned words changed"); Assertions.assertEquals("SLEDE", Lemma.asWord(filled.clueMap()[282])); Assertions.assertEquals(-1L, filled.grid().grid().lo); Assertions.assertEquals(255L, filled.grid().grid().hi); filled.grid().gridToString(mask); var aa = new PuzzleResult(new Clued(mask), filled).exportFormatFromFilled(1, new Rewards(1, 1, 1)); } @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), dict, opts); if (res != null && res.filled().ok()) { foundSeed = seed; System.out.println("[DEBUG_LOG] Seed found: " + seed); System.out.println("[DEBUG_LOG] Simplicity: " + res.filled().stats().simplicity); System.out.println("[DEBUG_LOG] ClueMap Size: " + res.filled().wordCount(0)); System.out.println("[DEBUG_LOG] Grid:"); System.out.println(res.filled().grid().renderHuman(res.clues().c())); System.out.println(res.filled().grid().gridToString(res.clues().c())); System.out.println(res.filled().grid().renderHuman(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')); } }