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();
}
//
}
| |