diff --git a/src/main/java/puzzle/Main.java b/src/main/java/puzzle/Main.java index b0fe7f3..bd8718e 100644 --- a/src/main/java/puzzle/Main.java +++ b/src/main/java/puzzle/Main.java @@ -357,7 +357,7 @@ public class Main { static PuzzleResult _attempt(Rng rng, Dict dict, Opts opts) { TOTAL_ATTEMPTS.incrementAndGet(); val stack = new int[STACK_SIZE]; - var swe = new SwedishGenerator(rng, stack); + var swe = new SwedishGenerator(rng, stack, Clues.createEmpty()); var mask = swe.generateMask(opts.pop, opts.gens, Math.max(opts.pop, (int) Math.floor(opts.pop * 1.5))); var filled = fillMask(rng, extractSlots(mask), mask.toGrid(), dict.index()); diff --git a/src/main/java/puzzle/SwedishGenerator.java b/src/main/java/puzzle/SwedishGenerator.java index c80f57b..1291f2f 100644 --- a/src/main/java/puzzle/SwedishGenerator.java +++ b/src/main/java/puzzle/SwedishGenerator.java @@ -41,7 +41,7 @@ import static java.nio.charset.StandardCharsets.*; * java SwedishGenerator [--seed N] [--pop N] [--gens N] [--tries N] [--words word-list.txt] */ @SuppressWarnings("ALL") -public record SwedishGenerator(Rng rng, int[] stack) { +public record SwedishGenerator(Rng rng, int[] stack, Clues cache) { record CandidateInfo(int[] indices, int count) { } @@ -283,6 +283,15 @@ public record SwedishGenerator(Rng rng, int[] stack) { for (var l = lo; l != X; l &= l - 1) processSlot(this, visitor, Long.numberOfTrailingZeros(l)); for (var h = hi; h != X; h &= h - 1) processSlot(this, visitor, 64 | Long.numberOfTrailingZeros(h)); } + public Clues from(Clues best) { + lo = best.lo; + hi = best.hi; + vlo = best.vlo; + vhi = best.vhi; + rlo = best.rlo; + rhi = best.rhi; + return this; + } } static record Grid(byte[] g, long lo, long hi) { @@ -605,8 +614,7 @@ public record SwedishGenerator(Rng rng, int[] stack) { } return g; } - Clues mutate(Clues clues) { - var c = clues.deepCopyGrid(); + Clues mutate(Clues c) { int ri; var bytes = MUTATE_RI[rng.randint(0, SIZE_MIN_1)]; for (var k = 0; k < 4; k++) { @@ -666,6 +674,7 @@ public record SwedishGenerator(Rng rng, int[] stack) { var fails = 0; while (fails < limit) { + cache.from(best); var cand = mutate(best); var f = maskFitness(cand); if (f < bestF) { @@ -673,6 +682,7 @@ public record SwedishGenerator(Rng rng, int[] stack) { bestF = f; fails = 0; } else { + best.from(cache); fails++; } } diff --git a/src/test/java/puzzle/ExportFormatTest.java b/src/test/java/puzzle/ExportFormatTest.java index ba023d4..772c56c 100644 --- a/src/test/java/puzzle/ExportFormatTest.java +++ b/src/test/java/puzzle/ExportFormatTest.java @@ -14,7 +14,6 @@ import puzzle.SwedishGenerator.Rng; import java.io.IOException; import java.nio.file.Paths; -import java.util.HashMap; import static org.junit.jupiter.api.Assertions.*; import static puzzle.SwedishGenerator.*; @@ -28,7 +27,7 @@ public class ExportFormatTest { @Test void testExportFormatFromFilled() { - var swe = new SwedishGenerator(new Rng(0), new int[STACK_SIZE]); + var swe = new SwedishGenerator(new Rng(0), new int[STACK_SIZE], Clues.createEmpty()); val clues = Clues.createEmpty(); // Place a RIGHT clue at (0,0) @@ -87,7 +86,7 @@ public class ExportFormatTest { @Test void testExportFormatEmpty() { - var swe = new SwedishGenerator(new Rng(0), new int[STACK_SIZE]); + var swe = new SwedishGenerator(new Rng(0), new int[STACK_SIZE], Clues.createEmpty()); var grid = Grid.createEmpty(); val clues = Clues.createEmpty(); var fillResult = new FillResult(true, new Gridded(grid), new long[300], new FillStats(0, 0, 0, 0)); diff --git a/src/test/java/puzzle/SwedishGeneratorTest.java b/src/test/java/puzzle/SwedishGeneratorTest.java index 63bf94f..b594285 100644 --- a/src/test/java/puzzle/SwedishGeneratorTest.java +++ b/src/test/java/puzzle/SwedishGeneratorTest.java @@ -255,8 +255,7 @@ public class SwedishGeneratorTest { // This should detect a slot starting at 0,1 with length 2 (0,1 and 0,2) var clues = Clues.createEmpty(); clues.setClue(OFF_0_0, CLUE_RIGHT); - var grid = clues.toGrid(); - + var grid = clues.toGrid(); var slots = extractSlots(clues); assertEquals(1, slots.length); @@ -269,7 +268,7 @@ public class SwedishGeneratorTest { @Test void testMaskFitnessBasic() { - var gen = new SwedishGenerator(new Rng(0), new int[STACK_SIZE]); + var gen = new SwedishGenerator(new Rng(0), new int[STACK_SIZE], Clues.createEmpty()); var grid = Clues.createEmpty(); // Empty grid should have high penalty (no slots) var f1 = gen.maskFitness(grid); @@ -284,12 +283,12 @@ public class SwedishGeneratorTest { @Test void testGeneticAlgorithmComponents() { var rng = new Rng(42); - var gen = new SwedishGenerator(rng, new int[STACK_SIZE]); + var gen = new SwedishGenerator(rng, new int[STACK_SIZE], Clues.createEmpty()); var g1 = gen.randomMask(); assertNotNull(g1); - var g2 = gen.mutate(g1); + var g2 = gen.mutate(g1.deepCopyGrid()); assertNotNull(g2); assertNotSame(g1, g2); @@ -410,7 +409,7 @@ public class SwedishGeneratorTest { @Test void testMaskFitnessDetailed() { - var gen = new SwedishGenerator(new Rng(42), new int[STACK_SIZE]); + var gen = new SwedishGenerator(new Rng(42), new int[STACK_SIZE], Clues.createEmpty()); var grid = Clues.createEmpty(); // Empty grid: huge penalty var fitEmpty = gen.maskFitness(grid);