Gather data
This commit is contained in:
@@ -16,7 +16,7 @@ import java.util.stream.Collectors;
|
|||||||
|
|
||||||
import static puzzle.Export.*;
|
import static puzzle.Export.*;
|
||||||
import static puzzle.SwedishGenerator.*;
|
import static puzzle.SwedishGenerator.*;
|
||||||
import static puzzle.SwedishGenerator.loadWords;
|
import static puzzle.SwedishGenerator.Dict.loadDict;
|
||||||
|
|
||||||
public class Main {
|
public class Main {
|
||||||
|
|
||||||
@@ -244,11 +244,11 @@ public class Main {
|
|||||||
PuzzleResult generatePuzzle(Opts opts) {
|
PuzzleResult generatePuzzle(Opts opts) {
|
||||||
|
|
||||||
var tLoad0 = System.nanoTime();
|
var tLoad0 = System.nanoTime();
|
||||||
var dict = loadWords(opts.wordsPath);
|
var dict = loadDict(opts.wordsPath);
|
||||||
var tLoad1 = System.nanoTime();
|
var tLoad1 = System.nanoTime();
|
||||||
|
|
||||||
section("Load");
|
section("Load");
|
||||||
info(String.format(Locale.ROOT, "words : %,d", dict.dictLength() ));
|
info(String.format(Locale.ROOT, "words : %,d", dict.length() ));
|
||||||
info(String.format(Locale.ROOT, "loadTime : %.3f s", (tLoad1 - tLoad0) / 1e9));
|
info(String.format(Locale.ROOT, "loadTime : %.3f s", (tLoad1 - tLoad0) / 1e9));
|
||||||
|
|
||||||
section("Search");
|
section("Search");
|
||||||
@@ -332,7 +332,7 @@ public class Main {
|
|||||||
if (TOTAL_SUCCESS.get() > 0) {
|
if (TOTAL_SUCCESS.get() > 0) {
|
||||||
info(String.format(Locale.ROOT, "avgSimplic : %.2f", TOTAL_SIMPLICITY.get() / 100.0 / TOTAL_SUCCESS.get()));
|
info(String.format(Locale.ROOT, "avgSimplic : %.2f", TOTAL_SIMPLICITY.get() / 100.0 / TOTAL_SUCCESS.get()));
|
||||||
}
|
}
|
||||||
info(String.format(Locale.ROOT, "dictWords : %,d", dict.dictLength()));
|
info(String.format(Locale.ROOT, "dictWords : %,d", dict.length()));
|
||||||
|
|
||||||
return resFinal;
|
return resFinal;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,6 +32,9 @@ public record SwedishGenerator() {
|
|||||||
|
|
||||||
record CandidateInfo(int[] indices, int count) { }
|
record CandidateInfo(int[] indices, int count) { }
|
||||||
|
|
||||||
|
//@formatter:off
|
||||||
|
@FunctionalInterface interface SlotVisitor { void visit(int key, long packedPos, int len); }
|
||||||
|
//@formatter:on
|
||||||
static final int BAR_LEN = 22;
|
static final int BAR_LEN = 22;
|
||||||
static final int C = Config.PUZZLE_COLS;
|
static final int C = Config.PUZZLE_COLS;
|
||||||
static final double CROSS_Y = (C - 1) / 2.0;
|
static final double CROSS_Y = (C - 1) / 2.0;
|
||||||
@@ -193,11 +196,10 @@ public record SwedishGenerator() {
|
|||||||
double nextFloat() { return (nextU32() & 0xFFFFFFFFL) / 4294967295.0; }
|
double nextFloat() { return (nextU32() & 0xFFFFFFFFL) / 4294967295.0; }
|
||||||
}
|
}
|
||||||
|
|
||||||
static final byte _48 = 48;
|
|
||||||
|
|
||||||
record Grid(byte[] g, long[] bo) {
|
record Grid(byte[] g, long[] bo) {
|
||||||
|
|
||||||
public Grid(byte[] g) { this(g, new long[2]); }
|
public Grid(byte[] g) { this(g, new long[2]); }
|
||||||
|
static Grid createEmpty() { return new Grid(new byte[SIZE], new long[2]); }
|
||||||
int digitAt(int r, int c) { return g[offset(r, c)] - 48; }
|
int digitAt(int r, int c) { return g[offset(r, c)] - 48; }
|
||||||
int digitAt(int index) { return g[index] - 48; }
|
int digitAt(int index) { return g[index] - 48; }
|
||||||
public static int r(int offset) { return offset & 7; }
|
public static int r(int offset) { return offset & 7; }
|
||||||
@@ -245,7 +247,6 @@ public record SwedishGenerator() {
|
|||||||
for (var hi = bo[1]; hi != 0; hi &= hi - 1) processSlot(this, visitor, 64 + Long.numberOfTrailingZeros(hi));
|
for (var hi = bo[1]; hi != 0; hi &= hi - 1) processSlot(this, visitor, 64 + Long.numberOfTrailingZeros(hi));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
static Grid makeEmptyGrid() { return new Grid(new byte[SIZE], new long[2]); }
|
|
||||||
|
|
||||||
static final class IntList {
|
static final class IntList {
|
||||||
|
|
||||||
@@ -280,8 +281,9 @@ public record SwedishGenerator() {
|
|||||||
|
|
||||||
public static record Dict(
|
public static record Dict(
|
||||||
DictEntry[] index,
|
DictEntry[] index,
|
||||||
int[] lenCounts) {
|
int[] lenCounts, int length) {
|
||||||
|
|
||||||
|
static final Gson GSON = new Gson();
|
||||||
public Dict(Lemma[] wordz) {
|
public Dict(Lemma[] wordz) {
|
||||||
var lenCounts = new int[MAX_WORD_LENGTH_PLUS_ONE];
|
var lenCounts = new int[MAX_WORD_LENGTH_PLUS_ONE];
|
||||||
var index = new DictEntry[MAX_WORD_LENGTH_PLUS_ONE];
|
var index = new DictEntry[MAX_WORD_LENGTH_PLUS_ONE];
|
||||||
@@ -300,55 +302,62 @@ public record SwedishGenerator() {
|
|||||||
entry.pos[i][letter].add(idx);
|
entry.pos[i][letter].add(idx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this(index, lenCounts);
|
for (var len : lenCounts) {
|
||||||
}
|
if (len <= 0) {
|
||||||
public int dictLength() { return Arrays.stream(lenCounts).sum(); }
|
System.out.println("No words for length " + len);
|
||||||
}
|
//throw new RuntimeException("Invalid word length: " + len);
|
||||||
|
}
|
||||||
static final Gson GSON = new Gson();
|
|
||||||
static Dict loadWords(String wordsPath) {
|
|
||||||
String raw;
|
|
||||||
try {
|
|
||||||
raw = Files.readString(Path.of(wordsPath), StandardCharsets.UTF_8);
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
raw = "WOORD,level_1_to_10,hint\nEU,2,hint\nUUR,2,hint\nAUTO,2,hint\nBOOM,2,hint\nHUIS,2,hint\nKAT,2,hint\nZEE,2,hint\nRODE,2,hint\nDRAAD,2,hint\nKENNIS,2,hint\nNETWERK,2,hint\nPAKTE,2,hint\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
var map = new ArrayList<Lemma>();
|
|
||||||
var first = true;
|
|
||||||
for (var line : raw.split("\\R")) {
|
|
||||||
if (line.isBlank()) {
|
|
||||||
System.err.println("Empty line: " + line);
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
var parts = line.split(",", 4);
|
this(index, lenCounts, Arrays.stream(lenCounts).sum());
|
||||||
var word = parts[0].trim();
|
}
|
||||||
if (first && word.equalsIgnoreCase("WOORD")) {
|
static Dict loadDict(String wordsPath) {
|
||||||
|
String raw;
|
||||||
|
try {
|
||||||
|
raw = Files.readString(Path.of(wordsPath), StandardCharsets.UTF_8);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
raw = "WOORD,level_1_to_10,hint\nEU,2,hint\nUUR,2,hint\nAUTO,2,hint\nBOOM,2,hint\nHUIS,2,hint\nKAT,2,hint\nZEE,2,hint\nRODE,2,hint\nDRAAD,2,hint\nKENNIS,2,hint\nNETWERK,2,hint\nPAKTE,2,hint\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
var map = new ArrayList<Lemma>();
|
||||||
|
var first = true;
|
||||||
|
for (var line : raw.split("\\R")) {
|
||||||
|
if (line.isBlank()) {
|
||||||
|
System.err.println("Empty line: " + line);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
var parts = line.split(",", 4);
|
||||||
|
var word = parts[0].trim();
|
||||||
|
if (first && word.equalsIgnoreCase("WOORD")) {
|
||||||
|
first = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
first = false;
|
first = false;
|
||||||
continue;
|
var s = word.toUpperCase(Locale.ROOT);
|
||||||
}
|
if (!s.matches("^[A-Z]{2,8}$")) {
|
||||||
first = false;
|
System.err.println("Invalid word: " + line);
|
||||||
var s = word.toUpperCase(Locale.ROOT);
|
continue;
|
||||||
if (s.matches("^[A-Z]{2,8}$")) {
|
}
|
||||||
|
|
||||||
// CSV has level 1-10. llmScores use 10-level.
|
// CSV has level 1-10. llmScores use 10-level.
|
||||||
int score = 10 - Integer.parseInt(parts[1].trim());
|
int score = 10 - Integer.parseInt(parts[1].trim());
|
||||||
|
if (score < 1) {
|
||||||
|
if (Main.VERBOSE) System.err.println("Word too complex: " + line);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
int simpel = Integer.parseInt(parts[2].trim());
|
int simpel = Integer.parseInt(parts[2].trim());
|
||||||
var rawClue = parts[3].trim();
|
var rawClue = parts[3].trim();
|
||||||
if (rawClue.startsWith("\"") && rawClue.endsWith("\"")) {
|
if (rawClue.startsWith("\"") && rawClue.endsWith("\"")) {
|
||||||
rawClue = rawClue.substring(1, rawClue.length() - 1).replace("\"\"", "\"");
|
rawClue = rawClue.substring(1, rawClue.length() - 1).replace("\"\"", "\"");
|
||||||
}
|
}
|
||||||
if (score >= 1) {
|
map.add(new Lemma(s, simpel, GSON.fromJson(rawClue, String[].class)));
|
||||||
map.add(new Lemma(s, simpel, GSON.fromJson(rawClue, String[].class)));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
System.err.println("Invalid word: " + line);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return new Dict(map.toArray(Lemma[]::new));
|
return new Dict(map.toArray(Lemma[]::new));
|
||||||
|
}
|
||||||
|
public int dictLength() { return Arrays.stream(lenCounts).sum(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
static int intersectSorted(int[] a, int aLen, int[] b, int bLen, int[] out) {
|
static int intersectSorted(int[] a, int aLen, int[] b, int bLen, int[] out) {
|
||||||
int i = 0, j = 0, k = 0;
|
int i = 0, j = 0, k = 0;
|
||||||
while (i < aLen && j < bLen) {
|
while (i < aLen && j < bLen) {
|
||||||
@@ -367,6 +376,7 @@ public record SwedishGenerator() {
|
|||||||
static record Slot(int key, long packedPos) {
|
static record Slot(int key, long packedPos) {
|
||||||
|
|
||||||
static Slot from(int key, long packedPos, int len) { return new Slot(key, packedPos | ((long) len << 56)); }
|
static Slot from(int key, long packedPos, int len) { return new Slot(key, packedPos | ((long) len << 56)); }
|
||||||
|
void undoPlace(Grid grid, int mask) { for (int i = 0, len = len(); i < len; i++) if ((mask & (1L << i)) != 0) grid.clear(pos(i)); }
|
||||||
public int len() { return (int) (packedPos >>> 56); }
|
public int len() { return (int) (packedPos >>> 56); }
|
||||||
public int clueR() { return Grid.r((key >>> 4)); }
|
public int clueR() { return Grid.r((key >>> 4)); }
|
||||||
public int clueIndex() { return key >>> 4; }
|
public int clueIndex() { return key >>> 4; }
|
||||||
@@ -377,16 +387,8 @@ public record SwedishGenerator() {
|
|||||||
public static boolean horiz(int key) { return ((key & 15) & 1) == 0; }
|
public static boolean horiz(int key) { return ((key & 15) & 1) == 0; }
|
||||||
public static int offset(long packedPos, int i) { return (int) ((packedPos >> (i * 7)) & 127); }
|
public static int offset(long packedPos, int i) { return (int) ((packedPos >> (i * 7)) & 127); }
|
||||||
}
|
}
|
||||||
static void undoPlace(Grid grid, Slot s, int mask) {
|
|
||||||
for (int i = 0, len = s.len(); i < len; i++) if ((mask & (1L << i)) != 0) grid.clear(s.pos(i));
|
|
||||||
}
|
|
||||||
@FunctionalInterface
|
|
||||||
interface SlotVisitor {
|
|
||||||
|
|
||||||
void visit(int key, long packedPos, int len);
|
private static void processSlot(Grid grid, SwedishGenerator.SlotVisitor visitor, int idx) {
|
||||||
}
|
|
||||||
|
|
||||||
private static void processSlot(Grid grid, SlotVisitor visitor, int idx) {
|
|
||||||
var d = grid.digitAt(idx);
|
var d = grid.digitAt(idx);
|
||||||
var nbrs16 = OFFSETS[d];
|
var nbrs16 = OFFSETS[d];
|
||||||
int r = Grid.r(idx), c = Grid.c(idx), rr = r + nbrs16.r, cc = c + nbrs16.c;
|
int r = Grid.r(idx), c = Grid.c(idx), rr = r + nbrs16.r, cc = c + nbrs16.c;
|
||||||
@@ -546,7 +548,7 @@ public record SwedishGenerator() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Grid randomMask(Rng rng) {
|
Grid randomMask(Rng rng) {
|
||||||
var g = makeEmptyGrid();
|
var g = Grid.createEmpty();
|
||||||
int placed = 0, guard = 0;
|
int placed = 0, guard = 0;
|
||||||
|
|
||||||
while (placed < TARGET_CLUES && guard++ < 4000) {
|
while (placed < TARGET_CLUES && guard++ < 4000) {
|
||||||
@@ -583,7 +585,7 @@ public record SwedishGenerator() {
|
|||||||
return g;
|
return g;
|
||||||
}
|
}
|
||||||
Grid crossover(Rng rng, Grid a, Grid b) {
|
Grid crossover(Rng rng, Grid a, Grid b) {
|
||||||
var out = makeEmptyGrid();
|
var out = Grid.createEmpty();
|
||||||
var theta = rng.nextFloat() * Math.PI;
|
var theta = rng.nextFloat() * Math.PI;
|
||||||
var nx = Math.cos(theta);
|
var nx = Math.cos(theta);
|
||||||
var ny = Math.sin(theta);
|
var ny = Math.sin(theta);
|
||||||
@@ -877,7 +879,7 @@ public record SwedishGenerator() {
|
|||||||
|
|
||||||
assigned.remove(k);
|
assigned.remove(k);
|
||||||
used.clear(w.index);
|
used.clear(w.index);
|
||||||
undoPlace(grid, s, ctx.undo[depth]);
|
s.undoPlace(grid, ctx.undo[depth]);
|
||||||
}
|
}
|
||||||
stats.backtracks++;
|
stats.backtracks++;
|
||||||
return false;
|
return false;
|
||||||
@@ -913,7 +915,7 @@ public record SwedishGenerator() {
|
|||||||
|
|
||||||
assigned.remove(k);
|
assigned.remove(k);
|
||||||
used.clear(w.index);
|
used.clear(w.index);
|
||||||
undoPlace(grid, s, ctx.undo[depth]);
|
s.undoPlace(grid, ctx.undo[depth]);
|
||||||
}
|
}
|
||||||
|
|
||||||
stats.backtracks++;
|
stats.backtracks++;
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ public class ExportFormatTest {
|
|||||||
@Test
|
@Test
|
||||||
void testExportFormatFromFilled() {
|
void testExportFormatFromFilled() {
|
||||||
var swe = new SwedishGenerator();
|
var swe = new SwedishGenerator();
|
||||||
var grid = SwedishGenerator.makeEmptyGrid();
|
var grid = Grid.createEmpty();
|
||||||
|
|
||||||
// Place a '2' (right) at (0,0)
|
// Place a '2' (right) at (0,0)
|
||||||
grid.setClue(0, (byte) '2');
|
grid.setClue(0, (byte) '2');
|
||||||
@@ -76,7 +76,7 @@ public class ExportFormatTest {
|
|||||||
@Test
|
@Test
|
||||||
void testExportFormatEmpty() {
|
void testExportFormatEmpty() {
|
||||||
var swe = new SwedishGenerator();
|
var swe = new SwedishGenerator();
|
||||||
var grid = SwedishGenerator.makeEmptyGrid();
|
var grid = Grid.createEmpty();
|
||||||
var fillResult = new FillResult(true, new Gridded(grid), new HashMap<>(), null);
|
var fillResult = new FillResult(true, new Gridded(grid), new HashMap<>(), null);
|
||||||
var puzzleResult = new PuzzleResult(swe, null, null, fillResult);
|
var puzzleResult = new PuzzleResult(swe, null, null, fillResult);
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ public class MainTest {
|
|||||||
@Test
|
@Test
|
||||||
void testExtractSlots() {
|
void testExtractSlots() {
|
||||||
var generator = new SwedishGenerator();
|
var generator = new SwedishGenerator();
|
||||||
var grid = makeEmptyGrid();
|
var grid = Grid.createEmpty();
|
||||||
|
|
||||||
// Set up digits on the grid to create slots.
|
// Set up digits on the grid to create slots.
|
||||||
// '2' (right) at (0,0) -> slot at (0,1), (0,2)
|
// '2' (right) at (0,0) -> slot at (0,1), (0,2)
|
||||||
@@ -60,7 +60,7 @@ public class MainTest {
|
|||||||
@Test
|
@Test
|
||||||
void testForEachSlot() {
|
void testForEachSlot() {
|
||||||
var generator = new SwedishGenerator();
|
var generator = new SwedishGenerator();
|
||||||
var grid = makeEmptyGrid();
|
var grid = Grid.createEmpty();
|
||||||
grid.setClue(0, (byte) '2'); // right
|
grid.setClue(0, (byte) '2'); // right
|
||||||
|
|
||||||
var count = new AtomicInteger(0);
|
var count = new AtomicInteger(0);
|
||||||
@@ -82,7 +82,7 @@ public class MainTest {
|
|||||||
}
|
}
|
||||||
@Test
|
@Test
|
||||||
public void testGridBasics() {
|
public void testGridBasics() {
|
||||||
var grid = makeEmptyGrid();
|
var grid = Grid.createEmpty();
|
||||||
|
|
||||||
// Test set/get
|
// Test set/get
|
||||||
grid.setCharAt(0, 0, 'A');
|
grid.setCharAt(0, 0, 'A');
|
||||||
@@ -115,7 +115,7 @@ public class MainTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGridDeepCopy() {
|
public void testGridDeepCopy() {
|
||||||
var grid = makeEmptyGrid();
|
var grid = Grid.createEmpty();
|
||||||
grid.setCharAt(0, 0, 'A');
|
grid.setCharAt(0, 0, 'A');
|
||||||
grid.setCharAt(0, 1, 'B');
|
grid.setCharAt(0, 1, 'B');
|
||||||
grid.setCharAt(1, 0, 'C');
|
grid.setCharAt(1, 0, 'C');
|
||||||
@@ -131,7 +131,7 @@ public class MainTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testMini() {
|
public void testMini() {
|
||||||
var grid = makeEmptyGrid();
|
var grid = Grid.createEmpty();
|
||||||
grid.setCharAt(1, 1, '1');
|
grid.setCharAt(1, 1, '1');
|
||||||
Assertions.assertTrue(grid.isDigitAt(1, 1));
|
Assertions.assertTrue(grid.isDigitAt(1, 1));
|
||||||
}
|
}
|
||||||
@@ -148,7 +148,7 @@ public class MainTest {
|
|||||||
opts.tries = 1;
|
opts.tries = 1;
|
||||||
opts.verbose = false;
|
opts.verbose = false;
|
||||||
|
|
||||||
var dict = loadWords(opts.wordsPath);
|
var dict = Dict.loadDict(opts.wordsPath);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
PuzzleResult res = null;
|
PuzzleResult res = null;
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ public class SwedishGeneratorTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testGrid() {
|
void testGrid() {
|
||||||
var grid = SwedishGenerator.makeEmptyGrid();
|
var grid = Grid.createEmpty();
|
||||||
grid.setCharAt(0, 0, 'A');
|
grid.setCharAt(0, 0, 'A');
|
||||||
grid.setCharAt(0, 1, '1');
|
grid.setCharAt(0, 1, '1');
|
||||||
|
|
||||||
@@ -191,7 +191,7 @@ public class SwedishGeneratorTest {
|
|||||||
@Test
|
@Test
|
||||||
void testForEachSlotAndExtractSlots() {
|
void testForEachSlotAndExtractSlots() {
|
||||||
var gen = new SwedishGenerator();
|
var gen = new SwedishGenerator();
|
||||||
var grid = SwedishGenerator.makeEmptyGrid();
|
var grid = Grid.createEmpty();
|
||||||
// 3x3 grid (Config.PUZZLE_ROWS/COLS are 3 in test env)
|
// 3x3 grid (Config.PUZZLE_ROWS/COLS are 3 in test env)
|
||||||
// Set '2' (right) at 0,0
|
// Set '2' (right) at 0,0
|
||||||
grid.setClue(0, (byte) '2');
|
grid.setClue(0, (byte) '2');
|
||||||
@@ -219,7 +219,7 @@ public class SwedishGeneratorTest {
|
|||||||
@Test
|
@Test
|
||||||
void testMaskFitnessBasic() {
|
void testMaskFitnessBasic() {
|
||||||
var gen = new SwedishGenerator();
|
var gen = new SwedishGenerator();
|
||||||
var grid = SwedishGenerator.makeEmptyGrid();
|
var grid = Grid.createEmpty();
|
||||||
var lenCounts = new int[12];
|
var lenCounts = new int[12];
|
||||||
lenCounts[2] = 10;
|
lenCounts[2] = 10;
|
||||||
lenCounts[8] = 10; // In case MAX_WORD_LENGTH is 8
|
lenCounts[8] = 10; // In case MAX_WORD_LENGTH is 8
|
||||||
@@ -257,7 +257,7 @@ public class SwedishGeneratorTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testPlaceWord() {
|
void testPlaceWord() {
|
||||||
var grid = SwedishGenerator.makeEmptyGrid();
|
var grid = Grid.createEmpty();
|
||||||
// Slot at (0,0) length 3, horizontal (right)
|
// Slot at (0,0) length 3, horizontal (right)
|
||||||
// key = (r << 8) | (c << 4) | d. Here we just need a valid slot for placeWord.
|
// key = (r << 8) | (c << 4) | d. Here we just need a valid slot for placeWord.
|
||||||
// r(i) and c(i) are used by placeWord.
|
// r(i) and c(i) are used by placeWord.
|
||||||
@@ -286,7 +286,7 @@ public class SwedishGeneratorTest {
|
|||||||
assertEquals('C', grid.byteAt(0, 2));
|
assertEquals('C', grid.byteAt(0, 2));
|
||||||
|
|
||||||
// 4. Partial placement then conflict (rollback)
|
// 4. Partial placement then conflict (rollback)
|
||||||
grid = SwedishGenerator.makeEmptyGrid();
|
grid = Grid.createEmpty();
|
||||||
grid.setCharAt(0, 2, 'X'); // Conflict at the end
|
grid.setCharAt(0, 2, 'X'); // Conflict at the end
|
||||||
assertFalse(SwedishGenerator.placeWord(grid, s, w1, undoBuffer, 3));
|
assertFalse(SwedishGenerator.placeWord(grid, s, w1, undoBuffer, 3));
|
||||||
// Verify grid is still empty (except for 'X')
|
// Verify grid is still empty (except for 'X')
|
||||||
@@ -297,7 +297,7 @@ public class SwedishGeneratorTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testBacktrackingHelpers() {
|
void testBacktrackingHelpers() {
|
||||||
var grid = SwedishGenerator.makeEmptyGrid();
|
var grid = Grid.createEmpty();
|
||||||
// Slot at 0,1 length 2
|
// Slot at 0,1 length 2
|
||||||
var packedPos = ((long) Grid.offset(0, 1)) | (((long) Grid.offset(0, 2)) << 7);
|
var packedPos = ((long) Grid.offset(0, 1)) | (((long) Grid.offset(0, 2)) << 7);
|
||||||
var s = Slot.from((0 << 8) | (1 << 4) | 2, packedPos, 2);
|
var s = Slot.from((0 << 8) | (1 << 4) | 2, packedPos, 2);
|
||||||
@@ -310,7 +310,7 @@ public class SwedishGeneratorTest {
|
|||||||
assertEquals('Z', grid.byteAt(0, 2));
|
assertEquals('Z', grid.byteAt(0, 2));
|
||||||
assertEquals(0b11L, undoBuffer[0]);
|
assertEquals(0b11L, undoBuffer[0]);
|
||||||
|
|
||||||
SwedishGenerator.undoPlace(grid, s, undoBuffer[0]);
|
s.undoPlace(grid, undoBuffer[0]);
|
||||||
assertEquals(SwedishGenerator.DASH, grid.byteAt(0, 1));
|
assertEquals(SwedishGenerator.DASH, grid.byteAt(0, 1));
|
||||||
assertEquals(SwedishGenerator.DASH, grid.byteAt(0, 2));
|
assertEquals(SwedishGenerator.DASH, grid.byteAt(0, 2));
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user