diff --git a/app/src/main/java/sudoku/solver/Solver.java b/app/src/main/java/sudoku/solver/Solver.java index 96b3dfd..1bb55c5 100644 --- a/app/src/main/java/sudoku/solver/Solver.java +++ b/app/src/main/java/sudoku/solver/Solver.java @@ -65,6 +65,7 @@ public class Solver { /** * Compte le nombre de solutions possibles au MultiDoku passé en paramètres. + * * @param doku MultiDoku, MultiDoku dont on veut le nombre de solutions. * @return int, nombre de solutions possibles. */ @@ -95,6 +96,7 @@ public class Solver { /** * Résout le MultiDoku passé en paramètre, avec backtracking. + * * @param doku MultiDoku, MultiDoku à résoudre. * @return boolean, valant true si le MultiDoku est résolu, false sinon. */ @@ -131,6 +133,7 @@ public class Solver { /** * Résout le MultiDoku passé en paramètre, avec règles de déduction. + * * @param doku MultiDoku, MultiDoku à résoudre. * @return boolean, valant true si le MultiDoku est résolu, false sinon. */ @@ -138,33 +141,31 @@ public class Solver { 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 cellsToFill = doku.getEmptyCells(); + if (cellsToFill.isEmpty()) { + return false; + } - while (!cellsToFill.isEmpty()) { + for (Cell cellToFill : cellsToFill) { - 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())); - - boolean blocked = true; - for (Cell cellToFill : cellsToFill) { - - List possibleSymbols = cellToFill.getPossibleSymbols(); - if (possibleSymbols.size() != 1) { - continue; - } - - cellToFill.setSymbolIndex(possibleSymbols.getFirst()); - cellsToFill.remove(cellToFill); - blocked = false; - break; + List possibleSymbols = cellToFill.getPossibleSymbols(); + if (possibleSymbols.size() != 1) { + continue; } - if (blocked) { - break; - } + cellToFill.setSymbolIndex(possibleSymbols.getFirst()); + + return Solver.humanSolve(doku); } return doku.isSolved(); @@ -172,42 +173,64 @@ public class 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. */ - public static boolean mixedSolve(MultiDoku doku) { - if (Thread.interrupted()) + public static boolean mixedSolve(MultiDoku doku, Random rand) { + if (Thread.interrupted()) { throw new CancellationException("User wants to stop the solver"); - - List cellsToFill = doku.getEmptyCells(); - - while (!cellsToFill.isEmpty()) { - - 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())); - - boolean blocked = true; - for (Cell cellToFill : cellsToFill) { - - List possibleSymbols = cellToFill.getPossibleSymbols(); - if (possibleSymbols.size() != 1) { - continue; - } - - cellToFill.setSymbolIndex(possibleSymbols.getFirst()); - cellsToFill.remove(cellToFill); - blocked = false; - break; - } - - if (blocked) { - break; - } } - return doku.isSolved(); + 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 cellsToFill = doku.getEmptyCells(); + if (cellsToFill.isEmpty()) { + return false; + } + + //Règles de déduction + for (Cell cellToFill : cellsToFill) { + + List possibleSymbols = cellToFill.getPossibleSymbols(); + if (possibleSymbols.size() != 1) { + continue; + } + + cellToFill.setSymbolIndex(possibleSymbols.getFirst()); + + return Solver.mixedSolve(doku, rand); + } + + //Si ça ne marche pas + //On fait du backtracking + Cell cellToFill = doku.getRandomEmptyCell(rand); + List possibleSymbols = cellToFill.getPossibleSymbols(); + + while (!possibleSymbols.isEmpty()) { + int nextPossibleSymbolIndex = rand.nextInt(possibleSymbols.size()); + int nextSymbol = possibleSymbols.get(nextPossibleSymbolIndex); + + cellToFill.setSymbolIndex(nextSymbol); + if (Solver.mixedSolve(doku, rand)) { + return true; + } + + cellToFill.setSymbolIndex(Cell.NOSYMBOL); + possibleSymbols.remove(nextPossibleSymbolIndex); + } + + return false; } } diff --git a/app/src/main/java/sudoku/structure/MultiDoku.java b/app/src/main/java/sudoku/structure/MultiDoku.java index 37b4976..eb64d46 100644 --- a/app/src/main/java/sudoku/structure/MultiDoku.java +++ b/app/src/main/java/sudoku/structure/MultiDoku.java @@ -1,9 +1,6 @@ package sudoku.structure; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; +import java.util.*; import sudoku.io.SudokuSerializer; @@ -170,4 +167,15 @@ public class MultiDoku { return stateManager; } + /** + * Renvoie une Cell vide choisie aléatoirement. + * + * @param rand Random, pour le choix aléatoire. + * @return Cell, une Cell vide. + */ + public Cell getRandomEmptyCell(Random rand) { + List emptyCells = getEmptyCells(); + int randomIndex = rand.nextInt(emptyCells.size()); + return emptyCells.get(randomIndex); + } }