diff --git a/src/main/java/puzzle/ExportFormat.java b/src/main/java/puzzle/ExportFormat.java index fd68b69..31ab0c7 100644 --- a/src/main/java/puzzle/ExportFormat.java +++ b/src/main/java/puzzle/ExportFormat.java @@ -119,7 +119,7 @@ public final class ExportFormat { private static Placed extractPlacedFromSlot(Dict dict, Slot s, Lemma lemma) { int r = s.clueR(); int c = s.clueC(); - char d = s.dir(); + int d = s.dir(); List cells = new ArrayList<>(); for (int i = 0; i < s.len(); i++) { @@ -131,26 +131,26 @@ public final class ExportFormat { String direction; boolean isReversed = false; - if (d == '2') { // right -> horizontal + if (d ==2) { // right -> horizontal direction = HORIZONTAL; startRow = cells.get(0)[0]; startCol = cells.get(0)[1]; arrowRow = r; arrowCol = c; - } else if (d == '3' || d == '5') { // down or down-bent -> vertical + } else if (d == 3 || d == 5) { // down or down-bent -> vertical direction = VERTICAL; startRow = cells.get(0)[0]; startCol = cells.get(0)[1]; arrowRow = r; arrowCol = c; - } else if (d == '4') { // left -> horizontal (REVERSED) + } else if (d == 4) { // left -> horizontal (REVERSED) direction = HORIZONTAL; isReversed = true; startRow = cells.get(0)[0]; startCol = cells.get(0)[1]; arrowRow = r; arrowCol = c; - } else if (d == '1') { // up -> vertical (REVERSED) + } else if (d == 1) { // up -> vertical (REVERSED) direction = VERTICAL; isReversed = true; startRow = cells.get(0)[0]; diff --git a/src/main/java/puzzle/SwedishGenerator.java b/src/main/java/puzzle/SwedishGenerator.java index 6d048a0..7619c1e 100644 --- a/src/main/java/puzzle/SwedishGenerator.java +++ b/src/main/java/puzzle/SwedishGenerator.java @@ -1,11 +1,13 @@ package puzzle; +import javax.xml.crypto.Data; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.util.*; import java.util.function.Predicate; +import java.util.stream.Stream; /** * SwedishGenerator.java @@ -15,22 +17,14 @@ import java.util.function.Predicate; * java SwedishGenerator [--seed N] [--pop N] [--gens N] [--tries N] [--words word-list.txt] */ @SuppressWarnings("ALL") -public record SwedishGenerator(int W, int H, int SIZE, int MAX_LEN) { +public record SwedishGenerator(int W, int H, int SIZE, int MAX_LEN, int[] buff) { public static final char C_DASH = '\0'; static final byte _1 = 49, _9 = 57, A = 65, Z = 90, DASH = (byte) C_DASH; record nbrs_8(int x, int y) { } - class Data { - - static byte[] EXAMPLE = new byte[0]; - } - public SwedishGenerator { - Data.EXAMPLE = new byte[SIZE]; - Arrays.fill(Data.EXAMPLE, DASH); - } - public SwedishGenerator(int W, int H) { this(W, H, W * H, Math.min(W, H)); } + public SwedishGenerator(int W, int H) { this(W, H, W * H, Math.min(W, H), new int[10000]); } public SwedishGenerator() { this(9, 8); } static final int CLUE_SIZE = 4, @@ -79,7 +73,6 @@ public record SwedishGenerator(int W, int H, int SIZE, int MAX_LEN) { static final char FIRST_ABC = 'A'; static final char LAST_ABC = 'Z'; static final char FIRST_ARROW = '1', LAST_ARROW = '6', HOR_ARROW_1 = '2', HOR_ARROW_2 = '4'; - static boolean isDigit(char ch) { return ch >= FIRST_ARROW && ch <= LAST_ARROW; } static boolean isLetter(char ch) { return ch >= FIRST_ABC && ch <= LAST_ABC; } static final class Rng { @@ -112,15 +105,16 @@ public record SwedishGenerator(int W, int H, int SIZE, int MAX_LEN) { record Grid(byte[] g, int H, int W) { Grid deepCopyGrid() { return new Grid(g.clone(), H, W); } - private int getOffset(int r, int c) { return r * W + c; } + private int offset(int r, int c) { return r * W + c; } boolean isLettercell(int r, int c) { return !isDigitAt(r, c); } - char getCharAt(int r, int c) { return (char) (g[getOffset(r, c)] & 0xFF); } - byte byteAt(int r, int c) { return g[getOffset(r, c)]; } - void setCharAt(int r, int c, char ch) { g[getOffset(r, c)] = (byte) ch; } - boolean isLetterAt(int r, int c) { return ((g[getOffset(r, c)] & 64) != 0); } - boolean isDigitAt(int r, int c) { return (g[getOffset(r, c)] & 48) == 48; } + char getCharAt(int r, int c) { return (char) (g[offset(r, c)] & 0xFF); } + int digitAt(int r, int c) { return g[offset(r, c)] - 48; } + byte byteAt(int r, int c) { return g[offset(r, c)]; } + void setCharAt(int r, int c, char ch) { g[offset(r, c)] = (byte) ch; } + boolean isLetterAt(int r, int c) { return ((g[offset(r, c)] & 64) != 0); } + boolean isDigitAt(int r, int c) { return (g[offset(r, c)] & 48) == 48; } } - Grid makeEmptyGrid() { return new Grid(Data.EXAMPLE.clone(), H, W); } + Grid makeEmptyGrid() { return new Grid(new byte[SIZE], H, W); } String gridToString(Grid g) { var sb = new StringBuilder(); @@ -252,23 +246,23 @@ public record SwedishGenerator(int W, int H, int SIZE, int MAX_LEN) { return new Dict(map.values().toArray(Lemma[]::new)); } - - static int[] intersectSorted(int[] a, int aLen, int[] b, int bLen) { - var out = new int[Math.min(aLen, bLen)]; - int i = 0, j = 0, k = 0; + int[] intersectSorted(int[] a, int aLen, int[] b, int bLen) { + //var out = new int[Math.min(aLen, bLen)]; + int i = 0, j = 0, k = 0, x = 0, y = 0; while (i < aLen && j < bLen) { - int x = a[i], y = b[j]; + x = a[i]; + y = b[j]; if (x == y) { - out[k++] = x; + buff[k++] = x; i++; j++; } else if (x < y) i++; else j++; } - return Arrays.copyOf(out, k); + return Arrays.copyOf(buff, k); } - static CandidateInfo candidateInfoForPattern(DictEntry entry, char[] pattern /* 0 means null */) { + CandidateInfo candidateInfoForPattern(DictEntry entry, char[] pattern ) { var lists = new ArrayList(); for (var i = 0; i < pattern.length; i++) { var ch = pattern[i]; @@ -296,10 +290,10 @@ public record SwedishGenerator(int W, int H, int SIZE, int MAX_LEN) { return new CandidateInfo(cur, curLen); } - static record Slot(String key, int clueR, int clueC, char dir, int[] rs, int[] cs, int len, boolean horiz) { + static record Slot(String key, int clueR, int clueC, int dir, int[] rs, int[] cs, int len, boolean horiz) { - public Slot(int clueR, int clueC, char dir, int[] rs, int[] cs) { - this(clueR + "," + clueC + ":" + dir, clueR, clueC, dir, rs, cs, rs.length, dir == HOR_ARROW_1 || dir == HOR_ARROW_2); + public Slot(int clueR, int clueC, int d, int[] rs, int[] cs) { + this(clueR + "," + clueC + ":" + d, clueR, clueC, d, rs, cs, rs.length, d == 2 || d == 4); } } @@ -308,10 +302,9 @@ public record SwedishGenerator(int W, int H, int SIZE, int MAX_LEN) { for (var r = 0; r < H; r++) { for (var c = 0; c < W; c++) { if (!grid.isDigitAt(r, c)) continue; - var d = grid.getCharAt(r, c); - var dir = d - '0'; - int or = OFFSETS[dir].x, oc = OFFSETS[dir].y; - int dr = STEPS[dir].x, dc = STEPS[dir].y; + var d = grid.digitAt(r, c); + int or = OFFSETS[d].x, oc = OFFSETS[d].y; + int dr = STEPS[d].x, dc = STEPS[d].y; int rr = r + or, cc = c + oc; if (rr < 0 || rr >= H || cc < 0 || cc >= W) continue; @@ -502,8 +495,7 @@ public record SwedishGenerator(int W, int H, int SIZE, int MAX_LEN) { for (var r = 0; r < H; r++) for (var c = 0; c < W; c++) { - var ch = out.getCharAt(r, c); - if (isDigit(ch) && !hasRoomForClue(out, r, c, ch)) out.setCharAt(r, c, C_DASH); + if (out.isDigitAt(r, c) && !hasRoomForClue(out, r, c, out.getCharAt(r, c))) out.setCharAt(r, c, C_DASH); } return out; } diff --git a/src/test/java/puzzle/MainTest.java b/src/test/java/puzzle/MainTest.java index 79108a4..78092ad 100644 --- a/src/test/java/puzzle/MainTest.java +++ b/src/test/java/puzzle/MainTest.java @@ -29,35 +29,36 @@ public class MainTest { grid.setCharAt(r, c, C_DASH); } } - + // Test set/get grid.setCharAt(0, 0, 'A'); grid.setCharAt(1, 2, '5'); grid.setCharAt(2, 3, 'Z'); - + Assertions.assertEquals('A', grid.getCharAt(0, 0)); Assertions.assertEquals('5', grid.getCharAt(1, 2)); Assertions.assertEquals('Z', grid.getCharAt(2, 3)); Assertions.assertEquals(C_DASH, grid.getCharAt(1, 1)); - + // Test isLetterAt Assertions.assertTrue(grid.isLetterAt(0, 0)); Assertions.assertFalse(grid.isLetterAt(1, 2)); Assertions.assertTrue(grid.isLetterAt(2, 3)); Assertions.assertFalse(grid.isLetterAt(1, 1)); - + // Test isDigitAt Assertions.assertFalse(grid.isDigitAt(0, 0)); Assertions.assertTrue(grid.isDigitAt(1, 2)); + Assertions.assertEquals(5, grid.digitAt(1, 2)); Assertions.assertFalse(grid.isDigitAt(2, 3)); Assertions.assertFalse(grid.isDigitAt(1, 1)); - + // Test isLettercell Assertions.assertTrue(grid.isLettercell(0, 0)); // 'A' is letter Assertions.assertFalse(grid.isLettercell(1, 2)); // '5' is digit Assertions.assertTrue(grid.isLettercell(1, 1)); // '#' is lettercell } - + @Test public void testGridDeepCopy() { var grid = new Grid(new byte[2 * 2], 2, 2); @@ -65,7 +66,7 @@ public class MainTest { grid.setCharAt(0, 1, 'B'); grid.setCharAt(1, 0, 'C'); grid.setCharAt(1, 1, 'D'); - + var copy = grid.deepCopyGrid(); Assertions.assertEquals('A', copy.getCharAt(0, 0)); @@ -73,8 +74,7 @@ public class MainTest { Assertions.assertEquals('X', copy.getCharAt(0, 0)); Assertions.assertEquals('A', grid.getCharAt(0, 0)); // Original should be unchanged } - - + @Test public void testMini() { var grid = new Grid(new byte[3 * 3], 3, 3); diff --git a/src/test/java/puzzle/SwedishGeneratorTest.java b/src/test/java/puzzle/SwedishGeneratorTest.java new file mode 100644 index 0000000..da5af90 --- /dev/null +++ b/src/test/java/puzzle/SwedishGeneratorTest.java @@ -0,0 +1,47 @@ +package puzzle; + +import org.junit.jupiter.api.Test; +import puzzle.SwedishGenerator.Grid; +import puzzle.SwedishGenerator.Slot; +import java.util.ArrayList; +import static org.junit.jupiter.api.Assertions.assertEquals; + +class SwedishGeneratorTest { + + @Test + void testExtractSlots() { + SwedishGenerator generator = new SwedishGenerator(3, 3); + Grid grid = generator.makeEmptyGrid(); + + // Set up digits on the grid to create slots. + for (int r = 0; r < 3; r++) { + for (int c = 0; c < 3; c++) { + if ((r + c) % 2 == 0) { + grid.setCharAt(r, c, '1'); + } + } + } + + // Set up letter cells around digits to form valid slots. + int[][] directions = { { -1, -1 }, { -1, 0 }, { -1, 1 }, { 0, -1 }, { 0, 1 }, { 1, -1 }, { 1, 0 } }; + + for (int r = 0; r < 3; r++) { + for (int c = 0; c < 3; c++) { + if (grid.isDigitAt(r, c)) { + int dr = directions[grid.digitAt(r, c)][0]; + int dc = directions[grid.digitAt(r, c)][1]; + + int rr = r + dr; + int cc = c + dc; + + if (rr >= 0 && rr < generator.H() && cc >= 0 && cc < generator.W()) + grid.setCharAt(rr, cc, 'A'); + } + } + } + + // Check the extractSlots method. + ArrayList slots = generator.extractSlots(grid); + assertEquals(3, slots.size()); + } +} \ No newline at end of file