package sudoku; import sudoku.constraint.IConstraint; import java.util.ArrayList; import java.util.List; /** * @class Sudoku * @brief Represents a sudoku */ public class Sudoku { private final List blocks; private final List cells; private final List constraints; public Sudoku(List cells, List blocks, List constraints) { this.cells = cells; this.blocks = blocks; this.constraints = constraints; } /** * @return wether the coords are in the sudoku */ public boolean isValidCoords(int x, int y) { int index = y * getSize() + x; return index < getSize() * getSize(); } /** * Try to place a cell at the given coordinate * * @return false if it can't be done */ public boolean setCellSymbol(int x, int y, int value) { assert (isValidCoords(x, y)); for (IConstraint constraint : this.constraints) { if (!constraint.canBePlaced(this, x, y, value)) { return false; } } Cell cell = getCell(x, y); if (cell instanceof MutableCell mCell) { mCell.setSymbolIndex(value); return true; } return false; } 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); if (!this.setCellSymbol(x, y, value)) { return false; } } return true; } public Cell getCell(int x, int y) { int index = y * getSize() + x; assert (isValidCoords(x, y)); return this.cells.get(index); } public Cell getCell(int i) { return this.cells.get(i); } public List getConstraints() { return constraints; } public int getSize() { return this.blocks.size(); } public List getCells() { return this.cells; } public List getBlocks() { return this.blocks; } public List getMutableCells() { List mutableCells = new ArrayList<>(); for (Cell cell : this.cells) { if (cell instanceof MutableCell) { mutableCells.add((MutableCell) cell); } } return mutableCells; } public boolean contains(Cell cell) { return this.cells.contains(cell); } private Coordinate getCoordinateCell(Cell c) throws Exception { int x = 0, y = 0; int size = this.getSize(); if (!this.contains(c)) { throw new Exception("The given cell is not in this sudoku."); } for (Cell cell : this.cells) { if (cell == c) { return new Coordinate(x, y); } if (x == size - 1) { y += 1; x = 0; } else { x += 1; } } return new Coordinate(x, y); } public void updateSymbolsPossibilities() throws Exception { for (IConstraint constraint : constraints) { List mutableCells = this.getMutableCells(); for (MutableCell cell : mutableCells) { Coordinate coord = null; try { coord = this.getCoordinateCell(cell); } catch (Exception e) { throw new RuntimeException(e); } 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"); } } } } 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(); } public MutableCell getFirstEmptyMutableCell() { for (MutableCell cell : this.getMutableCells()) { if (cell.isEmpty()) { return cell; } } return null; } public List getPossibleSymbolsOfCell(MutableCell cellToFill) { List result = new ArrayList<>(); Coordinate cellCoordinates; try { cellCoordinates = this.getCoordinateCell(cellToFill); } catch (Exception e) { return result; } for (IConstraint constraint : this.constraints) { if (result.isEmpty()) { result.addAll(constraint.getPossibleSymbols(this, cellCoordinates.getX(), cellCoordinates.getY())); } else { result.retainAll(constraint.getPossibleSymbols(this, cellCoordinates.getX(), cellCoordinates.getY())); } } return result; } }