diff --git a/README.md b/README.md new file mode 100644 index 0000000..0aeec94 --- /dev/null +++ b/README.md @@ -0,0 +1,21 @@ +# Sudoku 🧩 + +## Features 🌟 + +- Graphical User Interface (GUI) +- Sudoku saves +- Multiplayer + +## Develop ☝🤓 + +### Run 🏃 + +```sh +./gradlew run +``` + +### Run tests 🗣️🔥 + +```sh +./gradlew test +``` \ No newline at end of file diff --git a/app/src/main/java/gui/RenderableMultidoku.java b/app/src/main/java/gui/RenderableMultidoku.java index 33372f0..0271a78 100644 --- a/app/src/main/java/gui/RenderableMultidoku.java +++ b/app/src/main/java/gui/RenderableMultidoku.java @@ -27,6 +27,10 @@ public class RenderableMultidoku { this.doku = doku; } + public boolean isResolved() { + return this.doku.isValid(); + } + public int getWidth() { return width; } diff --git a/app/src/main/java/gui/SudokuRenderer.java b/app/src/main/java/gui/SudokuRenderer.java index da2916b..ca67ce9 100644 --- a/app/src/main/java/gui/SudokuRenderer.java +++ b/app/src/main/java/gui/SudokuRenderer.java @@ -1,18 +1,23 @@ package gui; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; +import common.Signal; import gui.ColorGenerator.Color; import imgui.ImGui; import imgui.ImVec2; import imgui.ImVec4; import imgui.flag.ImGuiCol; import imgui.flag.ImGuiStyleVar; +import sudoku.constraint.Constraint; import sudoku.structure.Block; import sudoku.structure.Cell; import sudoku.structure.MultiDoku; +import sudoku.structure.Sudoku; public class SudokuRenderer { @@ -22,11 +27,28 @@ public class SudokuRenderer { private static final ImVec4 BLACK = new ImVec4(0, 0, 0, 1); private static final ImVec4 TRANSPARENT = new ImVec4(); + private static final ImVec4 WHITE = new ImVec4(1.0f, 1.0f, 1.0f, 1.0f); private static final ImVec2 cellSize = new ImVec2(50, 50); + private final Set diagonals = new HashSet<>(); + + public final Signal onResolve = new Signal(); + public SudokuRenderer(MultiDoku doku) { this.doku = RenderableMultidoku.fromMultidoku(doku); this.colorPalette = initColors(); + initDiagonals(); + } + + private void initDiagonals() { + for (Sudoku sudoku : this.doku.getDoku().getSubGrids()) { + if (sudoku.hasConstraint(Constraint.Diagonal)) { + for (int i = 0; i < sudoku.getSize(); i++) { + this.diagonals.add(sudoku.getCell(i, i)); + this.diagonals.add(sudoku.getCell(sudoku.getSize() - i - 1, i)); + } + } + } } private Map initColors() { @@ -55,6 +77,8 @@ public class SudokuRenderer { } else { if (ImGui.button(Integer.toString(i + 1), cellSize)) { this.doku.setCellValue(currentCell, i); + if (this.doku.isResolved()) + this.onResolve.emit(); ImGui.closeCurrentPopup(); } } @@ -66,7 +90,11 @@ public class SudokuRenderer { public void render() { final float sudokuViewWidth = cellSize.x * doku.getWidth(); final float displayWidth = ImGui.getIO().getDisplaySizeX(); - ImGui.setCursorPosX(displayWidth / 2.0f - sudokuViewWidth / 2.0f); + float offsetX = displayWidth / 2.0f - sudokuViewWidth / 2.0f; + // if the grid is too big, don't offset it + if (offsetX > 0) { + ImGui.setCursorPosX(offsetX); + } ImGui.beginChild(1, new ImVec2(cellSize.x * doku.getWidth(), cellSize.y * doku.getHeight())); ImGui.pushStyleVar(ImGuiStyleVar.FrameBorderSize, 2.0f); @@ -82,15 +110,15 @@ public class SudokuRenderer { ImGui.pushStyleColor(ImGuiCol.Button, TRANSPARENT); ImGui.button("##" + index, cellSize); } else { - ImGui.pushStyleColor(ImGuiCol.Border, BLACK); + if (diagonals.contains(cell)) { + ImGui.pushStyleColor(ImGuiCol.Border, WHITE); + } else { + ImGui.pushStyleColor(ImGuiCol.Border, BLACK); + } int symbol = cell.getSymbolIndex(); Color blockColor = colorPalette.get(cell.getBlock()); if (!cell.isMutable()) { - // ImGui.pushFont(Fonts.ARIAL_BOLD); blockColor = new Color(blockColor.r - 0.20f, blockColor.g - 0.20f, blockColor.b - 0.20f); - // ImGui.pushStyleColor(ImGuiCol.Text, new ImVec4(0.1f, 0.1f, 0.1f, 1.0f)); - } else { - // ImGui.pushFont(Fonts.CHERI); } ImGui.pushStyleColor(ImGuiCol.Button, new ImVec4(blockColor.r, blockColor.g, blockColor.b, 1.0f)); String cellText = ""; @@ -100,10 +128,6 @@ public class SudokuRenderer { ImGui.openPopup("editPopup"); currentCell = cell; } - if (!cell.isMutable()) { - // ImGui.popStyleColor(); - } - // ImGui.popFont(); } ImGui.popStyleColor(2); } diff --git a/app/src/main/java/gui/SudokuSelector.java b/app/src/main/java/gui/SudokuSelector.java new file mode 100644 index 0000000..343a47f --- /dev/null +++ b/app/src/main/java/gui/SudokuSelector.java @@ -0,0 +1,147 @@ +package gui; + +import java.util.ArrayList; +import java.util.List; + +import common.Signal; +import imgui.ImGui; +import imgui.extension.imguifiledialog.ImGuiFileDialog; +import imgui.extension.imguifiledialog.flag.ImGuiFileDialogFlags; +import imgui.type.ImBoolean; +import imgui.type.ImInt; +import sudoku.constraint.Constraint; +import sudoku.structure.Difficulty; +import sudoku.structure.MultiDoku; +import sudoku.structure.SudokuFactory; + +public class SudokuSelector { + + public final Signal onSelect = new Signal(); + private MultiDoku doku; + + private final boolean canGenEmptyGrid; + + private final ImInt sudokuType = new ImInt(0); + + private final ImInt difficulty = new ImInt(Difficulty.Medium.ordinal()); + private final List contraints = new ArrayList<>(); + + private static final String[] sudokuTypes = { "Carré", "Rectangle", "Multidoku" }; + private static final int SQUARE = 0, RECTANGLE = 1, MULTIDOKU = 2; + + private final ImInt sudokuSize = new ImInt(3); + + private final ImInt sudokuWidth = new ImInt(3); + private final ImInt sudokuHeight = new ImInt(3); + + public SudokuSelector(boolean canGenEmptyGrid) { + this.canGenEmptyGrid = canGenEmptyGrid; + initConstraints(); + } + + private List getConstraints() { + List constraints = new ArrayList<>(); + for (int i = 0; i < this.contraints.size(); i++) { + if (this.contraints.get(i).get()) + constraints.add(Constraint.values()[i]); + } + return constraints; + } + + private void initConstraints() { + for (Constraint cons : Constraint.values()) { + contraints.add(new ImBoolean(SudokuFactory.DEFAULT_CONSTRAINTS.contains(cons))); + } + } + + private void selectSudoku(MultiDoku doku, boolean empty) { + this.doku = doku; + if (!empty) { + try { + SudokuFactory.fillDoku(doku, Difficulty.values()[difficulty.get()]); + } catch (Exception e) { + e.printStackTrace(); + } + } + this.onSelect.emit(); + } + + public void renderFileDialog() { + if (ImGuiFileDialog.display("browse-sudoku", ImGuiFileDialogFlags.None)) { + if (ImGuiFileDialog.isOk()) { + var selection = ImGuiFileDialog.getSelection(); + for (var entry : selection.entrySet()) { + try { + String filePath = entry.getValue(); + this.doku = SudokuFactory.fromfile(filePath); + if (this.doku != null) + this.onSelect.emit(); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + ImGuiFileDialog.close(); + } + } + + public void render() { + ImGui.combo("Type de Sudoku", sudokuType, sudokuTypes); + ImGui.combo("Difficulté", difficulty, Difficulty.getDifficultyNames()); + if (ImGui.treeNode("Constraintes")) { + for (Constraint cons : Constraint.values()) { + ImGui.checkbox(cons.getDisplayName(), contraints.get(cons.ordinal())); + } + ImGui.treePop(); + } + switch (sudokuType.get()) { + case SQUARE: + ImGui.inputInt("Taille", sudokuSize); + if (ImGui.button("Résoudre un sudoku")) { + selectSudoku(SudokuFactory.createBasicEmptySquareDoku(sudokuSize.get(), getConstraints()), false); + } + if (canGenEmptyGrid && ImGui.button("Générer une grille vide")) { + selectSudoku(SudokuFactory.createBasicEmptySquareDoku(sudokuSize.get(), getConstraints()), true); + } + break; + + case RECTANGLE: + ImGui.inputInt("Largeur", sudokuHeight); + ImGui.inputInt("Longueur", sudokuWidth); + if (ImGui.button("Résoudre un sudoku")) { + selectSudoku( + SudokuFactory.createBasicEmptyRectangleDoku(sudokuWidth.get(), sudokuHeight.get(), + getConstraints()), + false); + } + if (canGenEmptyGrid && ImGui.button("Générer une grille vide")) { + selectSudoku( + SudokuFactory.createBasicEmptyRectangleDoku(sudokuWidth.get(), sudokuHeight.get(), + getConstraints()), + true); + } + break; + + case MULTIDOKU: + ImGui.inputInt("Taille", sudokuSize); + if (ImGui.button("Résoudre un sudoku")) { + selectSudoku(SudokuFactory.createBasicXShapedMultidoku(sudokuSize.get(), getConstraints()), false); + } + if (canGenEmptyGrid && ImGui.button("Générer une grille vide")) { + selectSudoku(SudokuFactory.createBasicXShapedMultidoku(sudokuSize.get(), getConstraints()), true); + } + + default: + break; + } + if (ImGui.button("À partir d'un fichier")) { + ImGuiFileDialog.openDialog("browse-sudoku", "Choisissez un fichier", ".json", "."); + } + renderFileDialog(); + } + + public MultiDoku getDoku() { + return doku; + } + +} diff --git a/app/src/main/java/gui/menu/MultiPlayerView.java b/app/src/main/java/gui/menu/MultiPlayerView.java index 09afd83..e58f24d 100644 --- a/app/src/main/java/gui/menu/MultiPlayerView.java +++ b/app/src/main/java/gui/menu/MultiPlayerView.java @@ -1,9 +1,12 @@ package gui.menu; +import java.util.Arrays; + import game.Player; import imgui.ImGui; import network.client.Client; import network.server.Server; +import sudoku.constraint.Constraint; import sudoku.structure.MultiDoku; import sudoku.structure.SudokuFactory; @@ -17,7 +20,8 @@ public class MultiPlayerView extends BaseView { this.client = client; this.server = server; this.client.onDisconnect.connect(this::onDisconnect); - this.client.onGameStarted.connect(() -> this.stateMachine.pushState(new MultiPlayerDokuView(stateMachine, client, server))); + this.client.onGameStarted + .connect(() -> this.stateMachine.pushState(new MultiPlayerDokuView(stateMachine, client, server))); } @Override @@ -36,7 +40,7 @@ public class MultiPlayerView extends BaseView { } else { if (ImGui.button("Démarrer")) { // temp - MultiDoku doku = SudokuFactory.createBasicXShapedMultidoku(3); + MultiDoku doku = SudokuFactory.createBasicXShapedMultidoku(3, Arrays.asList(Constraint.Diagonal)); this.server.startGame(doku); } } diff --git a/app/src/main/java/gui/menu/SoloMenu.java b/app/src/main/java/gui/menu/SoloMenu.java index 0dc3d36..c3b714e 100644 --- a/app/src/main/java/gui/menu/SoloMenu.java +++ b/app/src/main/java/gui/menu/SoloMenu.java @@ -1,88 +1,26 @@ package gui.menu; +import gui.SudokuSelector; import imgui.ImGui; -import imgui.type.ImInt; -import sudoku.structure.Difficulty; -import sudoku.structure.MultiDoku; -import sudoku.structure.SudokuFactory; public class SoloMenu extends BaseView { - private final ImInt sudokuType = new ImInt(0); - - private final ImInt difficulty = new ImInt(Difficulty.Medium.ordinal()); - private final String[] difficulties; - - private static final String[] sudokuTypes = { "Carré", "Rectangle", "Multidoku" }; - private static final int SQUARE = 0, RECTANGLE = 1, MULTIDOKU = 2; - - private final ImInt sudokuSize = new ImInt(3); - - private final ImInt sudokuWidth = new ImInt(3); - private final ImInt sudokuHeight = new ImInt(3); + private final SudokuSelector sudokuSelector; public SoloMenu(StateMachine stateMachine) { super(stateMachine); - Difficulty[] diffs = Difficulty.values(); - difficulties = new String[diffs.length]; - for (int i = 0; i < diffs.length; i++) { - difficulties[i] = diffs[i].getDisplayName(); - } + this.sudokuSelector = new SudokuSelector(true); + this.sudokuSelector.onSelect.connect(this::pushSudokuState); } - private void pushSudokuState(MultiDoku doku, boolean empty) { - if (!empty) { - try { - SudokuFactory.fillDoku(doku, Difficulty.values()[difficulty.get()]); - } catch (Exception e) { - e.printStackTrace(); - } - } - this.stateMachine.pushState(new SudokuView(stateMachine, doku)); + private void pushSudokuState() { + this.stateMachine.pushState(new SudokuView(stateMachine, this.sudokuSelector.getDoku())); } @Override public void render() { ImGui.text("Solo"); - ImGui.combo("Type de Sudoku", sudokuType, sudokuTypes); - ImGui.combo("Difficulté", difficulty, difficulties); - switch (sudokuType.get()) { - case SQUARE: - ImGui.inputInt("Taille", sudokuSize); - if (ImGui.button("Résoudre un sudoku")) { - pushSudokuState(SudokuFactory.createBasicEmptySquareSudoku(sudokuSize.get()), false); - } - if (ImGui.button("Générer une grille vide")) { - pushSudokuState(SudokuFactory.createBasicEmptySquareSudoku(sudokuSize.get()), true); - } - break; - - case RECTANGLE: - ImGui.inputInt("Largeur", sudokuHeight); - ImGui.inputInt("Longueur", sudokuWidth); - if (ImGui.button("Résoudre un sudoku")) { - pushSudokuState( - SudokuFactory.createBasicEmptyRectangleSudoku(sudokuWidth.get(), sudokuHeight.get()), - false); - } - if (ImGui.button("Générer une grille vide")) { - pushSudokuState( - SudokuFactory.createBasicEmptyRectangleSudoku(sudokuWidth.get(), sudokuHeight.get()), true); - } - break; - - case MULTIDOKU: - ImGui.inputInt("Taille", sudokuSize); - if (ImGui.button("Résoudre un sudoku")) { - pushSudokuState(SudokuFactory.createBasicXShapedMultidoku(sudokuSize.get()), false); - } - if (ImGui.button("Générer une grille vide")) { - pushSudokuState(SudokuFactory.createBasicXShapedMultidoku(sudokuSize.get()), true); - } - - default: - break; - } + sudokuSelector.render(); renderReturnButton(); } diff --git a/app/src/main/java/gui/menu/SudokuView.java b/app/src/main/java/gui/menu/SudokuView.java index f0b18d1..e44a598 100644 --- a/app/src/main/java/gui/menu/SudokuView.java +++ b/app/src/main/java/gui/menu/SudokuView.java @@ -6,6 +6,7 @@ import java.util.concurrent.CancellationException; import gui.SudokuRenderer; import imgui.ImGui; import imgui.ImGuiStyle; +import sudoku.io.SudokuSerializer; import sudoku.solver.Solver; import sudoku.structure.MultiDoku; @@ -14,11 +15,19 @@ public class SudokuView extends BaseView { private final SudokuRenderer sudokuRenderer; private Thread resolveThread; private final MultiDoku doku; + private String lastSavePath = null; + + private boolean resolved = false; public SudokuView(StateMachine stateMachine, MultiDoku doku) { super(stateMachine); this.doku = doku; this.sudokuRenderer = new SudokuRenderer(doku); + this.sudokuRenderer.onResolve.connect(this::onResolve); + } + + private void onResolve() { + this.resolved = true; } private void stopResolve() { @@ -63,7 +72,7 @@ public class SudokuView extends BaseView { boolean beginSolve = false; - if (centeredButton("Résoudre")) { + if (!resolved && centeredButton("Résoudre")) { beginSolve = true; } if (resolveThread != null) @@ -81,12 +90,29 @@ public class SudokuView extends BaseView { stopResolve(); }); } + + if (resolved) { + ImGui.text("Bravo !"); + } + } + + private void renderSaveButton() { + if (ImGui.button("Sauvegarder l'état de la grille")) { + lastSavePath = SudokuSerializer.saveMultiDoku(doku); + ImGui.openPopup("saveDone"); + } + if (ImGui.beginPopup("saveDone")) { + ImGui.text("Sudoku sauvegardé dans "); + ImGui.text(lastSavePath); + ImGui.endPopup(); + } } @Override public void render() { sudokuRenderer.render(); renderSolveButton(); + renderSaveButton(); renderCancelButton(); renderReturnButton(); } diff --git a/app/src/main/java/sudoku/Main.java b/app/src/main/java/sudoku/Main.java index ca6a820..c91aa66 100644 --- a/app/src/main/java/sudoku/Main.java +++ b/app/src/main/java/sudoku/Main.java @@ -18,30 +18,29 @@ public class Main { int blockWidth = 2; int blockHeight = 2; - var multidoku = SudokuFactory.createBasicEmptyRectangleSudoku(blockWidth, blockHeight); + var multidoku = SudokuFactory.createBasicEmptyRectangleDoku(blockWidth, blockHeight, + SudokuFactory.DEFAULT_CONSTRAINTS); var sudoku = multidoku.getSubGrid(0); - if(!sudoku.setCellsSymbol(Arrays.asList(0,1,2,3, 2,3,1,1, 1,0,3,2, 3,2,1,1))){ + if (!sudoku.setCellsSymbol(Arrays.asList(0, 1, 2, 3, 2, 3, 1, 1, 1, 0, 3, 2, 3, 2, 1, 1))) { System.out.println("At least one of those values does not respect the constraints."); } + // sudoku.setCellSymbol(8,3,0); - //sudoku.setCellSymbol(8,3,0); - - SudokuPrinter.printRectangleSudoku(multidoku.getSubGrid(0), blockWidth , blockHeight); + SudokuPrinter.printRectangleSudoku(multidoku.getSubGrid(0), blockWidth, blockHeight); /* - Solver solver = new Solver(); - ArrayList constraints = new ArrayList<>(); - constraints.add(new LineConstraint()); - constraints.add(new ColumnConstraint()); - constraints.add(new BlockConstraint()); - try { - solver.solve(multidoku, constraints); - } catch (Exception e) { - System.out.println(e); - } - */ - + * Solver solver = new Solver(); + * ArrayList constraints = new ArrayList<>(); + * constraints.add(new LineConstraint()); + * constraints.add(new ColumnConstraint()); + * constraints.add(new BlockConstraint()); + * try { + * solver.solve(multidoku, constraints); + * } catch (Exception e) { + * System.out.println(e); + * } + */ } } diff --git a/app/src/main/java/sudoku/constraint/Constraint.java b/app/src/main/java/sudoku/constraint/Constraint.java new file mode 100644 index 0000000..14b7c3d --- /dev/null +++ b/app/src/main/java/sudoku/constraint/Constraint.java @@ -0,0 +1,52 @@ +package sudoku.constraint; + +import java.util.List; + +import sudoku.structure.Sudoku; + +public enum Constraint { + + Block("Bloc", new BlockConstraint()), + Column("Colonne", new ColumnConstraint()), + Line("Ligne", new LineConstraint()), + Diagonal("Diagonale", new DiagonalConstraint()); + + String displayName; + IConstraint constraint; + + private Constraint(String displayName, IConstraint contraint) { + this.constraint = contraint; + this.displayName = displayName; + } + + public boolean canBePlaced(Sudoku s, int x, int y, int newValue) { + return getConstraint().canBePlaced(s, x, y, newValue); + } + + public List getPossibleSymbols(final Sudoku s, int x, int y) { + return getConstraint().getPossibleSymbols(s, x, y); + } + + public String getDisplayName() { + return displayName; + } + + public IConstraint getConstraint() { + return constraint; + } + + private static final String[] constraintNames; + + static { + Constraint[] cons = Constraint.values(); + constraintNames = new String[cons.length]; + for (int i = 0; i < cons.length; i++) { + constraintNames[i] = cons[i].getDisplayName(); + } + } + + public static String[] getConstraintNames() { + return constraintNames; + } + +} diff --git a/app/src/main/java/sudoku/constraint/DiagonalConstraint.java b/app/src/main/java/sudoku/constraint/DiagonalConstraint.java new file mode 100644 index 0000000..95d6842 --- /dev/null +++ b/app/src/main/java/sudoku/constraint/DiagonalConstraint.java @@ -0,0 +1,24 @@ +package sudoku.constraint; + +import sudoku.structure.Sudoku; + +public class DiagonalConstraint implements IConstraint { + + @Override + public boolean canBePlaced(Sudoku s, int x, int y, int newSymbolIndex) { + if (x == y) { + for (int i = 0; i < s.getSize(); i++) { + if (s.getCell(i, i).getSymbolIndex() == newSymbolIndex) + return false; + } + } else if (s.getSize() - x == y) { + for (int i = 0; i < s.getSize(); i++) { + if (s.getCell(s.getSize() - i - 1, i).getSymbolIndex() == newSymbolIndex) + return false; + } + } + // not in diagonal + return true; + } + +} diff --git a/app/src/main/java/sudoku/io/SudokuSerializer.java b/app/src/main/java/sudoku/io/SudokuSerializer.java index 6c5978f..a71e4f3 100644 --- a/app/src/main/java/sudoku/io/SudokuSerializer.java +++ b/app/src/main/java/sudoku/io/SudokuSerializer.java @@ -10,6 +10,7 @@ import java.util.List; import org.json.JSONArray; import org.json.JSONObject; +import sudoku.constraint.Constraint; import sudoku.structure.Block; import sudoku.structure.Cell; import sudoku.structure.MultiDoku; @@ -34,7 +35,6 @@ public class SudokuSerializer { for (Cell cell : sudoku.getCells()) { if (!cellIds.contains(cell)) { cellIds.add(cell); - } Block block = cell.getBlock(); @@ -74,6 +74,7 @@ public class SudokuSerializer { JSONObject jsonSudoku = new JSONObject(); JSONArray cellsJsonArray = new JSONArray(); JSONArray blocksJsonArray = new JSONArray(); + JSONArray constraintsJsonArray = new JSONArray(); Sudoku sudoku = multidoku.getSubGrid(i); @@ -91,6 +92,13 @@ public class SudokuSerializer { blocksJsonArray.put(blockID); } + // serialize constraints + + for (Constraint cons : sudoku.getConstraints()) { + constraintsJsonArray.put(cons.ordinal()); + } + + jsonSudoku.put("constraints", constraintsJsonArray); jsonSudoku.put("cells", cellsJsonArray); jsonSudoku.put("blocks", blocksJsonArray); jsonSudoku.put("blockWidth", sudoku.getBlockWidth()); @@ -107,9 +115,9 @@ public class SudokuSerializer { /** * Save a serialized MultiDoku in a JSON file. * @param doku MultiDoku, MultiDoku to save. - * @return int, number of the save. + * @return String, the path of the save. */ - public static int saveMultiDoku(final MultiDoku doku) { + public static String saveMultiDoku(final MultiDoku doku) { JSONObject jsonRoot = serializeSudoku(doku); @@ -124,9 +132,9 @@ public class SudokuSerializer { try (FileWriter file = new FileWriter(f)) { file.write(jsonRoot.toString(3)); } catch (IOException e) { - e.fillInStackTrace(); + e.printStackTrace(); } - return i; + return f.getAbsolutePath(); } /** @@ -212,9 +220,11 @@ public class SudokuSerializer { JSONObject sudokuJsonObject = multidokuJsonObject.getJSONObject(i); JSONArray sudokuCellsJsonArray = sudokuJsonObject.getJSONArray("cells"); JSONArray sudokuBlocksJsonArray = sudokuJsonObject.getJSONArray("blocks"); + JSONArray sudokuConstraintsJsonArray = sudokuJsonObject.getJSONArray("constraints"); List sudokuCells = new ArrayList<>(); List sudokuBlocks = new ArrayList<>(); + List sudokuConstraints = new ArrayList<>(); for (int j = 0; j < sudokuCellsJsonArray.length(); j++) { int cellID = sudokuCellsJsonArray.getInt(j); @@ -226,7 +236,12 @@ public class SudokuSerializer { sudokuBlocks.add(blocks.get(blockID)); } - Sudoku s = new Sudoku(sudokuCells, sudokuBlocks, SudokuFactory.DEFAULT_CONSTRAINTS); + for (int j = 0; j < sudokuConstraintsJsonArray.length(); j++) { + int constraintID = sudokuConstraintsJsonArray.getInt(j); + sudokuConstraints.add(Constraint.values()[constraintID]); + } + + Sudoku s = new Sudoku(sudokuCells, sudokuBlocks, sudokuConstraints); s.setBlockWidth(sudokuJsonObject.getInt("blockWidth")); sudokus.add(s); } diff --git a/app/src/main/java/sudoku/structure/Block.java b/app/src/main/java/sudoku/structure/Block.java index 356b20b..98acdbd 100644 --- a/app/src/main/java/sudoku/structure/Block.java +++ b/app/src/main/java/sudoku/structure/Block.java @@ -5,7 +5,8 @@ import java.util.List; /** * Class qui représente les block de chaque sudoku, - * Un block étant un ensemble de cellule avec une contrainte de block qui lui ait associé + * Un block étant un ensemble de cellule avec une contrainte de block qui lui + * ait associé */ public class Block { @@ -18,14 +19,15 @@ public class Block { * List de sudoku qui contiennent le block * Pour un acces plus rapide aux sudokus */ - private List sudokus; + private final List sudokus; public Block(List cells) { this.cells = cells; + this.sudokus = new ArrayList<>(); } public Block() { - this.cells = new ArrayList<>(); + this(new ArrayList<>()); } public List getCells() { @@ -34,6 +36,7 @@ public class Block { /** * Ajoute une Cell au Block + * * @param newCell Cell, à ajouter */ void addCell(Cell newCell) { @@ -42,6 +45,7 @@ public class Block { /** * Cherche si le Block contient déjà un symbole donné. + * * @param symbolIndex int, un index de symbole * @return boolean, true s'il contient le symbole et false sinon */ @@ -65,8 +69,4 @@ public class Block { public List getSudokus() { return sudokus; } - - void setSudokus(List sudokus) { - this.sudokus = sudokus; - } } diff --git a/app/src/main/java/sudoku/structure/Difficulty.java b/app/src/main/java/sudoku/structure/Difficulty.java index 0952255..9f0b225 100644 --- a/app/src/main/java/sudoku/structure/Difficulty.java +++ b/app/src/main/java/sudoku/structure/Difficulty.java @@ -8,7 +8,7 @@ public enum Difficulty { double factor; String displayName; - Difficulty(String displayName, double factor) { + private Difficulty(String displayName, double factor) { this.factor = factor; this.displayName = displayName; } @@ -21,4 +21,18 @@ public enum Difficulty { return factor; } + private static final String[] difficultyNames; + + static { + Difficulty[] diffs = Difficulty.values(); + difficultyNames = new String[diffs.length]; + for (int i = 0; i < diffs.length; i++) { + difficultyNames[i] = diffs[i].getDisplayName(); + } + } + + public static String[] getDifficultyNames() { + return difficultyNames; + } + } diff --git a/app/src/main/java/sudoku/structure/Sudoku.java b/app/src/main/java/sudoku/structure/Sudoku.java index 2cd2e39..3b82bd1 100644 --- a/app/src/main/java/sudoku/structure/Sudoku.java +++ b/app/src/main/java/sudoku/structure/Sudoku.java @@ -1,5 +1,7 @@ package sudoku.structure; +import sudoku.constraint.BlockConstraint; +import sudoku.constraint.Constraint; import sudoku.constraint.IConstraint; import java.util.ArrayList; @@ -22,13 +24,13 @@ public class Sudoku { /** * Liste des contraintes (TODO) du Sudoku. */ - private final List constraints; + 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) { + public Sudoku(List cells, List blocks, List constraints) { this.cells = cells; this.blocks = blocks; this.constraints = constraints; @@ -41,7 +43,7 @@ public class Sudoku { * @return Coordinate, correspondante à l'index donné. */ public Coordinate toCoords(int index) { - return new Coordinate( index % getSize(), index / getSize() ); + return new Coordinate(index % getSize(), index / getSize()); } /** @@ -73,13 +75,13 @@ public class Sudoku { /** * 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 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) { + for (Constraint constraint : this.constraints) { if (!constraint.canBePlaced(this, x, y, value)) { return false; } @@ -89,8 +91,8 @@ public class Sudoku { /** * Tente de placer le symbole value dans la Cell de coordonnées x, y. - * @param x int, abscisse de la Cell voulue. - * @param y int, coordonnée de la Cell voulue; + * @param x int, abscisse de la Cell voulue. + * @param y int, coordonnée de la Cell voulue; * @param value int, index du symbole que l'on veut placer. * @return boolean, true si le symbole a été placé, false sinon */ @@ -132,14 +134,14 @@ public class Sudoku { /** * 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 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) { + for (Constraint constraint : this.constraints) { if (!constraint.canBePlaced(this, x, y, value)) { return null; } @@ -205,7 +207,7 @@ public class Sudoku { return this.cells.get(i); } - public List getConstraints() { + public List getConstraints() { return constraints; } @@ -264,8 +266,8 @@ public class Sudoku { * Met à jour les symboles possibles des Cells du Sudoku. * */ - public void updateSymbolsPossibilities(){ - for (IConstraint constraint : constraints) { + public void updateSymbolsPossibilities() { + for (Constraint constraint : constraints) { List cells = this.getCells(); for (Cell cell : cells) { Coordinate coord = null; @@ -275,7 +277,11 @@ public class Sudoku { System.out.println("Cas jamais atteint."); } List newPossibleSymbols = cell.getPossibleSymbols(); - newPossibleSymbols.retainAll(constraint.getPossibleSymbols(this, coord.getX(), coord.getY())); + newPossibleSymbols.retainAll(constraint.getPossibleSymbols( + this, + coord.getX(), + coord.getY() + )); cell.setPossibleSymbols(newPossibleSymbols); } @@ -323,7 +329,7 @@ public class Sudoku { return result; } for (int i = 0; i < this.constraints.size(); i++) { - IConstraint constraint = this.constraints.get(i); + Constraint constraint = this.constraints.get(i); if (i == 0) { result.addAll(constraint.getPossibleSymbols(this, cellCoordinates.getX(), cellCoordinates.getY())); } else { @@ -446,4 +452,8 @@ public class Sudoku { this.blockWidth = blockWidth; } + public boolean hasConstraint(Constraint constraint) { + return this.constraints.contains(constraint); + } + } diff --git a/app/src/main/java/sudoku/structure/SudokuFactory.java b/app/src/main/java/sudoku/structure/SudokuFactory.java index 3f84986..feff0dd 100644 --- a/app/src/main/java/sudoku/structure/SudokuFactory.java +++ b/app/src/main/java/sudoku/structure/SudokuFactory.java @@ -1,5 +1,8 @@ package sudoku.structure; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -8,9 +11,10 @@ import java.util.Random; import sudoku.constraint.BlockConstraint; import sudoku.constraint.ColumnConstraint; +import sudoku.constraint.Constraint; +import sudoku.constraint.DiagonalConstraint; import sudoku.constraint.IConstraint; import sudoku.constraint.LineConstraint; -import sudoku.io.SudokuPrinter; import sudoku.solver.Solver; public class SudokuFactory { @@ -19,18 +23,13 @@ public class SudokuFactory { * Générateur de nombre aléatoire. */ private static final Random random = new Random(); - /** - * Difficulté avec le ration des cases qui seront vides. - */ - private static final double VERY_EASY = 0.1; - private static final double EASY = 0.25; - private static final double MEDIUM = 0.5; - private static final double HARD = 0.75; + /** * Liste des contraintes par défaut d'un Multi- ou Sudoku. * Comprend les contraintes de blocs, de lignes, et de colonnes. */ - public static List DEFAULT_CONSTRAINTS = Arrays.asList(new BlockConstraint(), new LineConstraint(), new ColumnConstraint()); + public static List DEFAULT_CONSTRAINTS = Arrays.asList(Constraint.Block, Constraint.Column, + Constraint.Line); /** * Créée des Cells et les met dans une liste de taille size. @@ -81,9 +80,9 @@ public class SudokuFactory { * @param heightBlock int, hauteur des Blocks. * @return MultiDoku, MultiDoku vide. */ - public static MultiDoku createBasicEmptyRectangleSudoku(int widthBlock, int heightBlock) { - Sudoku s = createRectangleSudoku(widthBlock, heightBlock); - return new MultiDoku(Arrays.asList(s)); + public static MultiDoku createBasicEmptyRectangleDoku(int widthBlock, int heightBlock, + List constraints) { + return new MultiDoku(Arrays.asList(createRectangleSudoku(widthBlock, heightBlock, constraints))); } /** @@ -91,13 +90,13 @@ public class SudokuFactory { * @param size int, taille des Blocks. * @return MultiDoku, MultiDoku vide. */ - public static MultiDoku createBasicEmptySquareSudoku(int size) { - return createBasicEmptyRectangleSudoku(size, size); + public static MultiDoku createBasicEmptySquareDoku(int size, List constraints) { + return new MultiDoku(Arrays.asList(createSquareSudoku(size, constraints))); } /** * Place des Cells immutables de valeurs fournies, aux Coordinate fournies dans le MultiDoku doku fourni. - * @param doku MultiDoku, MultiDoku à remplir. + * @param doku MultiDoku, MultiDoku à remplir. * @param immutableCells Map, association de Coordinate coordonnées et Integer valeurs, correspondant aux cases à remplir. */ public static void setImmutableCells(MultiDoku doku, Map immutableCells) { @@ -120,7 +119,7 @@ public class SudokuFactory { * @return boolean, valant true si un MultiDoku de difficulté donnée peut être créée, false sinon. * @throws Exception si la difficulté n'est pas compatible avec la taille du MultiDoku. */ - public static boolean newDokuFromFilledOne (MultiDoku doku, int nbCellsToEmpty) throws Exception { + public static boolean newDokuFromFilledOne(MultiDoku doku, int nbCellsToEmpty) throws Exception { System.out.println("nbCellsToEmpty : "+nbCellsToEmpty); if (nbCellsToEmpty >= doku.getCells().size()) { @@ -152,37 +151,40 @@ public class SudokuFactory { } return false; - } + } /** * Créée un Sudoku vide dont les Blocks sont de taille widthBlock par heightBlock. - * @param widthBlock int, largeur des Blocks. + * @param widthBlock int, largeur des Blocks. * @param heightBlock int, hauteur des Blocks. * @return Sudoku, Sudoku vide. */ - private static Sudoku createRectangleSudoku(int widthBlock, int heightBlock) { + private static Sudoku createRectangleSudoku(int widthBlock, int heightBlock, List constraints) { int symbolCount = widthBlock * heightBlock; List cases = initCells(symbolCount); List blocs = initRectangleBlocs(cases, widthBlock, heightBlock); - Sudoku s = new Sudoku(cases, blocs, DEFAULT_CONSTRAINTS); + Sudoku s = new Sudoku(cases, blocs, constraints); + for (Block block : s.getBlocks()) { + block.getSudokus().add(s); + } s.setBlockWidth(widthBlock); return s; } - /** + /** * Créée un Sudoku vide dont les Blocks sont carrés de longueur size. * @param size int, taille des Blocks. * @return Sudoku, Sudoku vide. */ - private static Sudoku createSquareSudoku(int size) { - return createRectangleSudoku(size, size); + private static Sudoku createSquareSudoku(int size, List constraints) { + return createRectangleSudoku(size, size, constraints); } /** * Connecte deux Sudokus selon la décalage offset fourni. * @param sudoku1 Sudoku, premier sudoku à connecter. * @param sudoku2 Sudoku, second sudoku à connecter. - * @param offset Coordinate, décalage entre les deux Sudokus. + * @param offset Coordinate, décalage entre les deux Sudokus. */ private static void linkSquareSudokus(Sudoku sudoku1, Sudoku sudoku2, Coordinate offset) { int blockWidth = sudoku1.getBlockWidth(); @@ -199,6 +201,7 @@ public class SudokuFactory { // on remplace le bloc sudoku2.getBlocks().set(block2Y * blockWidth + block2X, block1); + block1.getSudokus().add(sudoku2); // on remplace les cellules for (int i = 0; i < block1.getCells().size(); i++) { @@ -218,7 +221,7 @@ public class SudokuFactory { * @param size int, largeur des Blocks unitraires des Sudokus à crééer. * @return MultiDoku, MultiDoku de forme X. */ - public static MultiDoku createBasicXShapedMultidoku(int size) { + public static MultiDoku createBasicXShapedMultidoku(int size, List constraints) { assert (size > 1); /* @@ -227,11 +230,11 @@ public class SudokuFactory { * 4 5 */ - Sudoku sudoku1 = createSquareSudoku(size); - Sudoku sudoku2 = createSquareSudoku(size); - Sudoku sudoku3 = createSquareSudoku(size); - Sudoku sudoku4 = createSquareSudoku(size); - Sudoku sudoku5 = createSquareSudoku(size); + Sudoku sudoku1 = createSquareSudoku(size, constraints); + Sudoku sudoku2 = createSquareSudoku(size, constraints); + Sudoku sudoku3 = createSquareSudoku(size, constraints); + Sudoku sudoku4 = createSquareSudoku(size, constraints); + Sudoku sudoku5 = createSquareSudoku(size, constraints); linkSquareSudokus(sudoku1, sudoku2, new Coordinate(1 - size, 1 - size)); linkSquareSudokus(sudoku1, sudoku3, new Coordinate(size - 1, 1 - size)); @@ -243,15 +246,22 @@ public class SudokuFactory { public static void fillDoku(MultiDoku doku, Difficulty difficulty) throws Exception { Solver.solveRandom(doku, random); - //SudokuPrinter.printRectangleSudoku(doku.getSubGrid(0), 3, 3); - int nbCellsToEmpty = (int)(difficulty.getFactor()*doku.getNbCells()); - //System.out.println(nbCellsToEmpty); - boolean successful = newDokuFromFilledOne(doku, nbCellsToEmpty); - - - if (!successful) { + int nbCellsToEmpty = (int) (difficulty.getFactor() * doku.getNbCells()); + boolean successfull = newDokuFromFilledOne(doku, nbCellsToEmpty); + if (!successfull) { throw new Exception("Canno't create this doku with this difficulty"); } doku.setFilledCellsImmutable(); } + + public static MultiDoku fromfile(String filePath) { + try { + String content = Files.readString(Paths.get(filePath)); + MultiDoku doku = SudokuSerializer.deserializeSudoku(content); + return doku; + } catch (IOException e) { + e.printStackTrace(); + return null; + } + } } diff --git a/app/src/test/java/sudoku/SudokuSerializerTest.java b/app/src/test/java/sudoku/SudokuSerializerTest.java index cacdadb..d08fe19 100644 --- a/app/src/test/java/sudoku/SudokuSerializerTest.java +++ b/app/src/test/java/sudoku/SudokuSerializerTest.java @@ -1,39 +1,41 @@ package sudoku; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; +import java.io.File; +import java.util.Random; import org.json.JSONObject; import org.junit.jupiter.api.Test; -import sudoku.io.SudokuPrinter; import sudoku.io.SudokuSerializer; import sudoku.structure.MultiDoku; import sudoku.structure.SudokuFactory; -import java.util.Random; - public class SudokuSerializerTest { void testSerializeWithSize(int blockWidth, int blockHeight) { - var sudoku = SudokuFactory.createBasicEmptyRectangleSudoku(blockWidth, blockHeight); + var sudoku = SudokuFactory.createBasicEmptyRectangleDoku(blockWidth, blockHeight, + SudokuFactory.DEFAULT_CONSTRAINTS); JSONObject data = SudokuSerializer.serializeSudoku(sudoku); MultiDoku multiDoku = SudokuSerializer.deserializeSudoku(data); - assert(data.toString().equals(SudokuSerializer.serializeSudoku(multiDoku).toString())); + assert (data.toString().equals(SudokuSerializer.serializeSudoku(multiDoku).toString())); } void testSaveWithSize(int blockWidth, int blockHeight) { - MultiDoku doku = SudokuFactory.createBasicEmptyRectangleSudoku(blockWidth, blockHeight); - int saveNumber = SudokuSerializer.saveMultiDoku(doku); + MultiDoku doku = SudokuFactory.createBasicEmptyRectangleDoku(blockWidth, blockHeight, + SudokuFactory.DEFAULT_CONSTRAINTS); + String savePath = SudokuSerializer.saveMultiDoku(doku); MultiDoku otherDoku = null; try { - otherDoku = SudokuSerializer.getSavedMultiDoku(saveNumber); + otherDoku = SudokuFactory.fromfile(savePath); assert (otherDoku != null); + // clean file after test + File fileToDelete = new File(savePath); + fileToDelete.delete(); } catch (Exception e) { e.printStackTrace(); assert false; } - assert(doku.equals(otherDoku)); + assert (doku.equals(otherDoku)); } @Test @@ -41,18 +43,15 @@ public class SudokuSerializerTest { Random r = new Random(); int testCount = 5; for (int i = 0; i < testCount; i++) { - int blockWidth = r.nextInt(20) + 1; - int blockHeight = r.nextInt(20) + 1; + int blockWidth = r.nextInt(10) + 1; + int blockHeight = r.nextInt(10) + 1; testSerializeWithSize(blockWidth, blockHeight); } for (int i = 0; i < testCount; i++) { - int blockWidth = r.nextInt(20) + 1; - int blockHeight = r.nextInt(20) + 1; + int blockWidth = r.nextInt(10) + 1; + int blockHeight = r.nextInt(10) + 1; testSaveWithSize(blockWidth, blockHeight); } - - - } } diff --git a/app/src/test/java/sudoku/solver/SolverTest.java b/app/src/test/java/sudoku/solver/SolverTest.java index 8267444..ae5d093 100644 --- a/app/src/test/java/sudoku/solver/SolverTest.java +++ b/app/src/test/java/sudoku/solver/SolverTest.java @@ -16,51 +16,46 @@ class SolverTest { void solveTest() { Random rand = new Random(); - MultiDoku dokuToTest = SudokuFactory.createBasicEmptySquareSudoku(3); - MultiDoku dokuResult = SudokuFactory.createBasicEmptySquareSudoku(3); + MultiDoku dokuToTest = SudokuFactory.createBasicEmptySquareDoku(3, SudokuFactory.DEFAULT_CONSTRAINTS); + MultiDoku dokuResult = SudokuFactory.createBasicEmptySquareDoku(3, SudokuFactory.DEFAULT_CONSTRAINTS); Sudoku sudokuToTest = dokuToTest.getSubGrid(0); Sudoku sudokuResult = dokuResult.getSubGrid(0); int ns = Cell.NOSYMBOL; - List 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)); + List 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 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); + List 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.isSolved()); Solver.solveRandom(dokuToTest, rand); - System.out.println("\n****************************\nDoku solved"); SudokuPrinter.printRectangleSudoku(dokuToTest.getSubGrid(0), 3, 3); @@ -69,25 +64,25 @@ class SolverTest { assert(dokuToTest.equals(dokuResult)); - MultiDoku dokuToTest2 = SudokuFactory.createBasicEmptySquareSudoku(3); + MultiDoku dokuToTest2 = SudokuFactory.createBasicEmptySquareDoku(3, SudokuFactory.DEFAULT_CONSTRAINTS); Sudoku sudokuToTest2 = dokuToTest2.getSubGrid(0); - List 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); + List 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.solveRandom(dokuToTest2, rand); - assert(!isSolved); + assert (!isSolved); - MultiDoku dokuToTest3 = SudokuFactory.createBasicEmptySquareSudoku(3); + MultiDoku dokuToTest3 = SudokuFactory.createBasicEmptySquareDoku(3, SudokuFactory.DEFAULT_CONSTRAINTS); Solver.solveRandom(dokuToTest3, rand);