83 lines
2.5 KiB
Java
83 lines
2.5 KiB
Java
package sudoku.solver;
|
|
|
|
import java.util.List;
|
|
import java.util.Random;
|
|
import java.util.concurrent.CancellationException;
|
|
import java.util.logging.Level;
|
|
|
|
import sudoku.io.SudokuPrinter;
|
|
import sudoku.structure.Cell;
|
|
import sudoku.structure.MultiDoku;
|
|
import sudoku.structure.Sudoku;
|
|
|
|
public class MixedSolver implements Solver{
|
|
|
|
/**
|
|
* Résout le MultiDoku passé en paramètre, avec règles de déduction et
|
|
* backtracking.
|
|
*
|
|
* @param doku MultiDoku, MultiDoku à résoudre.
|
|
* @param rand Random, pour tester aléatoirement les symboles, lors du
|
|
* backtracking.
|
|
* @return boolean, valant true si le MultiDoku est résolu, false sinon.
|
|
*/
|
|
@Override
|
|
public boolean solve(MultiDoku doku) {
|
|
Random rand = new Random();
|
|
|
|
if (Thread.interrupted()) {
|
|
throw new CancellationException("User wants to stop the solver");
|
|
}
|
|
|
|
Sudoku sudoku = doku.getSubGrid(0);
|
|
logger.log(Level.FINE,
|
|
'\n' + SudokuPrinter.toStringRectangleSudoku(
|
|
sudoku,
|
|
sudoku.getBlockWidth() == 0 ? sudoku.getSize() : sudoku.getBlockWidth(),
|
|
sudoku.getBlockWidth() == 0 ? sudoku.getSize() : sudoku.getSize() / sudoku.getBlockWidth()));
|
|
|
|
if (doku.isSolved()) {
|
|
return true;
|
|
}
|
|
|
|
List<Cell> cellsToFill = doku.getEmptyCells();
|
|
if (cellsToFill.isEmpty()) {
|
|
return false;
|
|
}
|
|
|
|
// Règles de déduction
|
|
for (Cell cellToFill : cellsToFill) {
|
|
|
|
List<Integer> possibleSymbols = cellToFill.getPossibleSymbols();
|
|
if (possibleSymbols.size() != 1) {
|
|
continue;
|
|
}
|
|
|
|
cellToFill.setSymbolIndex(possibleSymbols.getFirst());
|
|
|
|
return this.solve(doku);
|
|
}
|
|
|
|
// Si ça ne marche pas
|
|
// On fait du backtracking
|
|
Cell cellToFill = doku.getRandomEmptyCell(rand);
|
|
List<Integer> possibleSymbols = cellToFill.getPossibleSymbols();
|
|
|
|
while (!possibleSymbols.isEmpty()) {
|
|
int nextPossibleSymbolIndex = rand.nextInt(possibleSymbols.size());
|
|
int nextSymbol = possibleSymbols.get(nextPossibleSymbolIndex);
|
|
|
|
cellToFill.setSymbolIndex(nextSymbol);
|
|
if (this.solve(doku)) {
|
|
return true;
|
|
}
|
|
|
|
cellToFill.setSymbolIndex(Cell.NOSYMBOL);
|
|
possibleSymbols.remove(nextPossibleSymbolIndex);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
}
|