diff --git a/app/src/main/java/gui/menu/MultiPlayerView.java b/app/src/main/java/gui/menu/MultiPlayerView.java index 0f3acf0..09afd83 100644 --- a/app/src/main/java/gui/menu/MultiPlayerView.java +++ b/app/src/main/java/gui/menu/MultiPlayerView.java @@ -36,7 +36,7 @@ public class MultiPlayerView extends BaseView { } else { if (ImGui.button("Démarrer")) { // temp - MultiDoku doku = SudokuFactory.createBasicSquareMultidoku(3); + MultiDoku doku = SudokuFactory.createBasicXShapedMultidoku(3); this.server.startGame(doku); } } diff --git a/app/src/main/java/sudoku/solver/Solver.java b/app/src/main/java/sudoku/solver/Solver.java index 3817be4..63b8d3d 100644 --- a/app/src/main/java/sudoku/solver/Solver.java +++ b/app/src/main/java/sudoku/solver/Solver.java @@ -12,11 +12,15 @@ import java.util.logging.Level; import java.util.logging.Logger; public class Solver { + + /** + * Log du Solver, qui garde trace des actions réalisées. + */ private static final Logger logger = Logger.getLogger("SolverLogger"); /** - * Résout le multidoku passé en paramètre si c'est possible. - * En testant toutes les possibilités, de manière aléatoire, avec un algorithme + * Résout, si possible, le multidoku passé en paramètre + * en testant toutes les possibilités, de manière aléatoire, avec un algorithme * de backtracking. * * @param doku Multidoku, à résoudre @@ -59,6 +63,11 @@ public class Solver { return false; } + /** + * 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. + */ public static int countSolution(MultiDoku doku) { int result = 0; @@ -85,6 +94,11 @@ public class Solver { return result; } + /** + * Résout le MultiDoku passé en paramètre. + * @param doku MultiDoku, MultiDoku à résoudre. + * @return boolean, valant true si le MultiDoku est résolu, false sinon. + */ 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/Sudoku.java b/app/src/main/java/sudoku/structure/Sudoku.java index 566728d..4aff373 100644 --- a/app/src/main/java/sudoku/structure/Sudoku.java +++ b/app/src/main/java/sudoku/structure/Sudoku.java @@ -24,7 +24,7 @@ public class Sudoku { */ private final List constraints; /** - * Largeur des Blocks s'ils sont rectangulaires, sinon ça vaut 0. + * Largeur des Blocks s'ils sont rectangulaires, valant 0 si ce n'est pas le cas. */ private int blockWidth; @@ -35,7 +35,7 @@ public class Sudoku { } /** - * Transforme un index de Cell en Coordiante. + * Transforme un index de Cell en Coordinate. * * @param index int, index d'une Cell. * @return Coordinate, correspondante à l'index donné. @@ -56,7 +56,7 @@ public class Sudoku { /** * Vérifie que des coordonnées correspondent bien à une Cell dans le Sudoku. - * @return boolean, wether the coords are in the sudoku + * @return boolean, valant true si les coordonnées sont dans les bornes du Sudoku, false sinon. */ public boolean isValidCoords(int x, int y) { int index = toIndex(x, y); @@ -64,12 +64,20 @@ public class Sudoku { } /** - * @return wether the coords are in the sudoku + * Vérifie que l'index correspond bien à une Cell dans le Sudoku. + * @return boolean, valant true si l'index est dans les bornes du Sudoku, false sinon. */ public boolean isValidCoords(int index) { return index < getSize() * getSize(); } + /** + * Teste si on peut placer la value dans la Cell aux coordonnées x, y d'après les contraintes du Sudoku. + * @param x int, abscisse de la Cell voulue. + * @param y int, ordonnée de la Cell voulue. + * @param value int, index du symbole qu'on veut placer. + * @return boolean, true si on peut la placer et false sinon. + */ public boolean canBePlaced(int x, int y, int value) { for (IConstraint constraint : this.constraints) { if (!constraint.canBePlaced(this, x, y, value)) { @@ -79,6 +87,13 @@ public class Sudoku { return true; } + /** + * Tente de placer le symbole value dans la Cell de coordonnées x, y. + * @param x int, abscisse de la Cell voulue. + * @param y int, coordonnée de la Cell voulue; + * @param value int, index du symbole que l'on veut placer. + * @return boolean, true si le symbole a été placé, false sinon + */ public boolean tryPlaceCellSymbol(int x, int y, int value) { assert (isValidCoords(x, y)); if (!canBePlaced(x, y, value)) @@ -88,12 +103,21 @@ public class Sudoku { return true; } + /** + * Vide la Cell dotn les coordonnées sont renseignées de son symbole. + * @param x int, abscisse de la Cell voulue. + * @param y int, coordonnée de la Cell voulue. + */ + public void clearCell(int x, int y) { assert (isValidCoords(x, y)); Cell cell = getCell(x, y); cell.setSymbolIndex(Cell.NOSYMBOL); } + /** + * Vide toutes les Cell du Sudoku. + */ public void clear() { for (int i = 0; i < getSize() * getSize(); i++) { Cell cell = getCell(i); @@ -107,9 +131,11 @@ public class Sudoku { } /** - * Try to place a cell at the given coordinate - * - * @return Cell created or null if it can't be done + * Place le symbole d'index value dans la Cell de coordonnées précisées. + * @param x int, abscisse de la Cell voulue. + * @param y int, coordonnée de la Cell voulue. + * @param value int, index du symbole à placer. + * @return Cell, la Cell qui a été modifiée. */ public Cell setCellSymbol(int x, int y, int value) { assert (isValidCoords(x, y)); @@ -123,6 +149,11 @@ public class Sudoku { return cell; } + /** + * Place les symboles d'index contenus dans values dans les cases du Sudoku. + * @param values List, liste des index des symboles à placer. + * @return boolean, vaut true si les symboles ont été placés, false sinon. + */ public boolean setCellsSymbol(List values) { if (values.size() > this.cells.size()) { return false; @@ -136,6 +167,11 @@ public class Sudoku { return true; } + /** + * Place les symboles d'index contenus dans values dans les cases du Sudoku et rend ces cases immuables. + * @param values List, liste des index des symboles à placer. + * @return boolean, vaut true si les symboles ont été placés, false sinon. + */ public boolean setImmutableCellsSymbol(List values) { if (values.size() > this.cells.size()) { return false; @@ -185,10 +221,21 @@ public class Sudoku { return this.blocks; } + /** + * Vérifie si une Cell appartient au Sudoku. + * @param cell Cell, cellule dont on veut vérifier l'appartenance au Sudoku. + * @return boolean, vaut true si la Cell appartient au Sudoku. + */ public boolean contains(Cell cell) { return this.cells.contains(cell); } + /** + * Localise la Cell dans le Sudoku. + * @param c Cell, cellule dont on veut les coordonées. + * @return Coordinate, coordonnées de la Cell. + * @throws Exception si la Cell n'appartient pas au Sudoku. + */ private Coordinate getCoordinateCell(Cell c) throws Exception { int x = 0, y = 0; int size = this.getSize(); @@ -213,7 +260,11 @@ public class Sudoku { return new Coordinate(x, y); } - public void updateSymbolsPossibilities() throws Exception { + /** + * Met à jour les symboles possibles des Cells du Sudoku. + * + */ + public void updateSymbolsPossibilities(){ for (IConstraint constraint : constraints) { List cells = this.getCells(); for (Cell cell : cells) { @@ -221,16 +272,12 @@ public class Sudoku { try { coord = this.getCoordinateCell(cell); } catch (Exception e) { - throw new RuntimeException(e); + System.out.println("Cas jamais atteint."); } List newPossibleSymbols = cell.getPossibleSymbols(); newPossibleSymbols.retainAll(constraint.getPossibleSymbols(this, coord.getX(), coord.getY())); cell.setPossibleSymbols(newPossibleSymbols); - - if (cell.getPossibleSymbols().isEmpty()) { - throw new Exception("Rollback bitch"); - } } } } @@ -249,6 +296,10 @@ public class Sudoku { return sb.toString(); } + /** + * Renvoie la 1re Cell vide du Sudoku. + * @return Cell, une Cell vide, ou null s'il n'y en a pas. + */ public Cell getFirstEmptyCell() { for (Cell cell : this.cells) { if (cell.isEmpty()) { @@ -258,6 +309,11 @@ public class Sudoku { return null; } + /** + * Renvoie l'index des symboles possibles de la Cell passée en paramètres. + * @param cellToFill Cell, cellule dont on cherche les symboles posisbles. + * @return List, la liste des index des symboles possibles, vide si la Cell n'appartient pas au Sudoku. + */ public List getPossibleSymbolsOfCell(Cell cellToFill) { List result = new ArrayList<>(); Coordinate cellCoordinates; @@ -277,6 +333,10 @@ public class Sudoku { return result; } + /** + * 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. + */ public boolean isValid() { for (Cell cell : this.cells) { if (cell.isMutable()) { diff --git a/app/src/main/java/sudoku/structure/SudokuFactory.java b/app/src/main/java/sudoku/structure/SudokuFactory.java index 88d31f9..cfa0ea7 100644 --- a/app/src/main/java/sudoku/structure/SudokuFactory.java +++ b/app/src/main/java/sudoku/structure/SudokuFactory.java @@ -14,9 +14,21 @@ import sudoku.solver.Solver; public class SudokuFactory { + /** + * Générateur de nombre aléatoire. + */ private static final Random random = new Random(); + /** + * Liste des contraintes par défaut d'un Multi- ou Sudoku. + * Comprend les contraintes de blocs, de lignes, et de colonnes. + */ public static List DEFAULT_CONSTRAINTS = Arrays.asList(new BlockConstraint(), new LineConstraint(), new ColumnConstraint()); + /** + * Créée des Cells et les met dans une liste de taille size. + * @param size int, nombre de Cells à initialiser. + * @return List, liste des Cells initialisées. + */ private static List initCells(int size) { List cells = new ArrayList<>(size * size); for (int i = 0; i < size * size; i++) { @@ -25,6 +37,13 @@ public class SudokuFactory { return cells; } + /** + * Créée des Blocks de taille width par height à partir des cellules données, et les met dans une liste. + * @param cells List, liste des Cells à découper en Blocks. + * @param width int, largeur des Blocks à créer. + * @param height int, hauteur des Blocks à créer. + * @return List, liste des Blocks créés. + */ private static List initRectangleBlocs(List cells, int width, int height) { List blocs = new ArrayList<>(); int size = width * height; @@ -48,16 +67,32 @@ public class SudokuFactory { return blocs; } + /** + * Créée un MultiDoku vide dont les Blocks sont de taille widthBlock par heightBlock. + * @param widthBlock int, largeur des Blocks. + * @param heightBlock int, hauteur des Blocks. + * @return MultiDoku, MultiDoku vide. + */ public static MultiDoku createBasicEmptyRectangleSudoku(int widthBlock, int heightBlock) { Sudoku s = createRectangleSudoku(widthBlock, heightBlock); return new MultiDoku(Arrays.asList(s)); } + /** + * Créée un MultiDoku vide dont les Blocks sont carrés de longueur size. + * @param size int, taille des Blocks. + * @return MultiDoku, MultiDoku vide. + */ public static MultiDoku createBasicEmptySquareSudoku(int size) { return createBasicEmptyRectangleSudoku(size, size); } - public static void setIMMutableCells(MultiDoku doku, Map immutableCells) { + /** + * Place des Cells immutables de valeurs fournies, aux Coordinate fournies dans le MultiDoku doku fourni. + * @param doku MultiDoku, MultiDoku à remplir. + * @param immutableCells Map, association de Coordinate coordonnées et Integer valeurs, correspondant aux cases à remplir. + */ + public static void setImmutableCells(MultiDoku doku, Map immutableCells) { immutableCells.forEach((coordinate, symbol) -> { for (Sudoku sudoku : doku.getSubGrids()) { Cell cell = sudoku.getCell(coordinate.getX(), coordinate.getY()); @@ -69,6 +104,13 @@ public class SudokuFactory { }); } + /** + * Créée un MultiDoku de difficulté difficulty à partir d'un MultiDoku fourni. + * @param doku MultiDoku, MultiDoku dont on doit vider des Cells. + * @param difficulty int, nombre de cases à retirer. + * @return boolean, valant true si un MultiDoku de difficulté donnée peut être créée, false sinon. + * @throws Exception si la difficulté n'est pas compatible avec la taille du MultiDoku. + */ public static boolean newDokuFromFilledOne (MultiDoku doku, int difficulty) throws Exception { if (difficulty > doku.getCells().size()) { @@ -100,19 +142,36 @@ public class SudokuFactory { return false; } - private static Sudoku createRectangleSudoku(int width, int height) { - int symbolCount = width * height; + /** + * Créée un Sudoku vide dont les Blocks sont de taille widthBlock par heightBlock. + * @param widthBlock int, largeur des Blocks. + * @param heightBlock int, hauteur des Blocks. + * @return Sudoku, Sudoku vide. + */ + private static Sudoku createRectangleSudoku(int widthBlock, int heightBlock) { + int symbolCount = widthBlock * heightBlock; List cases = initCells(symbolCount); - List blocs = initRectangleBlocs(cases, width, height); + List blocs = initRectangleBlocs(cases, widthBlock, heightBlock); Sudoku s = new Sudoku(cases, blocs, DEFAULT_CONSTRAINTS); - s.setBlockWidth(width); + s.setBlockWidth(widthBlock); return s; } + /** + * Créée un Sudoku vide dont les Blocks sont carrés de longueur size. + * @param size int, taille des Blocks. + * @return Sudoku, Sudoku vide. + */ private static Sudoku createSquareSudoku(int size) { return createRectangleSudoku(size, size); } + /** + * Connecte deux Sudokus selon la décalage offset fourni. + * @param sudoku1 Sudoku, premier sudoku à connecter. + * @param sudoku2 Sudoku, second sudoku à connecter. + * @param offset Coordinate, décalage entre les deux Sudokus. + */ private static void linkSquareSudokus(Sudoku sudoku1, Sudoku sudoku2, Coordinate offset) { int blockWidth = sudoku1.getBlockWidth(); for (int dx = 0; dx < blockWidth; dx++) { @@ -142,7 +201,12 @@ public class SudokuFactory { } } - public static MultiDoku createBasicSquareMultidoku(int size) { + /** + * Créée un MultiDoku de Blocks carrés de taille size composé de cinq Sudokus, dont un central qui partage chacun de ses Blockss d'angle avec un autre Sudoku. + * @param size int, largeur des Blocks unitraires des Sudokus à crééer. + * @return MultiDoku, MultiDoku de forme X. + */ + public static MultiDoku createBasicXShapedMultidoku(int size) { assert (size > 1); /**