4 Commits

Author SHA1 Message Date
947a875694 yes
Some checks failed
Linux arm64 / Build (push) Failing after 29s
2025-02-02 20:32:41 +01:00
1246331125 moi
Some checks failed
Linux arm64 / Build (push) Failing after 28s
2025-02-02 20:31:28 +01:00
b68fe81914 aaaaaaaaaaaaaaaaaaaaaaaaaaaa
All checks were successful
Linux arm64 / Build (push) Successful in 32s
2025-02-02 20:17:54 +01:00
9c72891048 aaaaa
Some checks failed
Linux arm64 / Build (push) Failing after 31s
2025-02-02 19:34:21 +01:00
10 changed files with 1290 additions and 85 deletions

551
app/save/save-1.json Normal file
View File

@@ -0,0 +1,551 @@
{
"cells": [
{
"blockID": 0,
"symbolIndex": -1
},
{
"blockID": 0,
"symbolIndex": -1
},
{
"blockID": 0,
"symbolIndex": -1
},
{
"blockID": 1,
"symbolIndex": -1
},
{
"blockID": 1,
"immutable": true,
"symbolIndex": 2
},
{
"blockID": 1,
"symbolIndex": -1
},
{
"blockID": 2,
"immutable": true,
"symbolIndex": 1
},
{
"blockID": 2,
"symbolIndex": -1
},
{
"blockID": 2,
"symbolIndex": -1
},
{
"blockID": 0,
"immutable": true,
"symbolIndex": 8
},
{
"blockID": 0,
"immutable": true,
"symbolIndex": 2
},
{
"blockID": 0,
"symbolIndex": -1
},
{
"blockID": 1,
"symbolIndex": -1
},
{
"blockID": 1,
"immutable": true,
"symbolIndex": 0
},
{
"blockID": 1,
"symbolIndex": -1
},
{
"blockID": 2,
"symbolIndex": -1
},
{
"blockID": 2,
"symbolIndex": -1
},
{
"blockID": 2,
"symbolIndex": -1
},
{
"blockID": 0,
"immutable": true,
"symbolIndex": 5
},
{
"blockID": 0,
"symbolIndex": -1
},
{
"blockID": 0,
"symbolIndex": -1
},
{
"blockID": 1,
"symbolIndex": -1
},
{
"blockID": 1,
"symbolIndex": -1
},
{
"blockID": 1,
"symbolIndex": -1
},
{
"blockID": 2,
"symbolIndex": -1
},
{
"blockID": 2,
"immutable": true,
"symbolIndex": 8
},
{
"blockID": 2,
"symbolIndex": -1
},
{
"blockID": 3,
"symbolIndex": -1
},
{
"blockID": 3,
"symbolIndex": -1
},
{
"blockID": 3,
"immutable": true,
"symbolIndex": 1
},
{
"blockID": 4,
"immutable": true,
"symbolIndex": 5
},
{
"blockID": 4,
"immutable": true,
"symbolIndex": 6
},
{
"blockID": 4,
"immutable": true,
"symbolIndex": 0
},
{
"blockID": 5,
"symbolIndex": -1
},
{
"blockID": 5,
"immutable": true,
"symbolIndex": 3
},
{
"blockID": 5,
"symbolIndex": -1
},
{
"blockID": 3,
"symbolIndex": -1
},
{
"blockID": 3,
"symbolIndex": -1
},
{
"blockID": 3,
"symbolIndex": -1
},
{
"blockID": 4,
"symbolIndex": -1
},
{
"blockID": 4,
"immutable": true,
"symbolIndex": 7
},
{
"blockID": 4,
"symbolIndex": -1
},
{
"blockID": 5,
"symbolIndex": -1
},
{
"blockID": 5,
"symbolIndex": -1
},
{
"blockID": 5,
"symbolIndex": -1
},
{
"blockID": 3,
"symbolIndex": -1
},
{
"blockID": 3,
"symbolIndex": -1
},
{
"blockID": 3,
"symbolIndex": -1
},
{
"blockID": 4,
"symbolIndex": -1
},
{
"blockID": 4,
"symbolIndex": -1
},
{
"blockID": 4,
"symbolIndex": -1
},
{
"blockID": 5,
"symbolIndex": -1
},
{
"blockID": 5,
"symbolIndex": -1
},
{
"blockID": 5,
"symbolIndex": -1
},
{
"blockID": 6,
"symbolIndex": -1
},
{
"blockID": 6,
"immutable": true,
"symbolIndex": 6
},
{
"blockID": 6,
"symbolIndex": -1
},
{
"blockID": 7,
"symbolIndex": -1
},
{
"blockID": 7,
"symbolIndex": -1
},
{
"blockID": 7,
"symbolIndex": -1
},
{
"blockID": 8,
"immutable": true,
"symbolIndex": 8
},
{
"blockID": 8,
"symbolIndex": -1
},
{
"blockID": 8,
"symbolIndex": -1
},
{
"blockID": 6,
"symbolIndex": -1
},
{
"blockID": 6,
"symbolIndex": -1
},
{
"blockID": 6,
"symbolIndex": -1
},
{
"blockID": 7,
"immutable": true,
"symbolIndex": 4
},
{
"blockID": 7,
"symbolIndex": -1
},
{
"blockID": 7,
"symbolIndex": -1
},
{
"blockID": 8,
"immutable": true,
"symbolIndex": 6
},
{
"blockID": 8,
"immutable": true,
"symbolIndex": 7
},
{
"blockID": 8,
"symbolIndex": -1
},
{
"blockID": 6,
"immutable": true,
"symbolIndex": 0
},
{
"blockID": 6,
"symbolIndex": -1
},
{
"blockID": 6,
"symbolIndex": -1
},
{
"blockID": 7,
"symbolIndex": -1
},
{
"blockID": 7,
"symbolIndex": -1
},
{
"blockID": 7,
"symbolIndex": -1
},
{
"blockID": 8,
"immutable": true,
"symbolIndex": 3
},
{
"blockID": 8,
"symbolIndex": -1
},
{
"blockID": 8,
"symbolIndex": -1
}
],
"blocks": [
{"cellIDs": [
0,
1,
2,
9,
10,
11,
18,
19,
20
]},
{"cellIDs": [
3,
4,
5,
12,
13,
14,
21,
22,
23
]},
{"cellIDs": [
6,
7,
8,
15,
16,
17,
24,
25,
26
]},
{"cellIDs": [
27,
28,
29,
36,
37,
38,
45,
46,
47
]},
{"cellIDs": [
30,
31,
32,
39,
40,
41,
48,
49,
50
]},
{"cellIDs": [
33,
34,
35,
42,
43,
44,
51,
52,
53
]},
{"cellIDs": [
54,
55,
56,
63,
64,
65,
72,
73,
74
]},
{"cellIDs": [
57,
58,
59,
66,
67,
68,
75,
76,
77
]},
{"cellIDs": [
60,
61,
62,
69,
70,
71,
78,
79,
80
]}
],
"multidoku": [{
"blockWidth": 3,
"cells": [
0,
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25,
26,
27,
28,
29,
30,
31,
32,
33,
34,
35,
36,
37,
38,
39,
40,
41,
42,
43,
44,
45,
46,
47,
48,
49,
50,
51,
52,
53,
54,
55,
56,
57,
58,
59,
60,
61,
62,
63,
64,
65,
66,
67,
68,
69,
70,
71,
72,
73,
74,
75,
76,
77,
78,
79,
80
],
"blocks": [
0,
1,
2,
3,
4,
5,
6,
7,
8
],
"constraints": [
0,
1,
2
]
}]
}

