91 lines
2.9 KiB
Java
91 lines
2.9 KiB
Java
package sudoku.solver;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.List;
|
|
import java.util.concurrent.CancellationException;
|
|
|
|
import sudoku.structure.Cell;
|
|
import sudoku.structure.MultiDoku;
|
|
|
|
public class MixedSolver implements Solver {
|
|
|
|
private List<Cell> findCellsToBacktrack(MultiDoku doku, int maxPossibilities) {
|
|
List<Cell> cells = new ArrayList<>();
|
|
for (Cell cell : doku.getCells()) {
|
|
if (!cell.isMutable() || !cell.isEmpty())
|
|
continue;
|
|
|
|
List<Integer> possibleSymbols = cell.getPossibleSymbols();
|
|
if (possibleSymbols.size() == maxPossibilities) {
|
|
cells.add(cell);
|
|
}
|
|
|
|
// une cellule nous empêche de continuer
|
|
if (possibleSymbols.size() == 0)
|
|
return null;
|
|
}
|
|
return cells;
|
|
}
|
|
|
|
/**
|
|
* Résout le MultiDoku passé en paramètre, avec règles de déduction et
|
|
* backtracking.
|
|
*
|
|
* @param doku MultiDoku, MultiDoku à résoudre.
|
|
* @return boolean, valant true si le MultiDoku est résolu, false sinon.
|
|
*/
|
|
@Override
|
|
public boolean solve(MultiDoku doku, List<SolverStep> steps) {
|
|
if (Thread.interrupted()) {
|
|
throw new CancellationException("User wants to stop the solver");
|
|
}
|
|
|
|
if (doku.isSolved())
|
|
return true;
|
|
|
|
if (findCellsToBacktrack(doku, 0) == null)
|
|
return false;
|
|
|
|
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);
|
|
addStep(cell, steps);
|
|
return false;
|
|
}
|
|
}
|
|
// on ne peut plus remplir de cases, on tente de backtrack
|
|
int maxPossibilities = 2;
|
|
List<Cell> backtrackCells = new ArrayList<>();
|
|
while (backtrackCells.isEmpty()) {
|
|
backtrackCells = findCellsToBacktrack(doku, maxPossibilities);
|
|
if (backtrackCells == null || maxPossibilities > doku.getSubGrid(0).getSize())
|
|
return false;
|
|
maxPossibilities++;
|
|
}
|
|
// on fait du backtracking
|
|
for (Cell backtrackCell : backtrackCells) {
|
|
List<Integer> possibilities = backtrackCell.getPossibleSymbols();
|
|
for (int symbol : possibilities) {
|
|
backtrackCell.setSymbolIndex(symbol);
|
|
addStep(backtrackCell, steps);
|
|
if (solve(doku, steps))
|
|
return true;
|
|
}
|
|
|
|
backtrackCell.setSymbolIndex(Cell.NOSYMBOL);
|
|
addStep(backtrackCell, steps);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
}
|