Merge remote-tracking branch 'origin/master'
# Conflicts: # app/src/main/java/sudoku/structure/MultiDoku.java # app/src/main/java/sudoku/structure/Sudoku.java # app/src/main/java/sudoku/structure/SudokuFactory.java # app/src/test/java/sudoku/solver/SolverTest.java
This commit is contained in:
@@ -27,6 +27,10 @@ public class RenderableMultidoku {
|
||||
this.doku = doku;
|
||||
}
|
||||
|
||||
public boolean isResolved() {
|
||||
return this.doku.isValid();
|
||||
}
|
||||
|
||||
public int getWidth() {
|
||||
return width;
|
||||
}
|
||||
|
||||
@@ -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<Cell> 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<Block, Color> 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);
|
||||
}
|
||||
|
||||
147
app/src/main/java/gui/SudokuSelector.java
Normal file
147
app/src/main/java/gui/SudokuSelector.java
Normal file
@@ -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<ImBoolean> 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<Constraint> getConstraints() {
|
||||
List<Constraint> 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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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<IConstraint> 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<IConstraint> 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);
|
||||
* }
|
||||
*/
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
52
app/src/main/java/sudoku/constraint/Constraint.java
Normal file
52
app/src/main/java/sudoku/constraint/Constraint.java
Normal file
@@ -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<Integer> 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;
|
||||
}
|
||||
|
||||
}
|
||||
24
app/src/main/java/sudoku/constraint/DiagonalConstraint.java
Normal file
24
app/src/main/java/sudoku/constraint/DiagonalConstraint.java
Normal file
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<Cell> sudokuCells = new ArrayList<>();
|
||||
List<Block> sudokuBlocks = new ArrayList<>();
|
||||
List<Constraint> 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);
|
||||
}
|
||||
|
||||
@@ -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<Sudoku> sudokus;
|
||||
private final List<Sudoku> sudokus;
|
||||
|
||||
public Block(List<Cell> cells) {
|
||||
this.cells = cells;
|
||||
this.sudokus = new ArrayList<>();
|
||||
}
|
||||
|
||||
public Block() {
|
||||
this.cells = new ArrayList<>();
|
||||
this(new ArrayList<>());
|
||||
}
|
||||
|
||||
public List<Cell> 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<Sudoku> getSudokus() {
|
||||
return sudokus;
|
||||
}
|
||||
|
||||
void setSudokus(List<Sudoku> sudokus) {
|
||||
this.sudokus = sudokus;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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<IConstraint> constraints;
|
||||
private final List<Constraint> constraints;
|
||||
/**
|
||||
* Largeur des Blocks s'ils sont rectangulaires, valant 0 si ce n'est pas le cas.
|
||||
*/
|
||||
private int blockWidth;
|
||||
|
||||
public Sudoku(List<Cell> cells, List<Block> blocks, List<IConstraint> constraints) {
|
||||
public Sudoku(List<Cell> cells, List<Block> blocks, List<Constraint> 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<IConstraint> getConstraints() {
|
||||
public List<Constraint> 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<Cell> cells = this.getCells();
|
||||
for (Cell cell : cells) {
|
||||
Coordinate coord = null;
|
||||
@@ -275,7 +277,11 @@ public class Sudoku {
|
||||
System.out.println("Cas jamais atteint.");
|
||||
}
|
||||
List<Integer> 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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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<IConstraint> DEFAULT_CONSTRAINTS = Arrays.asList(new BlockConstraint(), new LineConstraint(), new ColumnConstraint());
|
||||
public static List<Constraint> 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<Constraint> 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<Constraint> 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<Coordinate, Integer>, association de Coordinate coordonnées et Integer valeurs, correspondant aux cases à remplir.
|
||||
*/
|
||||
public static void setImmutableCells(MultiDoku doku, Map<Coordinate, Integer> 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<Constraint> constraints) {
|
||||
int symbolCount = widthBlock * heightBlock;
|
||||
List<Cell> cases = initCells(symbolCount);
|
||||
List<Block> 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<Constraint> 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<Constraint> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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<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));
|
||||
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);
|
||||
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.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<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);
|
||||
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.solveRandom(dokuToTest2, rand);
|
||||
|
||||
assert(!isSolved);
|
||||
assert (!isSolved);
|
||||
|
||||
MultiDoku dokuToTest3 = SudokuFactory.createBasicEmptySquareSudoku(3);
|
||||
MultiDoku dokuToTest3 = SudokuFactory.createBasicEmptySquareDoku(3, SudokuFactory.DEFAULT_CONSTRAINTS);
|
||||
|
||||
Solver.solveRandom(dokuToTest3, rand);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user