diff --git a/app/src/main/java/sudoku/solver/Solver.java b/app/src/main/java/sudoku/solver/Solver.java index e1eb4b5..0a79cd1 100644 --- a/app/src/main/java/sudoku/solver/Solver.java +++ b/app/src/main/java/sudoku/solver/Solver.java @@ -11,11 +11,11 @@ public class Solver { /** * Résout le multidoku passé en paramètre si c'est possible. - * En testant toutes les possibilités avec un algorithme de backtracking. + * En testant toutes les possibilités, de manière aléatoire, avec un algorithme de backtracking. * * @param doku Multidoku, à résoudre - * @param rand random pour tester aléatoirement les symboles - * @return boolean, true s'il est résolut ou false s'il ne l'est pas. + * @param rand Random, pour tester aléatoirement les symboles + * @return boolean, true s'il est résolu ou false s'il ne l'est pas. */ public static boolean solveRandom(MultiDoku doku, Random rand) { if (Thread.interrupted()) @@ -39,15 +39,40 @@ public class Solver { cellToFill.setSymbolIndex(nextSymbol); if (Solver.solveRandom(doku, rand)) { return true; - } else { - cellToFill.setSymbolIndex(Cell.NOSYMBOL); - possibleSymbols.remove(nextPossibleSymbolIndex); } + cellToFill.setSymbolIndex(Cell.NOSYMBOL); + possibleSymbols.remove(nextPossibleSymbolIndex); } return false; } + public static int countSolution(MultiDoku doku) { + int result = 0; + + if (doku.isValid()) { + return 1; + } + + Cell cellToFill = doku.getFirstEmptyCell(); + if (cellToFill == null) { + return 0; + } + + List possibleSymbols = doku.getPossibleSymbolsOfCell(cellToFill); + + for (int symbol : possibleSymbols) { + + cellToFill.setSymbolIndex(symbol); + if (Solver.solve(doku)) { + result++; + } + cellToFill.setSymbolIndex(Cell.NOSYMBOL); + } + + return result; + } + public static boolean solve(MultiDoku doku) { if (Thread.interrupted()) throw new CancellationException("User wants to stop the solver"); diff --git a/app/src/main/java/sudoku/structure/Cell.java b/app/src/main/java/sudoku/structure/Cell.java index 758267c..58e7aeb 100644 --- a/app/src/main/java/sudoku/structure/Cell.java +++ b/app/src/main/java/sudoku/structure/Cell.java @@ -77,4 +77,10 @@ public class Cell { public boolean isMutable() { return this.isMutable; } + + public int empty() { + int oldSymbol = this.symbolIndex; + this.symbolIndex = Cell.NOSYMBOL; + return oldSymbol; + } } diff --git a/app/src/main/java/sudoku/structure/MultiDoku.java b/app/src/main/java/sudoku/structure/MultiDoku.java index cf68c69..5abfb11 100644 --- a/app/src/main/java/sudoku/structure/MultiDoku.java +++ b/app/src/main/java/sudoku/structure/MultiDoku.java @@ -98,5 +98,21 @@ public class MultiDoku { return true; } + + public List getFilledCells() { + List result = new ArrayList<>(); + for (Cell c : this.getCells()){ + if (!c.isEmpty()) { + result.add(c); + } + } + return result; + } + + public void empty(Cell cell) { + List cells = getCells(); + Cell cellToEmpty = cells.get(cells.indexOf(cell)); + cellToEmpty.setSymbolIndex(Cell.NOSYMBOL); + } } diff --git a/app/src/main/java/sudoku/structure/Sudoku.java b/app/src/main/java/sudoku/structure/Sudoku.java index 1d24441..a56acb8 100644 --- a/app/src/main/java/sudoku/structure/Sudoku.java +++ b/app/src/main/java/sudoku/structure/Sudoku.java @@ -287,4 +287,8 @@ public class Sudoku { return true; } + + public void empty(Cell cell) { + + } } diff --git a/app/src/main/java/sudoku/structure/SudokuFactory.java b/app/src/main/java/sudoku/structure/SudokuFactory.java index f235c7a..86b3770 100644 --- a/app/src/main/java/sudoku/structure/SudokuFactory.java +++ b/app/src/main/java/sudoku/structure/SudokuFactory.java @@ -4,14 +4,17 @@ import sudoku.constraint.BlockConstraint; import sudoku.constraint.ColumnConstraint; import sudoku.constraint.IConstraint; import sudoku.constraint.LineConstraint; -import sudoku.structure.*; +import sudoku.solver.Solver; import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.Random; public class SudokuFactory { + private static final Random random = new Random(); + private static List initCells(int size) { List cells = new ArrayList<>(size * size); for (int i = 0; i < size * size; i++) { @@ -72,4 +75,35 @@ public class SudokuFactory { } }); } + + public static boolean newDokuFromFilledOne (MultiDoku doku, int difficulty) throws Exception { + + if (difficulty > doku.getCells().size()) { + throw new Exception(); + } + + if (difficulty == 0) { + return true; + } + + List cellsThatCanBeEmptied = doku.getFilledCells(); + + while (!cellsThatCanBeEmptied.isEmpty()) { + int index = random.nextInt(cellsThatCanBeEmptied.size()); + Cell cellToEmpty = cellsThatCanBeEmptied.get(index); + + int oldSymbol = cellToEmpty.empty(); + + if (Solver.countSolution(doku) == 1) { + if (newDokuFromFilledOne(doku, --difficulty)) { + return true; + } + } + + cellToEmpty.setSymbolIndex(oldSymbol); + cellsThatCanBeEmptied.remove(cellToEmpty); + } + + return false; + } }