From cd4d01e1e63b9df85d34c1724d2b4e82b420f55d Mon Sep 17 00:00:00 2001 From: Melvyn Date: Wed, 29 Jan 2025 18:42:58 +0100 Subject: [PATCH] fix : MultiDoku.getCells --- .../sudoku/constraint/ColumnConstraint.java | 7 +- app/src/main/java/sudoku/solver/Solver.java | 25 +++-- .../main/java/sudoku/solver/StupidSolver.java | 2 +- .../main/java/sudoku/structure/MultiDoku.java | 25 +++-- .../main/java/sudoku/structure/Sudoku.java | 103 ++++++++++++++---- .../java/sudoku/structure/SudokuFactory.java | 16 ++- .../test/java/sudoku/solver/SolverTest.java | 4 +- 7 files changed, 132 insertions(+), 50 deletions(-) diff --git a/app/src/main/java/sudoku/constraint/ColumnConstraint.java b/app/src/main/java/sudoku/constraint/ColumnConstraint.java index 0d69e6d..19d3aff 100644 --- a/app/src/main/java/sudoku/constraint/ColumnConstraint.java +++ b/app/src/main/java/sudoku/constraint/ColumnConstraint.java @@ -1,5 +1,6 @@ package sudoku.constraint; +import sudoku.structure.Cell; import sudoku.structure.Sudoku; public class ColumnConstraint implements IConstraint { @@ -7,10 +8,12 @@ public class ColumnConstraint implements IConstraint { @Override public boolean canBePlaced(final Sudoku s, int x, int y, int newSymbolIndex) { for (int i = 0; i < s.getSize(); i++) { - if (s.getCell(x, i).getSymbolIndex() == newSymbolIndex) + Cell cell = s.getCell(x, i); + int symbol = cell.getSymbolIndex(); + if (symbol == newSymbolIndex) { return false; + } } return true; } - } diff --git a/app/src/main/java/sudoku/solver/Solver.java b/app/src/main/java/sudoku/solver/Solver.java index bb96a97..2ab99e3 100644 --- a/app/src/main/java/sudoku/solver/Solver.java +++ b/app/src/main/java/sudoku/solver/Solver.java @@ -32,12 +32,12 @@ public class Solver { throw new CancellationException("User wants to stop the solver"); Sudoku sudoku = doku.getSubGrid(0); - logger.log(Level.INFO, + 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.isValid()) { + if (doku.isSolved()) { return true; } @@ -65,7 +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. + * @param oldDoku MultiDoku, MultiDoku dont on veut le nombre de solutions. * @return int, nombre de solutions possibles. */ public static int countSolution(MultiDoku oldDoku) { @@ -73,21 +73,23 @@ public class Solver { MultiDoku doku = oldDoku.clone(); - if (doku.isValid()) { + if (doku.isSolved()) { return 1; } Cell cellToFill = doku.getFirstEmptyCell(); if (cellToFill == null) { + System.out.println("AAAAAAAAAAAAAA"); return 0; } List possibleSymbols = doku.getPossibleSymbolsOfCell(cellToFill); for (int symbol : possibleSymbols) { - cellToFill.setSymbolIndex(symbol); - if (Solver.solve(doku)) { + System.out.println("symbol : "+symbol); + System.out.println("doku.isSolved() || Solver.solve(doku) ? "+ (doku.isSolved() || Solver.solve(doku))); + if (doku.isSolved() || Solver.solve(doku)) { result++; } cellToFill.setSymbolIndex(Cell.NOSYMBOL); @@ -105,7 +107,7 @@ public class Solver { if (Thread.interrupted()) throw new CancellationException("User wants to stop the solver"); - if (doku.isValid()) { + if (doku.isSolved()) { return true; } @@ -144,6 +146,13 @@ public class 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) { @@ -163,6 +172,6 @@ public class Solver { } } - return doku.isValid(); + return doku.isSolved(); } } diff --git a/app/src/main/java/sudoku/solver/StupidSolver.java b/app/src/main/java/sudoku/solver/StupidSolver.java index dceabc8..9d2dec1 100644 --- a/app/src/main/java/sudoku/solver/StupidSolver.java +++ b/app/src/main/java/sudoku/solver/StupidSolver.java @@ -39,7 +39,7 @@ public class StupidSolver { } public static boolean solve(MultiDoku doku) { - if (doku.isValid()) + if (doku.isSolved()) return true; for (Sudoku sudoku : doku.getSubGrids()) { diff --git a/app/src/main/java/sudoku/structure/MultiDoku.java b/app/src/main/java/sudoku/structure/MultiDoku.java index a1ea69a..b60c842 100644 --- a/app/src/main/java/sudoku/structure/MultiDoku.java +++ b/app/src/main/java/sudoku/structure/MultiDoku.java @@ -1,7 +1,9 @@ package sudoku.structure; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; +import java.util.Set; import sudoku.io.SudokuSerializer; @@ -49,11 +51,11 @@ public class MultiDoku { * @return List */ public List getCells(){ - List cells = new ArrayList<>(); + Set cellsSet = new HashSet<>(); for (Sudoku sudoku : subGrids){ - cells.addAll(sudoku.getCells()); + cellsSet.addAll(sudoku.getCells()); } - return cells; + return new ArrayList<>(cellsSet); } /** @@ -111,10 +113,10 @@ public class MultiDoku { * Check si le MultiDoku est valide, en fonction de ses sous-Sudokus. * @return boolean, true s'il est valide et false sinon. */ - public boolean isValid() { + public boolean isSolved() { boolean result = true; for (Sudoku sudoku : this.subGrids) { - result = sudoku.isValid() && result; + result = sudoku.isSolved() && result; } return result; } @@ -191,14 +193,17 @@ public class MultiDoku { cellToEmpty.setSymbolIndex(Cell.NOSYMBOL); } + /** + * Renvoie le nombre de Cell contenue dans le MultiDoku. + * @return int, nombre de Cell dans le MultiDoku. + */ public int getNbCells() { - int result = 0; - for (Sudoku sudoku : this.subGrids) { - result += sudoku.getCells().size(); - } - return result; + return getCells().size(); } + /** + * Change les Cells de ce MultiDoku avec des symboles, en Cells immuables. + */ public void setFilledCellsImmutable() { for (Cell filledCell : getFilledCells()) { filledCell.setImmutable(); diff --git a/app/src/main/java/sudoku/structure/Sudoku.java b/app/src/main/java/sudoku/structure/Sudoku.java index 4aff373..2cd2e39 100644 --- a/app/src/main/java/sudoku/structure/Sudoku.java +++ b/app/src/main/java/sudoku/structure/Sudoku.java @@ -18,7 +18,7 @@ public class Sudoku { /** * Liste des Cells contenus dans le Sudoku. */ - private final List cells; + private List cells = new ArrayList<>(); /** * Liste des contraintes (TODO) du Sudoku. */ @@ -334,38 +334,95 @@ public class Sudoku { } /** - * Vérifie que le Sudoku est cohérent avec ses contraintes. - * @return boolean, valant true si le Sudoku est cohérent avec ses contraintes, false sinon. + * Vérifie si le Sudoku est résolue, soit complet et cohérent avec ses contraintes. + * @return boolean, valant true si le Sudoku est résolu, false sinon. */ - public boolean isValid() { - for (Cell cell : this.cells) { - if (cell.isMutable()) { - if (cell.isEmpty()) { - return false; - } - for (IConstraint constraint : this.constraints) { - Coordinate coords; - try { - int symbolPlaced = cell.getSymbolIndex(); - coords = this.getCoordinateCell(cell); + public boolean isSolved() { + boolean isComplete = isComplete(); + boolean isValid = isValid(); + return isComplete && isValid; + } - cell.setSymbolIndex(Cell.NOSYMBOL); - List possibleSymbols = constraint.getPossibleSymbols(this, coords.getX(), - coords.getY()); - cell.setSymbolIndex(symbolPlaced); - if (possibleSymbols.size() != 1 || possibleSymbols.get(0) != symbolPlaced) { - return false; - } + /** + * Vérifie que le Sudoku est complet, soit qu'il n'y ait aucune case vide. + * @return boolean, true si le Sudoku est complet, false sinon. + */ + private boolean isComplete() { + return getFirstEmptyCell() == null; + } - } catch (Exception e) { - throw new RuntimeException(e); + /** + * Vérifie si le Sudoku est valide, soit qu'il est cohérent avec ses contraintes. + * @return bollean, true si le Sudoku est valide, false sinon + */ + private boolean isValid() { + for (Cell cell : this.getFilledCells()) { + for (IConstraint constraint : this.constraints) { + try { + Coordinate coords = this.getCoordinateCell(cell); + + int symbolPlaced = cell.empty(); + List possibleSymbols = constraint.getPossibleSymbols( + this, + coords.getX(), + coords.getY() + ); + + cell.setSymbolIndex(symbolPlaced); + if (!possibleSymbols.contains(symbolPlaced)) { + return false; } + + } catch (Exception e) { + throw new RuntimeException(e); } } } return true; } + /** + * Renvoie la liste des Cells remplies. + * @return List + */ + private List getFilledCells() { + List result = new ArrayList<>(); + for (Cell cell : getCells()) { + if (!cell.isEmpty()) { + result.add(cell); + } + } + return result; + } + + /** + * Renvoie la liste des Cells modifiables. + * @return List + */ + private List getEmptyCells() { + List result = new ArrayList<>(); + for (Cell cell : getCells()) { + if (cell.isMutable()) { + result.add(cell); + } + } + return result; + } + + /** + * Renvoie la liste des Cells immuables. + * @return List + */ + private List getImmutableCells() { + List result = new ArrayList<>(); + for (Cell cell : getCells()) { + if (!cell.isMutable()) { + result.add(cell); + } + } + return result; + } + @Override public boolean equals(Object object) { if (!(object instanceof Sudoku)) { diff --git a/app/src/main/java/sudoku/structure/SudokuFactory.java b/app/src/main/java/sudoku/structure/SudokuFactory.java index 535af2c..3f84986 100644 --- a/app/src/main/java/sudoku/structure/SudokuFactory.java +++ b/app/src/main/java/sudoku/structure/SudokuFactory.java @@ -10,6 +10,7 @@ import sudoku.constraint.BlockConstraint; import sudoku.constraint.ColumnConstraint; import sudoku.constraint.IConstraint; import sudoku.constraint.LineConstraint; +import sudoku.io.SudokuPrinter; import sudoku.solver.Solver; public class SudokuFactory { @@ -121,7 +122,8 @@ public class SudokuFactory { */ public static boolean newDokuFromFilledOne (MultiDoku doku, int nbCellsToEmpty) throws Exception { - if (nbCellsToEmpty > doku.getCells().size()) { + System.out.println("nbCellsToEmpty : "+nbCellsToEmpty); + if (nbCellsToEmpty >= doku.getCells().size()) { throw new Exception(); } @@ -137,7 +139,9 @@ public class SudokuFactory { int oldSymbol = cellToEmpty.empty(); - if (Solver.countSolution(doku) == 1) { + int nbDokuSultions = Solver.countSolution(doku); + System.out.println("oldSymbol : "+oldSymbol); + if (nbDokuSultions == 1) { if (newDokuFromFilledOne(doku, --nbCellsToEmpty)) { return true; } @@ -239,9 +243,13 @@ public class SudokuFactory { public static void fillDoku(MultiDoku doku, Difficulty difficulty) throws Exception { Solver.solveRandom(doku, random); + //SudokuPrinter.printRectangleSudoku(doku.getSubGrid(0), 3, 3); int nbCellsToEmpty = (int)(difficulty.getFactor()*doku.getNbCells()); - boolean successfull = newDokuFromFilledOne(doku, nbCellsToEmpty); - if (!successfull) { + //System.out.println(nbCellsToEmpty); + boolean successful = newDokuFromFilledOne(doku, nbCellsToEmpty); + + + if (!successful) { throw new Exception("Canno't create this doku with this difficulty"); } doku.setFilledCellsImmutable(); diff --git a/app/src/test/java/sudoku/solver/SolverTest.java b/app/src/test/java/sudoku/solver/SolverTest.java index 85a38c4..8267444 100644 --- a/app/src/test/java/sudoku/solver/SolverTest.java +++ b/app/src/test/java/sudoku/solver/SolverTest.java @@ -56,7 +56,7 @@ class SolverTest { SudokuPrinter.printRectangleSudoku(sudokuResult, 3, 3); - assert(dokuResult.isValid()); + assert(dokuResult.isSolved()); Solver.solveRandom(dokuToTest, rand); @@ -65,7 +65,7 @@ class SolverTest { SudokuPrinter.printRectangleSudoku(dokuToTest.getSubGrid(0), 3, 3); - assert(dokuToTest.isValid()); + assert(dokuToTest.isSolved()); assert(dokuToTest.equals(dokuResult));