package sudoku.structure; import sudoku.constraint.Constraint; import sudoku.constraint.IConstraint; import java.util.List; /** * Class : Sudoku * Brief : Représent un Sudoku */ public class Sudoku { // /** * Liste des Block contenus dans le Sudoku. */ private final List blocks; /** * Liste des Cells contenus dans le Sudoku. */ private final List cells; /** * Liste des contraintes (TODO) du Sudoku. */ private final List constraints; /** * Largeur des Blocks s'ils sont rectangulaires, * valant 0 si ce n'est pas le cas. */ private int blockWidth; // // public Sudoku(List cells, List blocks, List constraints) { this.cells = cells; this.blocks = blocks; this.constraints = constraints; } /** * Transforme un index de Cell en Coordinate. * * @param index int, index d'une Cell. * @return Coordinate, correspondante à l'index donné. */ public Coordinate toCoords(int index) { return new Coordinate(index % getSize(), index / getSize()); } /** * Transforme des coordonées d'une Cell en index. * * @param x int, abscisse. * @param y int, ordonnée. * @return int, index correspondant. */ public int toIndex(int x, int y) { return y * getSize() + x; } /** * Vérifie que des coordonnées correspondent bien à une Cell dans le 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); return isValidCoords(index); } /** * 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)) { return false; } } return true; } /** * 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 isSolved() { boolean isComplete = isComplete(); boolean isValid = isValid(); return isComplete && isValid; } /** * 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; } /** * 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 (int i = 0; i < cells.size(); i++) { Cell cell = getCell(i); if (cell.isEmpty()) continue; Coordinate coordinate = toCoords(i); int symbolPlaced = cell.empty(); if (!canBePlaced(coordinate.getX(), coordinate.getY(), symbolPlaced)) { cell.setSymbolIndex(symbolPlaced); return false; } cell.setSymbolIndex(symbolPlaced); } return true; } /** * Renvoie la Cell aux coordonées données. * * @param x int, abscisse. * @param y int, ordonnée. * @return Cell, si une Cell existe aux coordonnées données, null sinon. */ public Cell getCell(int x, int y) { int index = toIndex(x, y); assert (isValidCoords(x, y)); try { return this.cells.get(index); } catch (IndexOutOfBoundsException e) { return null; } } /** * 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()) { return cell; } } return null; } /** * 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)); for (IConstraint constraint : this.constraints) { if (!constraint.canBePlaced(this, x, y, value)) { return null; } } Cell cell = getCell(x, y); cell.setSymbolIndex(value); return cell; } /** * Place les symboles d'index contenus dans values dans les cases du Sudoku. * * @param values List~Integer~, 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; } for (int i = 0; i < values.size(); i++) { int x = i % this.blocks.size(); int y = (i - x) / this.blocks.size(); int value = values.get(i); this.setCellSymbol(x, y, value); } return true; } /** * Place les symboles d'index contenus dans values dans les cases du Sudoku et * rend ces cases immuables. * * @param values List~Integer~, 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; } for (int i = 0; i < values.size(); i++) { int x = i % this.blocks.size(); int y = (i - x) / this.blocks.size(); int value = values.get(i); if (value != Cell.NOSYMBOL) { Cell cellPlaced = this.setCellSymbol(x, y, value); if (cellPlaced == null) { continue; } cellPlaced.setImmutable(); } } return true; } public boolean hasConstraint(Constraint constraint) { return this.constraints.contains(constraint.getConstraint()); } public Cell getCell(int i) { return this.cells.get(i); } public int getSize() { return this.blocks.size(); } public List getCells() { return this.cells; } public List getBlocks() { return this.blocks; } public List getConstraints() { return constraints; } public int getBlockWidth() { return blockWidth; } public void setBlockWidth(int blockWidth) { this.blockWidth = blockWidth; } @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append("Sudoku {"); for (int i = 0; i < getSize(); i++) { sb.append("\n\t"); for (int j = 0; j < getSize(); j++) { Cell cell = getCell(i, j); sb.append(cell.toString()).append(" "); } } sb.append("\n}"); return sb.toString(); } // }