introduce bitloops
This commit is contained in:
@@ -5,20 +5,28 @@ import org.junit.jupiter.api.Test;
|
||||
import puzzle.Export.Clued;
|
||||
import puzzle.Export.Gridded;
|
||||
import puzzle.Export.Placed;
|
||||
import puzzle.Export.Rewards;
|
||||
import puzzle.Export.PuzzleResult;
|
||||
import puzzle.Export.Rewards;
|
||||
import puzzle.SwedishGenerator.FillResult;
|
||||
import puzzle.SwedishGenerator.Grid;
|
||||
import puzzle.SwedishGenerator.Rng;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static puzzle.MainTest.*;
|
||||
import static puzzle.MainTest.LETTER_E;
|
||||
import static puzzle.MainTest.LETTER_T;
|
||||
import static puzzle.SwedishGenerator.*;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static puzzle.SwedishGenerator.C;
|
||||
import static puzzle.SwedishGenerator.Clues;
|
||||
import static puzzle.SwedishGenerator.FillStats;
|
||||
import static puzzle.SwedishGenerator.R;
|
||||
import static puzzle.SwedishGenerator.STACK_SIZE;
|
||||
import static puzzle.SwedishGenerator.Slot;
|
||||
import static puzzle.SwedishGenerator.placeWord;
|
||||
import static puzzle.SwedishGeneratorTest.OFF_0_1;
|
||||
import static puzzle.SwedishGeneratorTest.OFF_0_2;
|
||||
import static puzzle.SwedishGeneratorTest.OFF_0_3;
|
||||
import static puzzle.SwedishGeneratorTest.OFF_0_4;
|
||||
import static puzzle.SwedishGeneratorTest.OFF_0_5;
|
||||
import static puzzle.SwedishGeneratorTest.TEST;
|
||||
|
||||
public class ExportFormatTest {
|
||||
|
||||
@@ -26,7 +34,7 @@ public class ExportFormatTest {
|
||||
static final byte CLUE_RIGHT = 1;
|
||||
static final byte CLUE_UP = 2;
|
||||
static final byte CLUE_LEFT = 3;
|
||||
|
||||
|
||||
@Test
|
||||
void testExportFormatFromFilled() {
|
||||
var swe = new SwedishGenerator(new Rng(0), new int[STACK_SIZE], Clues.createEmpty());
|
||||
@@ -36,21 +44,17 @@ public class ExportFormatTest {
|
||||
clues.setClue(0, CLUE_RIGHT);
|
||||
// This creates a slot starting at (0,1)
|
||||
// Terminate the slot at (0,5) with another digit to avoid it extending to MAX_WORD_LENGTH
|
||||
clues.setClue(Grid.offset(0, 5), CLUE_LEFT);
|
||||
var grid = clues.toGrid();
|
||||
clues.setClue(OFF_0_5, CLUE_LEFT);
|
||||
var grid = new Gridded(clues.toGrid());
|
||||
|
||||
var clueMap = new long[300];
|
||||
// key = (cellIndex << 2) | (direction)
|
||||
var key = (0) | (CLUE_RIGHT);
|
||||
clueMap[key] = SwedishGeneratorTest.TEST;
|
||||
var key = Slot.packSlotKey(0, CLUE_RIGHT);
|
||||
var lo = (1L << OFF_0_1) | (1L << OFF_0_2) | (1L << OFF_0_3) | (1L << OFF_0_4);
|
||||
clueMap[key] = TEST;
|
||||
assertTrue(placeWord(grid.grid(), key, lo, 0L, TEST));
|
||||
|
||||
// Manually fill the grid letters for "TEST" at (0,1), (0,2), (0,3), (0,4)
|
||||
grid.setLetterLo(OFF_0_1, LETTER_T);
|
||||
grid.setLetterLo(OFF_0_2, LETTER_E);
|
||||
grid.setLetterLo(OFF_0_3, LETTER_S);
|
||||
grid.setLetterLo(OFF_0_4, LETTER_T);
|
||||
|
||||
var fillResult = new FillResult(true, new Gridded(grid), clueMap, new FillStats(0, 0, 0, 0));
|
||||
var fillResult = new FillResult(true, grid, clueMap, new FillStats(0, 0, 0, 0));
|
||||
var puzzleResult = new PuzzleResult(new Clued(clues), fillResult);
|
||||
|
||||
var rewards = new Rewards(10, 5, 1);
|
||||
|
||||
@@ -4,38 +4,27 @@ import lombok.val;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
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.SwedishGenerator.*;
|
||||
import static puzzle.SwedishGeneratorTest.*;
|
||||
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 byte LETTER_A = (byte) 'A';
|
||||
static final byte LETTER_B = (byte) 'B';
|
||||
static final byte LETTER_Z = (byte) 'Z';
|
||||
static final byte LETTER_T = (byte) 'T';
|
||||
static final byte LETTER_E = (byte) 'E';
|
||||
static final byte LETTER_S = (byte) 'S';
|
||||
static final byte CLUE_DOWN = 0;
|
||||
static final byte CLUE_RIGHT = 1;
|
||||
static final byte CLUE_UP = 2;
|
||||
static final byte CLUE_LEFT = 3;
|
||||
|
||||
static final int OFF_0_0 = Grid.offset(0, 0);
|
||||
static final int OFF_0_1 = Grid.offset(0, 1);
|
||||
static final int OFF_0_2 = Grid.offset(0, 2);
|
||||
static final int OFF_0_3 = Grid.offset(0, 3);
|
||||
static final int OFF_0_4 = Grid.offset(0, 4);
|
||||
static final int OFF_1_1 = Grid.offset(1, 1);
|
||||
static final int OFF_1_2 = Grid.offset(1, 2);
|
||||
static final int OFF_2_3 = Grid.offset(2, 3);
|
||||
|
||||
static final Opts opts = new Main.Opts() {{
|
||||
this.seed = 12348;
|
||||
this.clueSize = 4;
|
||||
@@ -52,10 +41,11 @@ public class MainTest {
|
||||
void testExtractSlots() {
|
||||
|
||||
var clues = Clues.createEmpty();
|
||||
val key = Slot.packSlotKey(OFF_0_0, CLUE_RIGHT);
|
||||
clues.setClue(OFF_0_0, CLUE_RIGHT);
|
||||
var grid = clues.toGrid();
|
||||
grid.setLetterLo(OFF_0_1, LETTER_A);
|
||||
grid.setLetterLo(OFF_0_2, LETTER_B);
|
||||
var grid = new Gridded(clues.toGrid());
|
||||
|
||||
placeWord(grid.grid(), key, (1L << OFF_0_1) | (1L << OFF_0_2), 0, AB);
|
||||
|
||||
var slots = extractSlots(clues, dict.index());
|
||||
assertEquals(1, slots.length);
|
||||
@@ -100,40 +90,33 @@ public class MainTest {
|
||||
@Test
|
||||
public void testGridBasics() {
|
||||
var clues = Clues.createEmpty();
|
||||
clues.setClue(OFF_1_2, CLUE_UP);
|
||||
var grid = clues.toGrid();
|
||||
val key = Slot.packSlotKey(OFF_2_1, CLUE_UP);
|
||||
clues.setClue(OFF_2_1, CLUE_UP);
|
||||
var grid = new Gridded(clues.toGrid());
|
||||
|
||||
// Test set/get
|
||||
grid.setLetterLo(OFF_0_0, LETTER_A);
|
||||
grid.setLetterLo(OFF_2_3, LETTER_Z);
|
||||
|
||||
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.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
|
||||
assertEquals(0, (grid.lo & (1L << OFF_1_1))); // Empty letter cell
|
||||
placeWord(grid.grid(), key, (1L << OFF_1_1) | (1L << OFF_0_1), 0, AZ);
|
||||
val arr = grid.stream(clues).collect(Collectors.toMap(LetterAt::index, LetterAt::letter));
|
||||
Assertions.assertEquals(LETTER_A, arr.get(OFF_1_1));
|
||||
Assertions.assertEquals(LETTER_Z, arr.get(OFF_0_1));
|
||||
Assertions.assertEquals(CLUE_UP, clues.digitAt(OFF_2_1));
|
||||
|
||||
// Test isLetterAt
|
||||
Assertions.assertTrue(clues.notClue(OFF_0_0));
|
||||
Assertions.assertFalse(clues.notClue(OFF_1_2));
|
||||
Assertions.assertTrue(clues.notClue(OFF_1_2));
|
||||
Assertions.assertTrue(clues.notClue(OFF_2_3));
|
||||
Assertions.assertFalse(clues.isClue(OFF_1_1));
|
||||
|
||||
// Test isDigitAt
|
||||
Assertions.assertFalse(clues.isClue(0));
|
||||
Assertions.assertTrue(clues.isClue(OFF_1_2));
|
||||
Assertions.assertEquals(CLUE_UP, clues.digitAt(OFF_1_2));
|
||||
Assertions.assertTrue(clues.isClue(OFF_2_1));
|
||||
Assertions.assertEquals(CLUE_UP, clues.digitAt(OFF_2_1));
|
||||
Assertions.assertFalse(clues.isClue(OFF_2_3));
|
||||
Assertions.assertFalse(clues.isClue(OFF_1_1));
|
||||
|
||||
// Test isLettercell
|
||||
Assertions.assertTrue(clues.notClue(OFF_0_0)); // 'A' is letter
|
||||
Assertions.assertTrue(clues.isClue(OFF_1_2)); // digit
|
||||
Assertions.assertTrue(clues.isClue(OFF_2_1)); // digit
|
||||
Assertions.assertTrue(clues.notClue(OFF_1_1)); // '#' is lettercell
|
||||
}
|
||||
@Test
|
||||
@@ -192,7 +175,7 @@ public class MainTest {
|
||||
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));
|
||||
|
||||
}
|
||||
@@ -209,7 +192,7 @@ public class MainTest {
|
||||
System.out.println("[DEBUG_LOG] Simplicity: " + res.filled().stats().simplicity);
|
||||
System.out.println("[DEBUG_LOG] ClueMap Size: " + res.filled().wordCount());
|
||||
System.out.println("[DEBUG_LOG] Grid:");
|
||||
System.out.println(res.filled().grid().renderHuman(res.mask().mask()));
|
||||
System.out.println(res.filled().grid().renderHuman(res.clues().mask()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,8 +5,10 @@ import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import puzzle.Export.Gridded;
|
||||
import puzzle.Export.IntListDTO;
|
||||
import puzzle.Export.LetterVisit.LetterAt;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static puzzle.SwedishGenerator.*;
|
||||
@@ -54,6 +56,7 @@ public class SwedishGeneratorTest {
|
||||
static final long ABC = Lemma.from(26, "ABC");
|
||||
static final long ABD = Lemma.from(27, "ABD");
|
||||
static final long AZ = Lemma.from(28, "AZ");
|
||||
static final long AB = Lemma.from(29, "AB");
|
||||
static final byte LETTER_A = ((byte) 'A') & 31;
|
||||
static final byte LETTER_B = ((byte) 'B') & 31;
|
||||
static final byte LETTER_C = ((byte) 'C') & 31;
|
||||
@@ -64,13 +67,18 @@ public class SwedishGeneratorTest {
|
||||
static final byte CLUE_UP = 2;
|
||||
static final byte CLUE_LEFT = 3;
|
||||
|
||||
static final int OFF_0_0 = Grid.offset(0, 0);
|
||||
static final int OFF_0_1 = Grid.offset(0, 1);
|
||||
static final int OFF_0_2 = Grid.offset(0, 2);
|
||||
static final int OFF_1_0 = Grid.offset(1, 0);
|
||||
static final int OFF_1_1 = Grid.offset(1, 1);
|
||||
static final int OFF_1_2 = Grid.offset(1, 2);
|
||||
static final int OFF_2_0 = Grid.offset(2, 0);
|
||||
static final int OFF_2_1 = Grid.offset(2, 1);
|
||||
static final int OFF_2_3 = Grid.offset(2, 3);
|
||||
static final int OFF_0_0 = Grid.offset(0, 0);
|
||||
static final int OFF_0_4 = Grid.offset(0, 4);
|
||||
static final int OFF_0_5 = Grid.offset(0, 5);
|
||||
static final int OFF_0_1 = Grid.offset(0, 1);
|
||||
static final int OFF_0_2 = Grid.offset(0, 2);
|
||||
static final int OFF_0_3 = Grid.offset(0, 3);
|
||||
static final int OFF_2_0 = Grid.offset(2, 0);
|
||||
static final int OFF_2_5 = Grid.offset(2, 5);
|
||||
static final int OFF_3_5 = Grid.offset(3, 5);
|
||||
static final int OFF_4_5 = Grid.offset(4, 5);
|
||||
@@ -78,21 +86,23 @@ public class SwedishGeneratorTest {
|
||||
static final byte D_BYTE_2 = CLUE_RIGHT;
|
||||
@Test
|
||||
void testPatternForSlotAllLetters() {
|
||||
var grid = createEmpty();
|
||||
grid.setLetterLo(0, LETTER_A);
|
||||
grid.setLetterLo(1, LETTER_B);
|
||||
grid.setLetterLo(2, LETTER_C);
|
||||
var key = Slot.packSlotKey(18, CLUE_RIGHT);
|
||||
var pattern = patternForSlot(grid, key, 7L, 0L);
|
||||
assertEquals(1L | (28L << 8) | (55L << 16), pattern);
|
||||
var grid = new Gridded(createEmpty());
|
||||
var key = Slot.packSlotKey(OFF_0_0, CLUE_RIGHT);
|
||||
val clues = Clues.createEmpty();
|
||||
clues.setClue(OFF_0_0, CLUE_RIGHT);
|
||||
placeWord(grid.grid(), key, (1L << OFF_0_1) | (1L << OFF_0_2) | (1L << OFF_0_3), 0L, ABC);
|
||||
val map = grid.stream(clues).collect(Collectors.toMap(LetterAt::index, LetterAt::letter));
|
||||
assertEquals(LETTER_A, map.get(OFF_0_1));
|
||||
assertEquals(LETTER_B, map.get(OFF_0_2));
|
||||
assertEquals(LETTER_C, map.get(OFF_0_3));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testPatternForSlotMixed() {
|
||||
var grid = createEmpty();
|
||||
grid.setLetterLo(OFF_0_0, LETTER_A);
|
||||
grid.setLetterLo(2, LETTER_C);
|
||||
var key = Slot.packSlotKey(1, CLUE_RIGHT);
|
||||
grid.setLetterLo(OFF_2_0, LETTER_C);
|
||||
var key = Slot.packSlotKey(OFF_1_0, CLUE_RIGHT);
|
||||
var pattern = patternForSlot(grid, key, 7L, 0L);
|
||||
assertEquals(1L | (0L) | (55L << 16), pattern);
|
||||
}
|
||||
@@ -133,9 +143,11 @@ public class SwedishGeneratorTest {
|
||||
|
||||
@Test
|
||||
void testGrid() {
|
||||
var grid = createEmpty();
|
||||
grid.setLetterLo(OFF_0_0, LETTER_A);
|
||||
assertEquals(LETTER_A, grid.letter32At(OFF_0_0));
|
||||
var grid = new Gridded(createEmpty());
|
||||
grid.grid().setLetterLo(OFF_0_0, LETTER_A);
|
||||
val arr = grid.stream(Clues.createEmpty()).collect(Collectors.toMap(LetterAt::index, LetterAt::letter));
|
||||
assertEquals(1, arr.size());
|
||||
assertEquals(LETTER_A, arr.get(OFF_0_0));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -270,7 +282,7 @@ public class SwedishGeneratorTest {
|
||||
|
||||
@Test
|
||||
void testPlaceWord() {
|
||||
var grid = createEmpty();
|
||||
var grid = new Gridded(createEmpty());
|
||||
// Slot at OFF_0_0 length 3, horizontal (right)
|
||||
var key = Slot.packSlotKey(0, CLUE_RIGHT);
|
||||
var lo = (1L << OFF_0_0) | (1L << OFF_0_1) | (1L << OFF_0_2);
|
||||
@@ -278,51 +290,55 @@ public class SwedishGeneratorTest {
|
||||
var w1 = ABC;
|
||||
|
||||
// 1. Successful placement in empty grid
|
||||
assertTrue(placeWord(grid, key, lo, hi, w1));
|
||||
assertEquals(LETTER_A, grid.letter32At(OFF_0_0));
|
||||
assertEquals(LETTER_B, grid.letter32At(OFF_0_1));
|
||||
assertEquals(LETTER_C, grid.letter32At(OFF_0_2));
|
||||
assertTrue(placeWord(grid.grid(), key, lo, hi, w1));
|
||||
var map = grid.stream(Clues.createEmpty()).collect(Collectors.toMap(LetterAt::index, LetterAt::letter));
|
||||
assertEquals(3, map.size());
|
||||
assertEquals(LETTER_A, map.get(OFF_0_0));
|
||||
assertEquals(LETTER_B, map.get(OFF_0_1));
|
||||
assertEquals(LETTER_C, map.get(OFF_0_2));
|
||||
|
||||
// 2. Successful placement with partial overlap (same characters)
|
||||
assertTrue(placeWord(grid, key, lo, hi, w1));
|
||||
|
||||
assertTrue(placeWord(grid.grid(), key, lo, hi, w1));
|
||||
// 3. Conflict: place "ABD" where "ABC" is
|
||||
var w2 = ABD;
|
||||
assertFalse(placeWord(grid, key, lo, hi, w2));
|
||||
assertFalse(placeWord(grid.grid(), key, lo, hi, ABD));
|
||||
// Verify grid is unchanged (still "ABC")
|
||||
assertEquals(LETTER_A, grid.letter32At(OFF_0_0));
|
||||
assertEquals(LETTER_B, grid.letter32At(OFF_0_1));
|
||||
assertEquals(LETTER_C, grid.letter32At(OFF_0_2));
|
||||
map = grid.stream(Clues.createEmpty()).collect(Collectors.toMap(LetterAt::index, LetterAt::letter));
|
||||
assertEquals(3, map.size());
|
||||
assertEquals(LETTER_A, map.get(OFF_0_0));
|
||||
assertEquals(LETTER_B, map.get(OFF_0_1));
|
||||
assertEquals(LETTER_C, map.get(OFF_0_2));
|
||||
|
||||
// 4. Partial placement then conflict (rollback)
|
||||
grid = createEmpty();
|
||||
grid.setLetterLo(OFF_0_2, LETTER_X); // Conflict at the end
|
||||
assertFalse(placeWord(grid, key, lo, hi, w1));
|
||||
// Verify grid is still empty (except for 'X')
|
||||
assertFalse(grid.lisLetterAtLo(OFF_0_0));
|
||||
assertFalse(grid.lisLetterAtLo(OFF_0_1));
|
||||
assertEquals(LETTER_X, grid.letter32At(OFF_0_2));
|
||||
grid = new Gridded(createEmpty());
|
||||
grid.grid().setLetterLo(OFF_0_2, LETTER_X); // Conflict at the end
|
||||
assertFalse(placeWord(grid.grid(), key, lo, hi, w1));
|
||||
map = grid.stream(Clues.createEmpty()).collect(Collectors.toMap(LetterAt::index, LetterAt::letter));
|
||||
assertEquals(1, map.size());
|
||||
assertEquals(LETTER_X, map.get(OFF_0_2));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBacktrackingHelpers() {
|
||||
var grid = createEmpty();
|
||||
var grid = new Gridded(createEmpty());
|
||||
// Slot at 0,1 length 2
|
||||
var key = Slot.packSlotKey(0, CLUE_RIGHT);
|
||||
var lo = (1L << OFF_0_1) | (1L << OFF_0_2);
|
||||
var w = AZ;
|
||||
val low = grid.lo;
|
||||
val top = grid.hi;
|
||||
var placed = placeWord(grid, key, lo, 0L, w);
|
||||
val low = grid.grid().lo;
|
||||
val top = grid.grid().hi;
|
||||
var placed = placeWord(grid.grid(), key, lo, 0L, w);
|
||||
assertTrue(placed);
|
||||
assertEquals(LETTER_A, grid.letter32At(OFF_0_1));
|
||||
assertEquals(LETTER_Z, grid.letter32At(OFF_0_2));
|
||||
var map = grid.stream(Clues.createEmpty()).collect(Collectors.toMap(LetterAt::index, LetterAt::letter));
|
||||
assertEquals(2, map.size());
|
||||
assertEquals(LETTER_A, map.get(OFF_0_1));
|
||||
assertEquals(LETTER_Z, map.get(OFF_0_2));
|
||||
|
||||
grid.hi = top;
|
||||
grid.lo = low;
|
||||
//grid.undoPlace(undoBuffer[0], undoBuffer[1]);
|
||||
assertFalse(grid.lisLetterAtLo(OFF_0_1));
|
||||
assertFalse(grid.lisLetterAtLo(OFF_0_2));
|
||||
grid.grid().hi = top;
|
||||
grid.grid().lo = low;
|
||||
map = grid.stream(Clues.createEmpty()).collect(Collectors.toMap(LetterAt::index, LetterAt::letter));
|
||||
assertEquals(0, map.size());
|
||||
assertEquals(DASH, map.getOrDefault(OFF_0_1, DASH));
|
||||
assertEquals(DASH, map.getOrDefault(OFF_0_2, DASH));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user