From bf67afe4a926652f0e300a3f210acccf2f7ba1e0 Mon Sep 17 00:00:00 2001 From: Melvyn Date: Thu, 30 Jan 2025 12:03:03 +0100 Subject: [PATCH] refactor : Solver --- app/src/main/java/gui/menu/SudokuView.java | 2 +- .../main/java/sudoku/io/ConsoleInterface.java | 2 +- app/src/main/java/sudoku/solver/Solver.java | 49 +++++++++++++++++-- .../java/sudoku/structure/SudokuFactory.java | 7 +-- .../java/sudoku/SudokuSerializerTest.java | 6 +-- .../test/java/sudoku/solver/SolverTest.java | 6 +-- 6 files changed, 54 insertions(+), 18 deletions(-) diff --git a/app/src/main/java/gui/menu/SudokuView.java b/app/src/main/java/gui/menu/SudokuView.java index e44a598..873609b 100644 --- a/app/src/main/java/gui/menu/SudokuView.java +++ b/app/src/main/java/gui/menu/SudokuView.java @@ -82,7 +82,7 @@ public class SudokuView extends BaseView { resolveThread = new Thread(() -> { try { Random rand = new Random(); - Solver.solveRandom(doku, rand); + Solver.randomSolve(doku, rand); Thread.sleep(200); } catch (CancellationException | InterruptedException e) { System.out.println("The user is bored !"); diff --git a/app/src/main/java/sudoku/io/ConsoleInterface.java b/app/src/main/java/sudoku/io/ConsoleInterface.java index b881f49..6f7890b 100644 --- a/app/src/main/java/sudoku/io/ConsoleInterface.java +++ b/app/src/main/java/sudoku/io/ConsoleInterface.java @@ -133,7 +133,7 @@ public class ConsoleInterface { } private void generateFullDoku(MultiDoku doku) { - Solver.solveRandom(doku, new Random()); + Solver.randomSolve(doku, new Random()); } } diff --git a/app/src/main/java/sudoku/solver/Solver.java b/app/src/main/java/sudoku/solver/Solver.java index b2e45a1..96b3dfd 100644 --- a/app/src/main/java/sudoku/solver/Solver.java +++ b/app/src/main/java/sudoku/solver/Solver.java @@ -27,7 +27,7 @@ public class Solver { * @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) { + public static boolean randomSolve(MultiDoku doku, Random rand) { if (Thread.interrupted()) throw new CancellationException("User wants to stop the solver"); @@ -53,7 +53,7 @@ public class Solver { int nextSymbol = possibleSymbols.get(nextPossibleSymbolIndex); cellToFill.setSymbolIndex(nextSymbol); - if (Solver.solveRandom(doku, rand)) { + if (Solver.randomSolve(doku, rand)) { return true; } cellToFill.setSymbolIndex(Cell.NOSYMBOL); @@ -65,7 +65,7 @@ public class Solver { /** * Compte le nombre de solutions possibles au MultiDoku passé en paramètres. - * @param oldDoku MultiDoku, MultiDoku dont on veut le nombre de solutions. + * @param doku MultiDoku, MultiDoku dont on veut le nombre de solutions. * @return int, nombre de solutions possibles. */ public static int countSolution(MultiDoku doku) { @@ -130,7 +130,7 @@ public class Solver { } /** - * Résout le MultiDoku passé en paramètre, sans backtracking. + * 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. */ @@ -169,4 +169,45 @@ public class Solver { return doku.isSolved(); } + + /** + * 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. + */ + public static boolean mixedSolve(MultiDoku doku) { + 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(); + } } diff --git a/app/src/main/java/sudoku/structure/SudokuFactory.java b/app/src/main/java/sudoku/structure/SudokuFactory.java index a2977d9..4b64402 100644 --- a/app/src/main/java/sudoku/structure/SudokuFactory.java +++ b/app/src/main/java/sudoku/structure/SudokuFactory.java @@ -11,12 +11,7 @@ import java.util.Random; import sudoku.io.SudokuSerializer; -import sudoku.constraint.BlockConstraint; -import sudoku.constraint.ColumnConstraint; import sudoku.constraint.Constraint; -import sudoku.constraint.DiagonalConstraint; -import sudoku.constraint.IConstraint; -import sudoku.constraint.LineConstraint; import sudoku.solver.Solver; public class SudokuFactory { @@ -277,7 +272,7 @@ public class SudokuFactory { } public static void fillDoku(MultiDoku doku, Difficulty difficulty) throws Exception { - Solver.solveRandom(doku, random); + Solver.randomSolve(doku, random); int nbCellsToEmpty = (int) (difficulty.getFactor() * doku.getNbCells()); boolean successfull = newDokuFromFilledOne(doku, nbCellsToEmpty); if (!successfull) { diff --git a/app/src/test/java/sudoku/SudokuSerializerTest.java b/app/src/test/java/sudoku/SudokuSerializerTest.java index 26791cb..7317fe3 100644 --- a/app/src/test/java/sudoku/SudokuSerializerTest.java +++ b/app/src/test/java/sudoku/SudokuSerializerTest.java @@ -19,7 +19,7 @@ public class SudokuSerializerTest { void testSerializeWithSize(int blockWidth, int blockHeight) { var sudoku = SudokuFactory.createBasicEmptyRectangleDoku(blockWidth, blockHeight, SudokuFactory.DEFAULT_CONSTRAINTS); - Solver.solveRandom(sudoku, new Random()); + Solver.randomSolve(sudoku, new Random()); JSONObject data = SudokuSerializer.serializeSudoku(sudoku); MultiDoku multiDoku = SudokuSerializer.deserializeSudoku(data); assertTrue(data.toString().equals(SudokuSerializer.serializeSudoku(multiDoku).toString())); @@ -28,7 +28,7 @@ public class SudokuSerializerTest { void testSaveWithSize(int blockWidth, int blockHeight) { MultiDoku doku = SudokuFactory.createBasicEmptyRectangleDoku(blockWidth, blockHeight, SudokuFactory.DEFAULT_CONSTRAINTS); - Solver.solveRandom(doku, new Random()); + Solver.randomSolve(doku, new Random()); String savePath = SudokuSerializer.saveMultiDoku(doku); MultiDoku otherDoku = null; try { @@ -47,7 +47,7 @@ public class SudokuSerializerTest { void testSerializeX(int size) { var sudoku = SudokuFactory.createBasicXShapedMultidoku(size, SudokuFactory.DEFAULT_CONSTRAINTS); - Solver.solveRandom(sudoku, new Random()); + Solver.randomSolve(sudoku, new Random()); JSONObject data = SudokuSerializer.serializeSudoku(sudoku); MultiDoku multiDoku = SudokuSerializer.deserializeSudoku(data); diff --git a/app/src/test/java/sudoku/solver/SolverTest.java b/app/src/test/java/sudoku/solver/SolverTest.java index f0c61e4..0363da2 100644 --- a/app/src/test/java/sudoku/solver/SolverTest.java +++ b/app/src/test/java/sudoku/solver/SolverTest.java @@ -57,7 +57,7 @@ class SolverTest { assert (dokuResult.isSolved()); - Solver.solveRandom(dokuToTest, rand); + Solver.randomSolve(dokuToTest, rand); System.out.println("\n****************************\nDoku solved"); SudokuPrinter.printRectangleSudoku(dokuToTest.getSubGrid(0), 3, 3); @@ -89,13 +89,13 @@ class SolverTest { 5, ns, ns, ns, 3, 1, 0, ns, ns); sudokuToTest2.setImmutableCellsSymbol(immutableCells2); - boolean isSolved = Solver.solveRandom(dokuToTest2, rand); + boolean isSolved = Solver.randomSolve(dokuToTest2, rand); assert (!isSolved); MultiDoku dokuToTest3 = SudokuFactory.createBasicEmptySquareDoku(3, SudokuFactory.DEFAULT_CONSTRAINTS); - Solver.solveRandom(dokuToTest3, rand); + Solver.randomSolve(dokuToTest3, rand); SudokuPrinter.printRectangleSudoku(dokuToTest3.getSubGrid(0), 3, 3); }