554
app/save/save.json Normal file
View File

@@ -0,0 +1,554 @@
{
"cells": [
{
"blockID": 0,
"immutable": true,
"symbolIndex": 5
},
{
"blockID": 0,
"symbolIndex": -1
},
{
"blockID": 0,
"immutable": true,
"symbolIndex": 6
},
{
"blockID": 1,
"immutable": true,
"symbolIndex": 7
},
{
"blockID": 1,
"symbolIndex": -1
},
{
"blockID": 1,
"immutable": true,
"symbolIndex": 1
},
{
"blockID": 2,
"symbolIndex": -1
},
{
"blockID": 2,
"symbolIndex": -1
},
{
"blockID": 2,
"symbolIndex": -1
},
{
"blockID": 0,
"symbolIndex": -1
},
{
"blockID": 0,
"symbolIndex": -1
},
{
"blockID": 0,
"symbolIndex": -1
},
{
"blockID": 1,
"symbolIndex": -1
},
{
"blockID": 1,
"immutable": true,
"symbolIndex": 2
},
{
"blockID": 1,
"symbolIndex": -1
},
{
"blockID": 2,
"symbolIndex": -1
},
{
"blockID": 2,
"symbolIndex": -1
},
{
"blockID": 2,
"symbolIndex": -1
},
{
"blockID": 0,
"symbolIndex": -1
},
{
"blockID": 0,
"immutable": true,
"symbolIndex": 4
},
{
"blockID": 0,
"symbolIndex": -1
},
{
"blockID": 1,
"symbolIndex": -1
},
{
"blockID": 1,
"symbolIndex": -1
},
{
"blockID": 1,
"immutable": true,
"symbolIndex": 8
},
{
"blockID": 2,
"immutable": true,
"symbolIndex": 7
},
{
"blockID": 2,
"symbolIndex": -1
},
{
"blockID": 2,
"symbolIndex": -1
},
{
"blockID": 3,
"immutable": true,
"symbolIndex": 6
},
{
"blockID": 3,
"symbolIndex": -1
},
{
"blockID": 3,
"symbolIndex": -1
},
{
"blockID": 4,
"symbolIndex": -1
},
{
"blockID": 4,
"symbolIndex": -1
},
{
"blockID": 4,
"symbolIndex": -1
},
{
"blockID": 5,
"immutable": true,
"symbolIndex": 8
},
{
"blockID": 5,
"symbolIndex": -1
},
{
"blockID": 5,
"symbolIndex": -1
},
{
"blockID": 3,
"immutable": true,
"symbolIndex": 1
},
{
"blockID": 3,
"immutable": true,
"symbolIndex": 2
},
{
"blockID": 3,
"symbolIndex": -1
},
{
"blockID": 4,
"symbolIndex": -1
},
{
"blockID": 4,
"symbolIndex": -1
},
{
"blockID": 4,
"symbolIndex": -1
},
{
"blockID": 5,
"symbolIndex": -1
},
{
"blockID": 5,
"symbolIndex": -1
},
{
"blockID": 5,
"immutable": true,
"symbolIndex": 6
},
{
"blockID": 3,
"immutable": true,
"symbolIndex": 8
},
{
"blockID": 3,
"symbolIndex": -1
},
{
"blockID": 3,
"symbolIndex": -1
},
{
"blockID": 4,
"symbolIndex": -1
},
{
"blockID": 4,
"immutable": true,
"symbolIndex": 0
},
{
"blockID": 4,
"symbolIndex": -1
},
{
"blockID": 5,
"symbolIndex": -1
},
{
"blockID": 5,
"symbolIndex": -1
},
{
"blockID": 5,
"symbolIndex": -1
},
{
"blockID": 6,
"symbolIndex": -1
},
{
"blockID": 6,
"immutable": true,
"symbolIndex": 5
},
{
"blockID": 6,
"symbolIndex": -1
},
{
"blockID": 7,
"symbolIndex": -1
},
{
"blockID": 7,
"immutable": true,
"symbolIndex": 1
},
{
"blockID": 7,
"symbolIndex": -1
},
{
"blockID": 8,
"symbolIndex": -1
},
{
"blockID": 8,
"immutable": true,
"symbolIndex": 7
},
{
"blockID": 8,
"symbolIndex": -1
},
{
"blockID": 6,
"symbolIndex": -1
},
{
"blockID": 6,
"immutable": true,
"symbolIndex": 8
},
{
"blockID": 6,
"symbolIndex": -1
},
{
"blockID": 7,
"symbolIndex": -1
},
{
"blockID": 7,
"symbolIndex": -1
},
{
"blockID": 7,
"immutable": true,
"symbolIndex": 6
},
{
"blockID": 8,
"symbolIndex": -1
},
{
"blockID": 8,
"symbolIndex": -1
},
{
"blockID": 8,
"symbolIndex": -1
},
{
"blockID": 6,
"symbolIndex": -1
},
{
"blockID": 6,
"symbolIndex": -1
},
{
"blockID": 6,
"symbolIndex": -1
},
{
"blockID": 7,
"immutable": true,
"symbolIndex": 4
},
{
"blockID": 7,
"immutable": true,
"symbolIndex": 5
},
{
"blockID": 7,
"immutable": true,
"symbolIndex": 0
},
{
"blockID": 8,
"symbolIndex": -1
},
{
"blockID": 8,
"symbolIndex": -1
},
{
"blockID": 8,
"symbolIndex": -1
}
],
"blocks": [
{"cellIDs": [
0,
1,
2,
9,
10,
11,
18,
19,
20
]},
{"cellIDs": [
3,
4,
5,
12,
13,
14,
21,
22,
23
]},
{"cellIDs": [
6,
7,
8,
15,
16,
17,
24,
25,
26
]},
{"cellIDs": [
27,
28,
29,
36,
37,
38,
45,
46,
47
]},
{"cellIDs": [
30,
31,
32,
39,
40,
41,
48,
49,
50
]},
{"cellIDs": [
33,
34,
35,
42,
43,
44,
51,
52,
53
]},
{"cellIDs": [
54,
55,
56,
63,
64,
65,
72,
73,
74
]},
{"cellIDs": [
57,
58,
59,
66,
67,
68,
75,
76,
77
]},
{"cellIDs": [
60,
61,
62,
69,
70,
71,
78,
79,
80
]}
],
"multidoku": [{
"blockWidth": 3,
"cells": [
0,
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25,
26,
27,
28,
29,
30,
31,
32,
33,
34,
35,
36,
37,
38,
39,
40,
41,
42,
43,
44,
45,
46,
47,
48,
49,
50,
51,
52,
53,
54,
55,
56,
57,
58,
59,
60,
61,
62,
63,
64,
65,
66,
67,
68,
69,
70,
71,
72,
73,
74,
75,
76,
77,
78,
79,
80
],
"blocks": [
0,
1,
2,
3,
4,
5,
6,
7,
8
],
"constraints": [
0,
1,
2
]
}]
}

