package sudoku.structure; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Random; import java.util.Set; import sudoku.io.SudokuSerializer; /** * @class MultiDoku * @brief Représente une grille de Multidoku. * Une grille de sudoku est un multidoku avec un seul sous-sudoku */ public class MultiDoku { /** * Liste des sous-Sudoku contenue dans le multidoku. */ private final List subGrids; private final StateManager stateManager; public MultiDoku(List subGrids) { this.subGrids = subGrids; this.stateManager = new StateManager(this); } /** * Renvoie le nombre de sudoku contenu dans ce MultiDoku. * * @return int */ public int getNbSubGrids() { return subGrids.size(); } /** * Renvoie la ie sudoku contenue dans ce MultiDoku. * * @param i int, indice du sudoku à renvoyer. * @return Sudoku, ie Sudoku */ public Sudoku getSubGrid(int i) { return subGrids.get(i); } /** * Renvoie la liste des Cells contenue dans ce MultiDoku, * soit les Cells contenues de chaques sous-Sudoku. * * @return List */ public List getCells() { Set cellsSet = new HashSet<>(); for (Sudoku sudoku : subGrids) { cellsSet.addAll(sudoku.getCells()); } return new ArrayList<>(cellsSet); } @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append("Multidoku {"); for (Sudoku sudoku : subGrids) { sb.append("\n\t").append(sudoku.toString()); } sb.append("\n}"); return sb.toString(); } /** * Renvoie les sous-Sudoku * * @return List */ public List getSubGrids() { return this.subGrids; } /** * Check si le MultiDoku est résolu, c'est à dire complet et cohérent avec ses contraintes. * * @return boolean, true s'il est résolu et false sinon. */ public boolean isSolved() { for (Sudoku sudoku : this.subGrids) { if (!sudoku.isSolved()) return false; } return true; } /** * Renvoie la 1re Cell vide des sous-Sudoku. * * @return Cell, une Cell vide, ou null s'il n'y en a pas. */ public Cell getFirstEmptyCell() { for (Sudoku sudoku : this.subGrids) { Cell cellTmp = sudoku.getFirstEmptyCell(); if (cellTmp != null) { return cellTmp; } } return null; } /** * Renvoie la liste des Cells préalablement remplies du MultiDoku. * * @return List, vide si aucune Cell n'est remplie. */ public List getFilledCells() { List result = new ArrayList<>(); for (Cell cell : this.getCells()) { if (!cell.isEmpty()) { result.add(cell); } } return result; } /** * Renvoie la liste des Cells vides du MultiDoku. * * @return List, vide si aucune Cell ne l'est. */ public List getEmptyCells() { List result = new ArrayList<>(); for (Cell cell : this.getCells()) { if (cell.isEmpty()) { result.add(cell); } } return result; } /** * Vide une Cell donnée. * * @param cell Cell, à vider. */ public void empty(Cell cell) { List cells = getCells(); Cell cellToEmpty = cells.get(cells.indexOf(cell)); cellToEmpty.setSymbolIndex(Cell.NOSYMBOL); } /** * Renvoie le nombre de Cell contenue dans le MultiDoku. * * @return int, nombre de Cell dans le MultiDoku. */ public int getNbCells() { return getCells().size(); } /** * Change les Cells de ce MultiDoku avec des symboles, en Cells immuables. */ public void setFilledCellsImmutable() { for (Cell filledCell : getFilledCells()) { filledCell.setImmutable(); } } public StateManager getStateManager() { 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); } public void clearMutableCells() { for (Sudoku s : getSubGrids()) { for (Cell cell : s.getCells()) { if (cell.isMutable()) cell.clearCurrentSymbol(); } } } public MultiDoku clone() { // TODO: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaah return SudokuSerializer.deserializeSudoku(SudokuSerializer.serializeSudoku(this)); } }