3 Commits

Author SHA1 Message Date
4a8644181a build.gradle fix tests
Some checks failed
Linux arm64 / Build (push) Has been cancelled
2025-02-02 15:03:26 +01:00
efa357a1ab refactor MixedSolver 2025-02-02 14:56:31 +01:00
618e436270 refactor stupidsolver 2025-02-02 14:43:09 +01:00
3 changed files with 58 additions and 40 deletions

View File

@@ -11,8 +11,6 @@ plugins {
id 'application' id 'application'
} }
project.ext.os = System.properties['os.name'].toLowerCase().split(" ")[0]
repositories { repositories {
// Use Maven Central for resolving dependencies. // Use Maven Central for resolving dependencies.
mavenCentral() mavenCentral()
@@ -22,6 +20,8 @@ dependencies {
// Use JUnit Jupiter for testing. // Use JUnit Jupiter for testing.
testImplementation 'org.junit.jupiter:junit-jupiter:5.9.1' testImplementation 'org.junit.jupiter:junit-jupiter:5.9.1'
implementation 'com.google.guava:guava:31.1-jre'
implementation 'org.json:json:20250107' implementation 'org.json:json:20250107'
implementation "io.github.spair:imgui-java-app:1.88.0" implementation "io.github.spair:imgui-java-app:1.88.0"
@@ -50,6 +50,10 @@ jar {
} }
} }
test {
useJUnitPlatform()
}
run { run {
enableAssertions = true enableAssertions = true
} }

View File

@@ -1,7 +1,6 @@
package sudoku.solver; package sudoku.solver;
import java.util.List; import java.util.List;
import java.util.Random;
import java.util.concurrent.CancellationException; import java.util.concurrent.CancellationException;
import sudoku.structure.Cell; import sudoku.structure.Cell;
@@ -9,6 +8,19 @@ import sudoku.structure.MultiDoku;
public class MixedSolver implements Solver { public class MixedSolver implements Solver {
private Cell findCellToBacktrack(MultiDoku doku, int maxPossibilities) {
for (Cell cell : doku.getCells()) {
if (!cell.isMutable() || !cell.isEmpty())
continue;
List<Integer> possibleSymbols = cell.getPossibleSymbols();
if (possibleSymbols.size() == maxPossibilities) {
return cell;
}
}
return null;
}
/** /**
* Résout le MultiDoku passé en paramètre, avec règles de déduction et * Résout le MultiDoku passé en paramètre, avec règles de déduction et
* backtracking. * backtracking.
@@ -18,47 +30,45 @@ public class MixedSolver implements Solver {
*/ */
@Override @Override
public boolean solve(MultiDoku doku, List<SolverStep> steps) { public boolean solve(MultiDoku doku, List<SolverStep> steps) {
Random rand = new Random();
if (Thread.interrupted()) { if (Thread.interrupted()) {
throw new CancellationException("User wants to stop the solver"); throw new CancellationException("User wants to stop the solver");
} }
if (doku.isSolved()) { while (!doku.isSolved()) {
return true; boolean filledCell = false;
} for (Cell cell : doku.getCells()) {
if (!cell.isMutable() || !cell.isEmpty())
Cell cellToFill = doku.getFirstEmptyCell(); continue;
if (cellToFill == null) {
return false;
}
List<Integer> possibleSymbols = cellToFill.getPossibleSymbols();
List<Integer> possibleSymbols = cell.getPossibleSymbols();
if (possibleSymbols.size() == 1) { if (possibleSymbols.size() == 1) {
cellToFill.setSymbolIndex(possibleSymbols.getFirst()); cell.setSymbolIndex(possibleSymbols.getFirst());
addStep(cellToFill, steps); addStep(cell, steps);
if (this.solve(doku, 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();
}
}
}
return true; return true;
} }
}
while (!possibleSymbols.isEmpty()) {
int nextPossibleSymbolIndex = rand.nextInt(possibleSymbols.size());
int nextSymbol = possibleSymbols.get(nextPossibleSymbolIndex);
cellToFill.setSymbolIndex(nextSymbol);
addStep(cellToFill, steps);
if (this.solve(doku, steps)) {
return true;
}
cellToFill.setSymbolIndex(Cell.NOSYMBOL);
addStep(cellToFill, steps);
possibleSymbols.remove(nextPossibleSymbolIndex);
}
return false;
}
} }

View File

@@ -1,5 +1,6 @@
package sudoku.solver; package sudoku.solver;
import java.util.List;
import java.util.concurrent.CancellationException; import java.util.concurrent.CancellationException;
import sudoku.structure.MultiDoku; import sudoku.structure.MultiDoku;
@@ -8,9 +9,9 @@ import sudoku.structure.Sudoku;
/** /**
* Class de test non utilisé * Class de test non utilisé
*/ */
public class StupidSolver { public class StupidSolver implements Solver{
private static boolean solve(Sudoku sudoku, int index) { private boolean solve(Sudoku sudoku, int index, List<SolverStep> steps) {
// mécanisme d'abandon // mécanisme d'abandon
if (Thread.interrupted()) if (Thread.interrupted())
throw new CancellationException("User wants to stop the solver"); throw new CancellationException("User wants to stop the solver");
@@ -21,27 +22,30 @@ public class StupidSolver {
// si la case n'est pas modifiable, on passe à la suivante // si la case n'est pas modifiable, on passe à la suivante
if (!sudoku.getCell(index).isMutable()) if (!sudoku.getCell(index).isMutable())
return solve(sudoku, index + 1); return solve(sudoku, index + 1, steps);
for (int symbol = 0; symbol < sudoku.getSize(); symbol++) { for (int symbol = 0; symbol < sudoku.getSize(); symbol++) {
if (sudoku.getCell(index).trySetValue(symbol)) { if (sudoku.getCell(index).trySetValue(symbol)) {
addStep(sudoku.getCell(index), steps);
// on tente de placer sur la case suivante // on tente de placer sur la case suivante
if (solve(sudoku, index + 1)) { if (solve(sudoku, index + 1, steps)) {
return true; return true;
} }
} }
} }
// on a tout essayé et rien n'a fonctionné // on a tout essayé et rien n'a fonctionné
sudoku.getCell(index).empty(); sudoku.getCell(index).empty();
addStep(sudoku.getCell(index), steps);
return false; return false;
} }
public static boolean solve(MultiDoku doku) { @Override
public boolean solve(MultiDoku doku, List<SolverStep> steps) {
if (doku.isSolved()) if (doku.isSolved())
return true; return true;
for (Sudoku sudoku : doku.getSubGrids()) { for (Sudoku sudoku : doku.getSubGrids()) {
if (!solve(sudoku, 0)) if (!solve(sudoku, 0, steps))
return false; return false;
} }
return true; return true;