# Conflicts: # app/src/main/java/sudoku/Main.java # app/src/main/java/sudoku/Sudoku.java
This commit is contained in:
@@ -31,4 +31,12 @@ public class Block {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean containsCell(Cell cell) {
|
||||||
|
for (Cell cellTmp : this.cells) {
|
||||||
|
if (cellTmp.equals(cell)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,94 +1,74 @@
|
|||||||
package sudoku;
|
package sudoku;
|
||||||
|
|
||||||
import org.checkerframework.checker.units.qual.C;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public abstract class Cell {
|
public class Cell {
|
||||||
|
|
||||||
protected static int NOSYMBOL = -1;
|
public static int NOSYMBOL = -1;
|
||||||
protected int symbolIndex;
|
|
||||||
protected Block block = null;
|
private Block blockContainer;
|
||||||
//protected List<Block> blockContainers = null;
|
private int symbolIndex = Cell.NOSYMBOL;
|
||||||
//protected List<Sudoku> sudokuContainers = null;
|
private final List<Integer> possibleSymbols;
|
||||||
|
private boolean isMutable = true;
|
||||||
|
|
||||||
|
public Cell() {
|
||||||
|
this.possibleSymbols = new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
public Cell(int symbolIndex) {
|
public Cell(int symbolIndex) {
|
||||||
this.symbolIndex = symbolIndex;
|
this.symbolIndex = symbolIndex;
|
||||||
|
this.possibleSymbols = new ArrayList<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Default constructor, empty square
|
|
||||||
*/
|
|
||||||
public Cell() {
|
|
||||||
this(NOSYMBOL);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
public Cell(Cell cell) {
|
|
||||||
this.symbolIndex = cell.symbolIndex;
|
|
||||||
this.sudokuContainers = cell.sudokuContainers;
|
|
||||||
this.blockContainers = cell.blockContainers;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Cell(List<Sudoku> sudokuContainers, List<Block> blockContainers) {
|
|
||||||
super();
|
|
||||||
this.sudokuContainers = new ArrayList<>(sudokuContainers);
|
|
||||||
this.blockContainers = new ArrayList<>(blockContainers);
|
|
||||||
}
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
public int getSymbolIndex() {
|
public int getSymbolIndex() {
|
||||||
return symbolIndex;
|
return this.symbolIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSymbolIndex(int symbolIndex) {
|
||||||
|
this.symbolIndex = symbolIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPossibleSymbols(List<Integer> possibleSymbols) {
|
||||||
|
this.possibleSymbols.clear();
|
||||||
|
this.possibleSymbols.addAll(possibleSymbols);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setImmutable() {
|
||||||
|
this.isMutable = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Block getBlock() {
|
public Block getBlock() {
|
||||||
return this.block;
|
return this.blockContainer;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
public List<Block> getBlockContainers() {
|
|
||||||
return this.blockContainers;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setBlockContainers(List<Block> block) {
|
|
||||||
this.blockContainers = block;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<Sudoku> getSudokuContainers() {
|
|
||||||
return this.sudokuContainers;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
// only SudokuFactory and SudokuSerializer should access this
|
|
||||||
public void setBlock(Block block) {
|
public void setBlock(Block block) {
|
||||||
this.block = block;
|
this.blockContainer = block;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/**
|
||||||
public void setSudokuContainers(List<Sudoku> sudoku) {
|
* Remove the current symbolIndex and returns it
|
||||||
this.sudokuContainers = sudoku;
|
* @return integer symbolIndex cleared
|
||||||
}
|
*/
|
||||||
*/
|
public int clearCurrentSymbol() {
|
||||||
|
int i = this.symbolIndex;
|
||||||
public boolean equalsValue(Cell otherCell) {
|
setSymbolIndex(NOSYMBOL);
|
||||||
return otherCell.getSymbolIndex() == this.getSymbolIndex();
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public boolean isEmpty() {
|
||||||
public String toString() {
|
return this.symbolIndex == Cell.NOSYMBOL;
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
sb.append("| ");
|
|
||||||
if (this.symbolIndex != NOSYMBOL){
|
|
||||||
sb.append(this.symbolIndex);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
sb.append(" ");
|
|
||||||
}
|
|
||||||
|
|
||||||
sb.append(" |");
|
|
||||||
return sb.toString();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void removeSymbolFromPossibilities(int indexSymbol) {
|
||||||
|
possibleSymbols.remove(indexSymbol);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Integer> getPossibleSymbols() {
|
||||||
|
return this.possibleSymbols;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isMutable() {
|
||||||
|
return this.isMutable;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,9 +5,9 @@ public class Coordinate {
|
|||||||
private int x;
|
private int x;
|
||||||
private int y;
|
private int y;
|
||||||
|
|
||||||
public Coordinate(int row, int col) {
|
public Coordinate(int x, int y) {
|
||||||
this.x = row;
|
this.x = x;
|
||||||
this.y = col;
|
this.y = y;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getX() {
|
public int getX() {
|
||||||
|
|||||||
@@ -3,10 +3,10 @@
|
|||||||
*/
|
*/
|
||||||
package sudoku;
|
package sudoku;
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
import sudoku.io.SudokuPrinter;
|
import sudoku.io.SudokuPrinter;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
public class Main {
|
public class Main {
|
||||||
public String getGreeting() {
|
public String getGreeting() {
|
||||||
return "Hello World!";
|
return "Hello World!";
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
package sudoku;
|
package sudoku;
|
||||||
|
|
||||||
import sudoku.constraint.IConstraint;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -26,12 +24,12 @@ public class MultiDoku {
|
|||||||
return subGrids.get(i);
|
return subGrids.get(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<MutableCell> getMutableCells(){
|
public List<Cell> getCells(){
|
||||||
List<MutableCell> mutableCells = new ArrayList<>();
|
List<Cell> cells = new ArrayList<>();
|
||||||
for (Sudoku sudoku : subGrids){
|
for (Sudoku sudoku : subGrids){
|
||||||
mutableCells.addAll(sudoku.getMutableCells());
|
cells.addAll(sudoku.getCells());
|
||||||
}
|
}
|
||||||
return mutableCells;
|
return cells;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateSymbolsPossibilities() throws Exception {
|
public void updateSymbolsPossibilities() throws Exception {
|
||||||
@@ -50,4 +48,55 @@ public class MultiDoku {
|
|||||||
sb.append("\n}");
|
sb.append("\n}");
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Cell getFirstEmptyCell() {
|
||||||
|
for (Sudoku sudoku : this.subGrids) {
|
||||||
|
Cell cellTmp = sudoku.getFirstEmptyCell();
|
||||||
|
if (cellTmp != null && cellTmp.isEmpty()) {
|
||||||
|
return cellTmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Integer> getPossibleSymbolsOfCell(Cell cellToFill) {
|
||||||
|
for (Sudoku sudoku : this.subGrids) {
|
||||||
|
if (sudoku.contains(cellToFill)) {
|
||||||
|
return sudoku.getPossibleSymbolsOfCell(cellToFill);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Sudoku> getSubGrids() {
|
||||||
|
return this.subGrids;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isValid() {
|
||||||
|
boolean result = true;
|
||||||
|
for (Sudoku sudoku : this.subGrids) {
|
||||||
|
result = sudoku.isValid() && result;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object object) {
|
||||||
|
if (!(object instanceof MultiDoku)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.getNbSubGrids() != ((MultiDoku) object).getNbSubGrids()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < this.getNbSubGrids(); i++) {
|
||||||
|
if (!this.getSubGrid(i).equals(((MultiDoku) object).getSubGrid(i))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,47 +0,0 @@
|
|||||||
package sudoku;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class MutableCell extends Cell{
|
|
||||||
|
|
||||||
private final List<Integer> possibleSymbols;
|
|
||||||
|
|
||||||
public MutableCell() {
|
|
||||||
super();
|
|
||||||
this.possibleSymbols = new ArrayList<>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public MutableCell(int symbolIndex) {
|
|
||||||
super(symbolIndex);
|
|
||||||
this.possibleSymbols = new ArrayList<>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSymbolIndex(int symbolIndex) {
|
|
||||||
this.symbolIndex = symbolIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPossibleSymbols(List<Integer> possibleSymbols) {
|
|
||||||
this.possibleSymbols.clear();
|
|
||||||
this.possibleSymbols.addAll(possibleSymbols);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove the current symbolIndex and returns it
|
|
||||||
* @return integer symbolIndex cleared
|
|
||||||
*/
|
|
||||||
public int clearCurrentSymbol() {
|
|
||||||
int i = this.symbolIndex;
|
|
||||||
setSymbolIndex(NOSYMBOL);
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void removeSymbolFromPossibilities(int indexSymbol) {
|
|
||||||
possibleSymbols.remove(indexSymbol);
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<Integer> getPossibleSymbols() {
|
|
||||||
return this.possibleSymbols;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -14,6 +14,7 @@ public class Sudoku {
|
|||||||
private final List<Block> blocks;
|
private final List<Block> blocks;
|
||||||
private final List<Cell> cells;
|
private final List<Cell> cells;
|
||||||
private final List<IConstraint> constraints;
|
private final List<IConstraint> constraints;
|
||||||
|
private boolean isMutable;
|
||||||
|
|
||||||
public Sudoku(List<Cell> cells, List<Block> blocks, List<IConstraint> constraints) {
|
public Sudoku(List<Cell> cells, List<Block> blocks, List<IConstraint> constraints) {
|
||||||
this.cells = cells;
|
this.cells = cells;
|
||||||
@@ -32,21 +33,18 @@ public class Sudoku {
|
|||||||
/**
|
/**
|
||||||
* Try to place a cell at the given coordinate
|
* Try to place a cell at the given coordinate
|
||||||
*
|
*
|
||||||
* @return false if it can't be done
|
* @return Cell created or null if it can't be done
|
||||||
*/
|
*/
|
||||||
public boolean setCellSymbol(int x, int y, int value) {
|
public Cell setCellSymbol(int x, int y, int value) {
|
||||||
assert (isValidCoords(x, y));
|
assert (isValidCoords(x, y));
|
||||||
for (IConstraint constraint : this.constraints) {
|
for (IConstraint constraint : this.constraints) {
|
||||||
if (!constraint.canBePlaced(this, x, y, value)) {
|
if (!constraint.canBePlaced(this, x, y, value)) {
|
||||||
return false;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Cell cell = getCell(x, y);
|
Cell cell = getCell(x, y);
|
||||||
if (cell instanceof MutableCell mCell) {
|
cell.setSymbolIndex(value);
|
||||||
mCell.setSymbolIndex(value);
|
return cell;
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean setCellsSymbol(List<Integer> values) {
|
public boolean setCellsSymbol(List<Integer> values) {
|
||||||
@@ -55,19 +53,41 @@ public class Sudoku {
|
|||||||
}
|
}
|
||||||
for (int i = 0; i < values.size(); i++) {
|
for (int i = 0; i < values.size(); i++) {
|
||||||
int x = i % this.blocks.size();
|
int x = i % this.blocks.size();
|
||||||
int y = (i - x) / this.blocks.size();
|
int y = (i-x) / this.blocks.size();
|
||||||
int value = values.get(i);
|
int value = values.get(i);
|
||||||
if (!this.setCellSymbol(x, y, value)) {
|
this.setCellSymbol(x, y, value);
|
||||||
return false;
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean setImmutableCellsSymbol(List<Integer> 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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public Cell getCell(int x, int y) {
|
public Cell getCell(int x, int y) {
|
||||||
int index = y * getSize() + x;
|
int index = y * getSize() + x;
|
||||||
assert (isValidCoords(x, y));
|
assert (isValidCoords(x, y));
|
||||||
return this.cells.get(index);
|
try {
|
||||||
|
return this.cells.get(index);
|
||||||
|
} catch (IndexOutOfBoundsException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Cell getCell(int i) {
|
public Cell getCell(int i) {
|
||||||
@@ -82,12 +102,6 @@ public class Sudoku {
|
|||||||
return this.blocks.size();
|
return this.blocks.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isValid(List<IConstraint> constraints) {
|
|
||||||
// not implemented
|
|
||||||
// for eachcase check contraintes
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<Cell> getCells() {
|
public List<Cell> getCells() {
|
||||||
return this.cells;
|
return this.cells;
|
||||||
}
|
}
|
||||||
@@ -96,16 +110,6 @@ public class Sudoku {
|
|||||||
return this.blocks;
|
return this.blocks;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<MutableCell> getMutableCells() {
|
|
||||||
List<MutableCell> mutableCells = new ArrayList<>();
|
|
||||||
for (Cell cell : this.cells) {
|
|
||||||
if (cell instanceof MutableCell) {
|
|
||||||
mutableCells.add((MutableCell) cell);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return mutableCells;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean contains(Cell cell) {
|
public boolean contains(Cell cell) {
|
||||||
return this.cells.contains(cell);
|
return this.cells.contains(cell);
|
||||||
}
|
}
|
||||||
@@ -134,8 +138,8 @@ public class Sudoku {
|
|||||||
|
|
||||||
public void updateSymbolsPossibilities() throws Exception {
|
public void updateSymbolsPossibilities() throws Exception {
|
||||||
for (IConstraint constraint : constraints) {
|
for (IConstraint constraint : constraints) {
|
||||||
List<MutableCell> mutableCells = this.getMutableCells();
|
List<Cell> cells = this.getCells();
|
||||||
for (MutableCell cell : mutableCells) {
|
for (Cell cell : cells) {
|
||||||
Coordinate coord = null;
|
Coordinate coord = null;
|
||||||
try {
|
try {
|
||||||
coord = this.getCoordinateCell(cell);
|
coord = this.getCoordinateCell(cell);
|
||||||
@@ -154,7 +158,6 @@ public class Sudoku {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
public String toString() {
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
sb.append("Sudoku {");
|
sb.append("Sudoku {");
|
||||||
@@ -168,4 +171,78 @@ public class Sudoku {
|
|||||||
sb.append("\n}");
|
sb.append("\n}");
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Cell getFirstEmptyCell() {
|
||||||
|
for (Cell cell : this.cells) {
|
||||||
|
if (cell.isEmpty()) {
|
||||||
|
return cell;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Integer> getPossibleSymbolsOfCell(Cell cellToFill) {
|
||||||
|
List<Integer> 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isValid() {
|
||||||
|
for (Cell cell : this.cells) {
|
||||||
|
if (cell.isMutable()) {
|
||||||
|
if (cell.isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (IConstraint constraint : this.constraints) {
|
||||||
|
Coordinate coords;
|
||||||
|
try {
|
||||||
|
int symbolPlaced = cell.getSymbolIndex();
|
||||||
|
coords = this.getCoordinateCell(cell);
|
||||||
|
|
||||||
|
cell.setSymbolIndex(Cell.NOSYMBOL);
|
||||||
|
List<Integer> possibleSymbols = constraint.getPossibleSymbols(this, coords.getX(), coords.getY());
|
||||||
|
cell.setSymbolIndex(symbolPlaced);
|
||||||
|
if (possibleSymbols.size() != 1 || possibleSymbols.get(0) != symbolPlaced) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object object) {
|
||||||
|
if (!(object instanceof Sudoku)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.getSize() != ((Sudoku) object).getSize()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < this.getSize(); i++) {
|
||||||
|
if (this.getCell(i).getSymbolIndex() != ((Sudoku) object).getCell(i).getSymbolIndex()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,13 +7,14 @@ import sudoku.constraint.LineConstraint;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
public class SudokuFactory {
|
public class SudokuFactory {
|
||||||
|
|
||||||
private static List<Cell> initCells(int size) {
|
private static List<Cell> initCells(int size) {
|
||||||
List<Cell> cells = new ArrayList<>(size * size);
|
List<Cell> cells = new ArrayList<>(size * size);
|
||||||
for (int i = 0; i < size * size; i++) {
|
for (int i = 0; i < size * size; i++) {
|
||||||
cells.add(new MutableCell());
|
cells.add(new Cell());
|
||||||
}
|
}
|
||||||
return cells;
|
return cells;
|
||||||
}
|
}
|
||||||
@@ -59,4 +60,15 @@ public class SudokuFactory {
|
|||||||
return createBasicEmptyRectangleSudoku(size, size);
|
return createBasicEmptyRectangleSudoku(size, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void setIMMutableCells(MultiDoku doku, Map<Coordinate, Integer> immutableCells) {
|
||||||
|
immutableCells.forEach((coordinate, symbol) -> {
|
||||||
|
for (Sudoku sudoku : doku.getSubGrids()) {
|
||||||
|
Cell cell = sudoku.getCell(coordinate.getX(), coordinate.getY());
|
||||||
|
if (cell != null) {
|
||||||
|
cell.setSymbolIndex(symbol);
|
||||||
|
cell.setImmutable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,15 @@
|
|||||||
package sudoku.constraint;
|
package sudoku.constraint;
|
||||||
|
|
||||||
import sudoku.Block;
|
import sudoku.Block;
|
||||||
|
import sudoku.Cell;
|
||||||
import sudoku.Sudoku;
|
import sudoku.Sudoku;
|
||||||
|
|
||||||
public class BlockConstraint implements IConstraint{
|
public class BlockConstraint implements IConstraint{
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean canBePlaced(final Sudoku s, int x, int y, int newSymbolIndex) {
|
public boolean canBePlaced(final Sudoku s, int x, int y, int newSymbolIndex) {
|
||||||
Block bloc = s.getCell(x, y).getBlock();
|
Block block = s.getCell(x, y).getBlock();
|
||||||
return !bloc.containsSymbol(newSymbolIndex);
|
return !block.containsSymbol(newSymbolIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,17 +10,16 @@ import sudoku.Block;
|
|||||||
import sudoku.Cell;
|
import sudoku.Cell;
|
||||||
import sudoku.ImmutableCell;
|
import sudoku.ImmutableCell;
|
||||||
import sudoku.MultiDoku;
|
import sudoku.MultiDoku;
|
||||||
import sudoku.MutableCell;
|
|
||||||
import sudoku.Sudoku;
|
import sudoku.Sudoku;
|
||||||
|
|
||||||
public class SudokuSerializer {
|
public class SudokuSerializer {
|
||||||
|
|
||||||
public static String serializeSudoku(final MultiDoku multidoku) {
|
public static String serializeSudoku(final MultiDoku multidoku) {
|
||||||
List<Cell> cellIds = new ArrayList<>();
|
List<Cell> cellIds = new ArrayList<>();
|
||||||
List<Block> blockIds = new ArrayList<>();
|
List<Block> blockIds = new ArrayList<>();
|
||||||
|
|
||||||
JSONObject jsonRoot = new JSONObject();
|
JSONObject jsonRoot = new JSONObject();
|
||||||
JSONArray jsonCells = new JSONArray();
|
JSONArray jsonCells = new JSONArray();
|
||||||
JSONArray jsonBlocks = new JSONArray();
|
JSONArray jsonBlocks = new JSONArray();
|
||||||
JSONArray jsonSudokus = new JSONArray(multidoku.getNbSubGrids());
|
JSONArray jsonSudokus = new JSONArray(multidoku.getNbSubGrids());
|
||||||
|
|
||||||
@@ -55,17 +54,16 @@ public class SudokuSerializer {
|
|||||||
|
|
||||||
// init blocks
|
// init blocks
|
||||||
|
|
||||||
for (int i = 0; i < blockIds.size(); i++) {
|
for (Block blockId : blockIds) {
|
||||||
JSONObject blockJsonObject = new JSONObject();
|
JSONObject blockJsonObject = new JSONObject();
|
||||||
JSONArray cellsJsonArray = new JSONArray();
|
JSONArray cellsJsonArray = new JSONArray();
|
||||||
Block block = blockIds.get(i);
|
for (Cell cell : blockId.getCells()) {
|
||||||
for (Cell cell : block.getCells()) {
|
int cellID = cellIds.indexOf(cell);
|
||||||
int cellID = cellIds.indexOf(cell);
|
cellsJsonArray.put(cellID);
|
||||||
cellsJsonArray.put(cellID);
|
}
|
||||||
}
|
blockJsonObject.put("cellIDs", cellsJsonArray);
|
||||||
blockJsonObject.put("cellIDs", cellsJsonArray);
|
jsonBlocks.put(blockJsonObject);
|
||||||
jsonBlocks.put(blockJsonObject);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < multidoku.getNbSubGrids(); i++) {
|
for (int i = 0; i < multidoku.getNbSubGrids(); i++) {
|
||||||
// serialise sub grid
|
// serialise sub grid
|
||||||
@@ -115,7 +113,7 @@ public class SudokuSerializer {
|
|||||||
if (entry.has("immutable")) {
|
if (entry.has("immutable")) {
|
||||||
cells.add(new ImmutableCell(symboleIndex));
|
cells.add(new ImmutableCell(symboleIndex));
|
||||||
} else {
|
} else {
|
||||||
cells.add(new MutableCell(symboleIndex));
|
cells.add(new Cell(symboleIndex));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,23 +1,53 @@
|
|||||||
package sudoku.solver;
|
package sudoku.solver;
|
||||||
|
|
||||||
import sudoku.MultiDoku;
|
import sudoku.MultiDoku;
|
||||||
import sudoku.MutableCell;
|
import sudoku.Cell;
|
||||||
import sudoku.constraint.IConstraint;
|
import sudoku.io.SudokuPrinter;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Random;
|
|
||||||
import java.util.Stack;
|
|
||||||
|
|
||||||
public class Solver {
|
public class Solver {
|
||||||
Stack<MutableCell> stack;
|
|
||||||
|
|
||||||
public Solver() {}
|
/**
|
||||||
|
* Résout le multidoku passé en paramètre si c'est possible.
|
||||||
|
* En testant toutes les possibilités avec un algorithme de backtracking.
|
||||||
|
* @param doku Multidoku, à résoudre
|
||||||
|
* @return boolean, true s'il est résolut ou false s'il ne l'est pas.
|
||||||
|
*/
|
||||||
|
public static boolean solve(MultiDoku doku) {
|
||||||
|
if (doku.isValid()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Cell cellToFill = doku.getFirstEmptyCell();
|
||||||
|
if (cellToFill == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Integer> possibleSymbols = doku.getPossibleSymbolsOfCell(cellToFill);
|
||||||
|
if (possibleSymbols.isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int symbol : possibleSymbols) {
|
||||||
|
cellToFill.setSymbolIndex(symbol);
|
||||||
|
if (Solver.solve(doku)) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
cellToFill.setSymbolIndex(Cell.NOSYMBOL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Ancien algo abandonné pour le moment
|
||||||
|
|
||||||
private void rollBack() {
|
private void rollBack() {
|
||||||
stack.pop();
|
stack.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public MultiDoku solve(MultiDoku doku, List<IConstraint> constraints) throws Exception {
|
public MultiDoku solve(MultiDoku doku, List<IConstraint> constraints) throws Exception {
|
||||||
List<MutableCell> allMutableCells = doku.getMutableCells();
|
List<MutableCell> allMutableCells = doku.getMutableCells();
|
||||||
List<MutableCell> remainingCellsToCheck = new ArrayList<>(allMutableCells);
|
List<MutableCell> remainingCellsToCheck = new ArrayList<>(allMutableCells);
|
||||||
@@ -39,4 +69,6 @@ public class Solver {
|
|||||||
}
|
}
|
||||||
return doku;
|
return doku;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|||||||
85
app/src/test/java/sudoku/solver/SolverTest.java
Normal file
85
app/src/test/java/sudoku/solver/SolverTest.java
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
package sudoku.solver;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import sudoku.*;
|
||||||
|
import sudoku.io.SudokuPrinter;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
class SolverTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void solveTest() {
|
||||||
|
|
||||||
|
MultiDoku dokuToTest = SudokuFactory.createBasicEmptySquareSudoku(3);
|
||||||
|
MultiDoku dokuResult = SudokuFactory.createBasicEmptySquareSudoku(3);
|
||||||
|
|
||||||
|
Sudoku sudokuToTest = dokuToTest.getSubGrid(0);
|
||||||
|
Sudoku sudokuResult = dokuResult.getSubGrid(0);
|
||||||
|
|
||||||
|
int ns = Cell.NOSYMBOL;
|
||||||
|
List<Integer> immutableCells = List.of(ns, ns, 0, ns, ns, 2, 8, ns, 1,
|
||||||
|
ns, 3, ns, ns, 5, 6, 7, ns, ns,
|
||||||
|
ns, ns, ns, 8, ns, 7, ns, ns, 6,
|
||||||
|
0, ns, 1, ns, ns, ns, ns, ns, ns,
|
||||||
|
4, 8, 7, 5, 1, ns, 6, ns, ns,
|
||||||
|
6, ns, 3, 2, ns, ns, ns, 8, 0,
|
||||||
|
ns, ns, 6, ns, ns, 8, ns, 7, 5,
|
||||||
|
8, 0, ns, 7, ns, 5, 2, ns, 3,
|
||||||
|
5, ns, ns, ns, 3, 1, 0, ns, ns);
|
||||||
|
|
||||||
|
assert(sudokuToTest.setImmutableCellsSymbol(immutableCells));
|
||||||
|
|
||||||
|
|
||||||
|
SudokuPrinter.printRectangleSudoku(dokuToTest.getSubGrid(0), 3, 3);
|
||||||
|
|
||||||
|
|
||||||
|
List<Integer> correctCells = List.of(7, 6, 0, 3, 4, 2, 8, 5, 1,
|
||||||
|
2, 3, 8, 1, 5, 6, 7, 0, 4,
|
||||||
|
1, 4, 5, 8, 0, 7, 3, 2, 6,
|
||||||
|
0, 2, 1, 6, 8, 3, 5, 4, 7,
|
||||||
|
4, 8, 7, 5, 1, 0, 6, 3, 2,
|
||||||
|
6, 5, 3, 2, 7, 4, 1, 8, 0,
|
||||||
|
3, 1, 6, 0, 2, 8, 4, 7, 5,
|
||||||
|
8, 0, 4, 7, 6, 5, 2, 1, 3,
|
||||||
|
5, 7, 2, 4, 3, 1, 0, 6, 8);
|
||||||
|
|
||||||
|
sudokuResult.setCellsSymbol(correctCells);
|
||||||
|
|
||||||
|
|
||||||
|
System.out.println("\n****************************Doku Control\n");
|
||||||
|
SudokuPrinter.printRectangleSudoku(sudokuResult, 3, 3);
|
||||||
|
|
||||||
|
|
||||||
|
assert(dokuResult.isValid());
|
||||||
|
|
||||||
|
Solver.solve(dokuToTest);
|
||||||
|
|
||||||
|
|
||||||
|
System.out.println("\n****************************\nDoku solved");
|
||||||
|
SudokuPrinter.printRectangleSudoku(dokuToTest.getSubGrid(0), 3, 3);
|
||||||
|
|
||||||
|
|
||||||
|
assert(dokuToTest.isValid());
|
||||||
|
|
||||||
|
assert(dokuToTest.equals(dokuResult));
|
||||||
|
|
||||||
|
MultiDoku dokuToTest2 = SudokuFactory.createBasicEmptySquareSudoku(3);
|
||||||
|
Sudoku sudokuToTest2 = dokuToTest2.getSubGrid(0);
|
||||||
|
|
||||||
|
List<Integer> immutableCells2 = List.of(ns, ns, 0, ns, ns, 2, 8, ns, 1,
|
||||||
|
1, 3, ns, ns, 5, 6, 7, ns, ns,
|
||||||
|
ns, ns, ns, 8, ns, 7, ns, ns, 6,
|
||||||
|
0, ns, 1, ns, ns, ns, ns, ns, ns,
|
||||||
|
4, 8, 7, 5, 1, ns, 6, ns, ns,
|
||||||
|
6, ns, 3, 2, ns, ns, ns, 8, 0,
|
||||||
|
ns, ns, 6, ns, ns, 8, ns, 7, 5,
|
||||||
|
8, 0, ns, 7, ns, 5, 2, ns, 3,
|
||||||
|
5, ns, ns, ns, 3, 1, 0, ns, ns);
|
||||||
|
sudokuToTest2.setImmutableCellsSymbol(immutableCells2);
|
||||||
|
|
||||||
|
boolean isSolved = Solver.solve(dokuToTest2);
|
||||||
|
|
||||||
|
assert(!isSolved);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user