diff --git a/src/main/java/puzzle/Export.java b/src/main/java/puzzle/Export.java index 8763df1..7125dc5 100644 --- a/src/main/java/puzzle/Export.java +++ b/src/main/java/puzzle/Export.java @@ -108,7 +108,10 @@ public record Export() { } } //public boolean isLetterSet(int idx) { return isLetter(g[idx]); } - char NOT_CLUE_NOT_LETTER_TO(byte b, char fallback) { return b == SwedishGenerator.DASH ? fallback : (char) (64 | b); } + char NOT_CLUE_NOT_LETTER_TO(byte b, char fallback) { + if (b == SwedishGenerator.DASH) throw new RuntimeException(); + return (char) (64 | b); + } String gridToString(Clues clues) { var sb = new StringBuilder(); for (var r = 0; r < R; r++) { @@ -117,8 +120,10 @@ public record Export() { var offset = Grid.offset(r, c); if (clues.isClue(offset)) sb.append((char) (48 | clues.digitAt(offset))); - else + else if (grid.lisLetterAtLo(offset)) sb.append((char) (64 | grid.letter32At(offset))); + else + sb.append(' '); } } return sb.toString(); @@ -140,8 +145,10 @@ public record Export() { var offset = Grid.offset(r, c); if (clues.isClue(offset)) { sb.append(clueChar.replace(new Cell(grid, clues, offset, clues.digitAt(offset)))); - } else { + } else if (grid.lisLetterAt(offset)) { sb.append(NOT_CLUE_NOT_LETTER_TO(grid.letter32At(offset), emptyFallback)); + } else { + sb.append(emptyFallback); } } out[r] = sb.toString(); @@ -229,7 +236,8 @@ public record Export() { var letterAt = new HashMap(); for (var p : placed) { for (var c : p.cells) { - if (inBounds(c) && mask.notClue(c)) { + if (!inBounds(c)) throw new RuntimeException(); + if (mask.notClue(c) && g.lisLetterAt(c)) { letterAt.put(c, (char) (64 | g.letter32At(c))); } } diff --git a/src/main/java/puzzle/SwedishGenerator.java b/src/main/java/puzzle/SwedishGenerator.java index 5068b3a..ab1303a 100644 --- a/src/main/java/puzzle/SwedishGenerator.java +++ b/src/main/java/puzzle/SwedishGenerator.java @@ -285,6 +285,14 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) { static int offset(int r, int c) { return r | (c << 3); } /// the pos will never target a clue public byte letter32At(int pos) { return g[pos]; } + public boolean lisLetterAt(int pos) { + if ((pos & 64) == 0) + return lisLetterAtLo(pos); + return lisLetterAtHi(pos); + } + + public boolean lisLetterAtLo(int pos) { return (lo & (1L << pos)) != 0; } + public boolean lisLetterAtHi(int pos) { return (hi & (1L << (pos & 63))) != 0; } void setLetterLo(int idx, byte ch) { lo |= (1L << idx); @@ -313,8 +321,11 @@ public record SwedishGenerator(Rng rng, int[] stack, Clues cache) { hi &= ~(1L << (idx & 63)); } void undoPlace(long maskLo, long maskHi) { - for (long b = maskLo; b != 0; b &= b - 1) clearletterLo(Long.numberOfTrailingZeros(b)); - for (long b = maskHi; b != 0; b &= b - 1) clearletterHi(64 | Long.numberOfTrailingZeros(b)); + lo &= ~maskLo; + hi &= ~maskHi; + + /*for (long b = maskLo; b != 0; b &= b - 1) clearletterLo(Long.numberOfTrailingZeros(b)); + for (long b = maskHi; b != 0; b &= b - 1) clearletterHi(64 | Long.numberOfTrailingZeros(b));*/ } } diff --git a/src/test/java/puzzle/MainTest.java b/src/test/java/puzzle/MainTest.java index eb6334f..4a7f745 100644 --- a/src/test/java/puzzle/MainTest.java +++ b/src/test/java/puzzle/MainTest.java @@ -14,7 +14,6 @@ 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.SwedishGenerator.*; -import static puzzle.SwedishGenerator.DASH; public class MainTest { @@ -107,13 +106,13 @@ public class MainTest { Assertions.assertEquals(LETTER_A, grid.letter32At(OFF_0_0)); Assertions.assertEquals(CLUE_UP, clues.digitAt(OFF_1_2)); Assertions.assertEquals(LETTER_Z, grid.letter32At(OFF_2_3)); - Assertions.assertEquals(DASH, grid.letter32At(OFF_1_1)); + Assertions.assertFalse(grid.lisLetterAtLo(OFF_1_1)); // Verify letter mask Assertions.assertTrue((grid.lo & (1L << OFF_0_0)) != 0); Assertions.assertTrue((grid.lo & (1L << OFF_2_3)) != 0); Assertions.assertTrue((grid.lo & (1L << OFF_1_2)) != 0); // Clue also in lo - Assertions.assertTrue((grid.lo & (1L << OFF_1_1)) == 0); // Empty letter cell + assertEquals(0, (grid.lo & (1L << OFF_1_1))); // Empty letter cell // Test isLetterAt Assertions.assertTrue(clues.notClue(OFF_0_0)); diff --git a/src/test/java/puzzle/SwedishGeneratorTest.java b/src/test/java/puzzle/SwedishGeneratorTest.java index a27b455..5efdf53 100644 --- a/src/test/java/puzzle/SwedishGeneratorTest.java +++ b/src/test/java/puzzle/SwedishGeneratorTest.java @@ -100,7 +100,7 @@ public class SwedishGeneratorTest { @Test void testPatternForSlotAllDashes() { - var grid = createEmpty(); + var grid = createEmpty(); var slot = Slot.from(1 << Slot.BIT_FOR_DIR | (CLUE_RIGHT), 7L, 0L); var pattern = patternForSlot(grid, slot); @@ -360,8 +360,8 @@ public class SwedishGeneratorTest { grid.setLetter(OFF_0_2, LETTER_X); // Conflict at the end assertFalse(placeWord(grid, s, w1, undoBuffer, 3)); // Verify grid is still empty (except for 'X') - assertEquals(DASH, grid.letter32At(OFF_0_0)); - assertEquals(DASH, grid.letter32At(OFF_0_1)); + assertFalse(grid.lisLetterAtLo(OFF_0_0)); + assertFalse(grid.lisLetterAtLo(OFF_0_1)); assertEquals(LETTER_X, grid.letter32At(OFF_0_2)); } @@ -382,8 +382,8 @@ public class SwedishGeneratorTest { assertEquals(lo, undoBuffer[0]); grid.undoPlace(undoBuffer[0], undoBuffer[1]); - assertEquals(DASH, grid.letter32At(OFF_0_1)); - assertEquals(DASH, grid.letter32At(OFF_0_2)); + assertFalse(grid.lisLetterAtLo(OFF_0_1)); + assertFalse(grid.lisLetterAtLo(OFF_0_2)); } @Test