View File

@@ -15,6 +15,7 @@ import sudoku.constraint.IConstraint;
import sudoku.structure.Difficulty; import sudoku.structure.Difficulty;
import sudoku.structure.MultiDoku; import sudoku.structure.MultiDoku;
import sudoku.structure.SudokuFactory; import sudoku.structure.SudokuFactory;
import sudoku.structure.SudokuFiller;
public class SudokuSelector { public class SudokuSelector {
@@ -86,7 +87,8 @@ public class SudokuSelector {
this.genThread = new Thread(() -> { this.genThread = new Thread(() -> {
try { try {
if (!empty) { if (!empty) {
SudokuFactory.fillDoku(doku, Difficulty.values()[difficulty.get()]); SudokuFiller.fillDoku(doku, Difficulty.values()[difficulty.get()]);
// SudokuFactory.fillDoku(doku, Difficulty.values()[difficulty.get()]);
} }
this.onSelect.emit(this.doku); this.onSelect.emit(this.doku);
} catch (Exception e) { } catch (Exception e) {

View File

@@ -1,13 +1,13 @@
package sudoku.io; package sudoku.io;
import java.util.List;
import gui.RenderableMultidoku; import gui.RenderableMultidoku;
import gui.constants.Symbols; import gui.constants.Symbols;
import sudoku.structure.Cell; import sudoku.structure.Cell;
import sudoku.structure.MultiDoku; import sudoku.structure.MultiDoku;
import sudoku.structure.Sudoku; import sudoku.structure.Sudoku;
import java.util.List;
public class SudokuPrinter { public class SudokuPrinter {
public static final String ANSI_RESET = "\u001B[0m"; public static final String ANSI_RESET = "\u001B[0m";
public static final String ANSI_RED = "\u001B[31m"; public static final String ANSI_RED = "\u001B[31m";
@@ -47,7 +47,7 @@ public class SudokuPrinter {
List<String> listSymbols) { List<String> listSymbols) {
StringBuilder header = new StringBuilder(""); StringBuilder header = new StringBuilder("");
header.append(" "); header.append(" ");
for (int x = 0; x < blockWidth * blockHeight; x++) { for (int x = 0; x < blockWidth*blockHeight; x++) {
header.append(x + 1).append(" "); header.append(x + 1).append(" ");
if (x % blockWidth == blockWidth - 1 && x != blockWidth * blockHeight - 1) { if (x % blockWidth == blockWidth - 1 && x != blockWidth * blockHeight - 1) {
header.append(" "); header.append(" ");
@@ -77,12 +77,11 @@ public class SudokuPrinter {
} }
} }
public static String printMultiDoku(final RenderableMultidoku rm, Symbols symbols, int blockWidth, public static void printMultiDoku(final RenderableMultidoku rm, Symbols symbols, int blockWidth, int blockHeight) {
int blockHeight) { printMultiDoku(rm, symbols.getSymbols(), blockWidth, blockHeight);
return printMultiDoku(rm, symbols.getSymbols(), blockWidth, blockHeight);
} }
public static String printMultiDoku(final RenderableMultidoku rm, List<String> listSymbols, int blockWidth, public static void printMultiDoku(final RenderableMultidoku rm, List<String> listSymbols, int blockWidth,
int blockHeight) { int blockHeight) {
StringBuilder line = new StringBuilder("\n"); StringBuilder line = new StringBuilder("\n");
int nBlockInWidth = rm.getWidth() / blockWidth; int nBlockInWidth = rm.getWidth() / blockWidth;
@@ -109,8 +108,7 @@ public class SudokuPrinter {
line.append("]\n"); line.append("]\n");
} }
line.append("__".repeat(Math.max(0, rm.getWidth() + nBlockInWidth))).append("_\n"); line.append("__".repeat(Math.max(0, rm.getWidth() + nBlockInWidth))).append("_\n");
// System.out.println(line); System.out.println(line);
return line.toString();
} }
public static void printMultiDokuWithIndex(final RenderableMultidoku rm, List<String> listSymbols, int blockWidth, public static void printMultiDokuWithIndex(final RenderableMultidoku rm, List<String> listSymbols, int blockWidth,
@@ -129,7 +127,7 @@ public class SudokuPrinter {
if (y % blockHeight == 0) { if (y % blockHeight == 0) {
line.append(" ").append("__".repeat(Math.max(0, rm.getWidth() + nBlockInWidth))).append("_\n"); line.append(" ").append("__".repeat(Math.max(0, rm.getWidth() + nBlockInWidth))).append("_\n");
} }
line.append(y + 1).append(" [ "); line.append(y+1).append(" [ ");
for (int x = 0; x < rm.getWidth(); x++) { for (int x = 0; x < rm.getWidth(); x++) {
if (x % blockWidth == 0 && x > 0) { if (x % blockWidth == 0 && x > 0) {
line.append("| "); line.append("| ");
@@ -184,16 +182,12 @@ public class SudokuPrinter {
return result.toString(); return result.toString();
} }
public static String printMultiDoku(final MultiDoku doku) { public static void printMultiDoku(final MultiDoku doku, int blockWidth, int blockHeight, Symbols symbols) {
int blockWidth = doku.getSubGrid(0).getBlockWidth(); if (doku.getNbSubGrids() == 1) {
if (blockWidth == 0) printRectangleSudoku(doku.getSubGrid(0), blockWidth, blockHeight, symbols);
return printMultiDoku(doku, 0, 0, Symbols.Numbers); } else {
else printMultiDoku(RenderableMultidoku.fromMultidoku(doku), symbols, blockWidth, blockHeight);
return printMultiDoku(doku, blockWidth, doku.getSubGrid(0).getSize() / blockWidth, Symbols.Letters); }
}
public static String printMultiDoku(final MultiDoku doku, int blockWidth, int blockHeight, Symbols symbols) {
return printMultiDoku(RenderableMultidoku.fromMultidoku(doku), symbols, blockWidth, blockHeight);
} }
public static void printMultiDokuWithIndex(final MultiDoku doku, int blockWidth, int blockHeight, Symbols symbols) { public static void printMultiDokuWithIndex(final MultiDoku doku, int blockWidth, int blockHeight, Symbols symbols) {

View File

@@ -1,5 +1,6 @@
package sudoku.solver; package sudoku.solver;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.concurrent.CancellationException; import java.util.concurrent.CancellationException;
@@ -8,17 +9,27 @@ import sudoku.structure.MultiDoku;
public class MixedSolver implements Solver { public class MixedSolver implements Solver {
private Cell findCellToBacktrack(MultiDoku doku, int maxPossibilities) { private List<Cell> findCellToBacktrack(MultiDoku doku, int maxPossibilities) {
int symbolCount = doku.getSubGrid(0).getSize();
if (maxPossibilities > symbolCount)
return null;
List<Cell> backtrackCells = new ArrayList<>();
for (Cell cell : doku.getCells()) { for (Cell cell : doku.getCells()) {
if (!cell.isMutable() || !cell.isEmpty()) if (!cell.isMutable() || !cell.isEmpty())
continue; continue;
List<Integer> possibleSymbols = cell.getPossibleSymbols(); List<Integer> possibleSymbols = cell.getPossibleSymbols();
if (possibleSymbols.size() == maxPossibilities) { if (possibleSymbols.size() == maxPossibilities) {
return cell; backtrackCells.add(cell);
} }
// grille non résolvable
if (possibleSymbols.size() == 0)
return null;
} }
return null; return backtrackCells;
} }
/** /**
@@ -34,41 +45,55 @@ public class MixedSolver implements Solver {
throw new CancellationException("User wants to stop the solver"); throw new CancellationException("User wants to stop the solver");
} }
while (!doku.isSolved()) { if (doku.isSolved())
boolean filledCell = false; return true;
for (Cell cell : doku.getCells()) {
if (!cell.isMutable() || !cell.isEmpty())
continue;
List<Integer> possibleSymbols = cell.getPossibleSymbols(); int symbolCount = doku.getSubGrid(0).getSize();
if (possibleSymbols.size() == 1) {
cell.setSymbolIndex(possibleSymbols.getFirst());
addStep(cell, steps);
filledCell = true;
}
}
// on ne peut plus remplir de cases, on tente de backtrack
if (!filledCell) {
int maxPossibilities = 2;
Cell backtrackCell = null;
while (backtrackCell == null) {
backtrackCell = findCellToBacktrack(doku, maxPossibilities);
maxPossibilities++;
}
// on fait du backtracking
List<Integer> possibilities = backtrackCell.getPossibleSymbols();
for (int symbol : possibilities) {
doku.getStateManager().pushState();
backtrackCell.setSymbolIndex(symbol);
if (solve(doku, steps))
return true;
doku.getStateManager().popState();
}
}
// on remplit les cases par déduction
for (Cell cell : doku.getCells()) {
if (!cell.isMutable() || !cell.isEmpty())
continue;
List<Integer> possibleSymbols = cell.getPossibleSymbols();
if (possibleSymbols.size() == 1) {
cell.setSymbolIndex(possibleSymbols.getFirst());
addStep(cell, steps);
if (solve(doku, steps))
return true;
cell.setSymbolIndex(Cell.NOSYMBOL);
return false;
}
} }
return true; // on ne peut plus remplir de cases, on tente de backtrack
for (int maxPossibilities = 2; maxPossibilities <= symbolCount; maxPossibilities++) {
List<Cell> backtrackCells = new ArrayList<>();
while (backtrackCells.isEmpty()) {
backtrackCells = findCellToBacktrack(doku, maxPossibilities);
// grille non résolvable
if (backtrackCells == null) {
return false;
}
maxPossibilities++;
}
// on fait du backtracking
for (Cell backtrackCell : backtrackCells) {
List<Integer> possibilities = backtrackCell.getPossibleSymbols();
// System.out.println("Backtraing on " + backtrackCell);
// on tente de placer chacun des symboles
for (int symbol : possibilities) {
backtrackCell.setSymbolIndex(symbol);
if (solve(doku, steps)) {
return true;
}
}
backtrackCell.setSymbolIndex(Cell.NOSYMBOL);
}
}
return doku.isSolved();
} }
} }

View File

@@ -1,6 +1,5 @@
package sudoku.structure; package sudoku.structure;
import sudoku.io.SudokuPrinter;
import sudoku.io.SudokuSerializer; import sudoku.io.SudokuSerializer;
import java.util.ArrayList; import java.util.ArrayList;
@@ -183,7 +182,7 @@ public class MultiDoku {
if (sudoku.getSize() != otherSudoku.getSize()) if (sudoku.getSize() != otherSudoku.getSize())
return false; return false;
for (int j = 0; j < sudoku.getSize() * sudoku.getSize(); j++) { for (int j = 0; j < sudoku.getSize() * sudoku.getSize(); j++) {
if (sudoku.getCell(j).getSymbolIndex() != otherSudoku.getCell(j).getSymbolIndex()) if (sudoku.getCell(i).getSymbolIndex() != otherSudoku.getCell(i).getSymbolIndex())
return false; return false;
} }
} }
@@ -192,7 +191,13 @@ public class MultiDoku {
@Override @Override
public String toString() { public String toString() {
return SudokuPrinter.printMultiDoku(this); StringBuilder sb = new StringBuilder();
sb.append("Multidoku {");
for (Sudoku sudoku : subGrids) {
sb.append("\n\t").append(sudoku.toString());
}
sb.append("\n}");
return sb.toString();
} }
public MultiDoku clone() { public MultiDoku clone() {

View File

@@ -25,6 +25,10 @@ public class StateManager {
this.doku = doku; this.doku = doku;
} }
public void forgetState() {
states.pop();
}
public Map<Cell, Integer> pushState() { public Map<Cell, Integer> pushState() {
states.add(saveState()); states.add(saveState());
return states.getLast(); return states.getLast();
@@ -42,7 +46,7 @@ public class StateManager {
return currentState; return currentState;
} }
private void restoreState(Map<Cell, Integer> state) { public void restoreState(Map<Cell, Integer> state) {
for (var entry : state.entrySet()) { for (var entry : state.entrySet()) {
entry.getKey().setSymbolIndex(entry.getValue()); entry.getKey().setSymbolIndex(entry.getValue());
} }

View File

@@ -328,7 +328,7 @@ public class SudokuFactory {
} }
/** /**
* Remplit un MultiDoku donné par rapport à une difficulté. * Rempli un MultiDoku donné par rapport à un difficulté.
* *
* @param doku MultiDoku, vide. * @param doku MultiDoku, vide.
* @param difficulty Difficulty, qui correspond au pourcentage de cases à enlever. * @param difficulty Difficulty, qui correspond au pourcentage de cases à enlever.

View File

@@ -0,0 +1,78 @@
package sudoku.structure;
import java.util.List;
import java.util.Random;
import sudoku.solver.BacktrackingSolver;
import sudoku.solver.HumanSolver;
import sudoku.solver.MixedSolver;
import sudoku.solver.RandomSolver;
import sudoku.solver.Solver;
public class SudokuFiller {
private static boolean isPossiblySolvable(MultiDoku doku) {
for (Cell cell : doku.getEmptyCells()) {
if (cell.getPossibleSymbols().size() == 0)
return false;
}
return true;
}
private static void tryFillRandomCells(MultiDoku doku) {
Random r = new Random();
while (isPossiblySolvable(doku)) {
int cellCount = doku.getEmptyCells().size();
if (cellCount == 0)
return;
Cell cellToFill = doku.getEmptyCells().get(r.nextInt(cellCount));
if (!cellToFill.isEmpty() || !cellToFill.isMutable())
continue;
List<Integer> possibleSymbols = cellToFill.getPossibleSymbols();
int symbolCount = possibleSymbols.size();
// la cellule n'a pas de valeur possible
if (symbolCount == 0)
return;
cellToFill.setSymbolIndex(possibleSymbols.get(r.nextInt(symbolCount)));
}
}
private static void removeRandomCell(MultiDoku doku) {
Random r = new Random();
int cellCount = doku.getFilledCells().size();
doku.getFilledCells().get(r.nextInt(cellCount)).clearCurrentSymbol();
}
private static void makeSolvable(MultiDoku doku) {
while (!isPossiblySolvable(doku)) {
removeRandomCell(doku);
}
Solver solver = new BacktrackingSolver();
boolean solvable = false;
while (!solvable) {
removeRandomCell(doku);
doku.getStateManager().pushState();
solvable = solver.solve(doku);
doku.getStateManager().popState();
System.out.println("eeeeeeeeeeeee");
}
}
private static void fillDoku(MultiDoku doku) {
tryFillRandomCells(doku);
makeSolvable(doku);
}
private static void setCellsImmutable(MultiDoku doku) {
for (Cell cell : doku.getFilledCells())
cell.setImmutable();
}
public static void fillDoku(MultiDoku doku, Difficulty difficulty) {
fillDoku(doku);
setCellsImmutable(doku);
}
}

View File

@@ -42,12 +42,12 @@ class SolverTest {
ns, 0, 1, ns); ns, 0, 1, ns);
assertTrue(test.setImmutableCellsSymbol(immutableCells)); assertTrue(test.setImmutableCellsSymbol(immutableCells));
List<Integer> correctCells = List.of( List<Integer> correctCells = List.of(
1, 2, 3, 0, 1, 2, 3, 0,
0, 3, 2, 1, 0, 3, 2, 1,
2, 1, 0, 3, 2, 1, 0, 3,
3, 0, 1, 2); 3, 0, 1, 2);
assertTrue(result.setCellsSymbol(correctCells)); assertTrue(result.setCellsSymbol(correctCells));
assertTrue(result.isSolved()); assertTrue(result.isSolved());
assertNotEquals(mdResult, mdTest); assertNotEquals(mdResult, mdTest);
solver.solve(mdTest); solver.solve(mdTest);
@@ -101,32 +101,24 @@ class SolverTest {
MultiDoku mdResult = SudokuSerializer.deserializeSudoku(SudokuSerializer.serializeSudoku(mdTest)); MultiDoku mdResult = SudokuSerializer.deserializeSudoku(SudokuSerializer.serializeSudoku(mdTest));
assertFalse(mdTest.isSolved()); assertFalse(mdTest.isSolved());
assertFalse(mdResult.isSolved()); assertFalse(mdResult.isSolved());
assertEquals(mdTest, mdResult);
assertTrue(solver.solve(mdTest)); assertTrue(solver.solve(mdTest));
assertTrue(mdTest.isSolved()); assertTrue(mdTest.isSolved());
assertFalse(mdResult.isSolved()); assertFalse(mdResult.isSolved());
System.out.println(mdTest);
System.out.println(mdResult);
assertNotEquals(mdTest, mdResult); assertNotEquals(mdTest, mdResult);
solver.solve(mdResult);
assertTrue(solver.solve(mdResult));
assertEquals(mdTest, mdResult); assertEquals(mdTest, mdResult);
} }
@Test @Test
void solveTest() { void solveTest() {
for (int i = 0; i < 100; i++) { initializeSolvers();
testSize2(h); testSize2(h);
testSize3(h); testSize3(h);
testSize2(m); testSize2(m);
testSize3(m); testSize3(m);
testMDSize3(m); testMDSize3(m);
testSize2(r); testSize2(r);
testSize3(r); testSize3(r);
testMDSize3(r); testMDSize3(r);
}
} }
} }