From 89653f8517e23caa093e70aff2e767868a5a7bb6 Mon Sep 17 00:00:00 2001 From: Persson-dev Date: Wed, 29 Jan 2025 12:10:30 +0100 Subject: [PATCH 01/16] gui: display victory --- app/src/main/java/gui/RenderableMultidoku.java | 4 ++++ app/src/main/java/gui/SudokuRenderer.java | 12 +++++------- app/src/main/java/gui/menu/SudokuView.java | 13 ++++++++++++- 3 files changed, 21 insertions(+), 8 deletions(-) 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..6501b99 100644 --- a/app/src/main/java/gui/SudokuRenderer.java +++ b/app/src/main/java/gui/SudokuRenderer.java @@ -4,6 +4,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import common.Signal; import gui.ColorGenerator.Color; import imgui.ImGui; import imgui.ImVec2; @@ -24,6 +25,8 @@ public class SudokuRenderer { private static final ImVec4 TRANSPARENT = new ImVec4(); private static final ImVec2 cellSize = new ImVec2(50, 50); + public final Signal onResolve = new Signal(); + public SudokuRenderer(MultiDoku doku) { this.doku = RenderableMultidoku.fromMultidoku(doku); this.colorPalette = initColors(); @@ -55,6 +58,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(); } } @@ -86,11 +91,8 @@ public class SudokuRenderer { 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 +102,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/menu/SudokuView.java b/app/src/main/java/gui/menu/SudokuView.java index f0b18d1..39f1421 100644 --- a/app/src/main/java/gui/menu/SudokuView.java +++ b/app/src/main/java/gui/menu/SudokuView.java @@ -15,10 +15,17 @@ public class SudokuView extends BaseView { private Thread resolveThread; private final MultiDoku doku; + 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 +70,7 @@ public class SudokuView extends BaseView { boolean beginSolve = false; - if (centeredButton("Résoudre")) { + if (!resolved && centeredButton("Résoudre")) { beginSolve = true; } if (resolveThread != null) @@ -81,6 +88,10 @@ public class SudokuView extends BaseView { stopResolve(); }); } + + if (resolved) { + ImGui.text("Bravo !"); + } } @Override From cd81334c95427e3f10ea66d0c530db1e93d6accd Mon Sep 17 00:00:00 2001 From: Persson-dev Date: Wed, 29 Jan 2025 12:18:33 +0100 Subject: [PATCH 02/16] basic README --- README.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..7760c12 --- /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 From 859d5795d05ac581af41b55e9f5d96babb6a29ee Mon Sep 17 00:00:00 2001 From: Persson-dev Date: Wed, 29 Jan 2025 12:22:19 +0100 Subject: [PATCH 03/16] nerd --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7760c12..d74abb6 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ - Sudoku saves - Multiplayer -## Develop 🤓 +## Develop ☝🤓 ### Run 🏃 From 21b7011ece3f5542fd3e2f844ef431aa8db5d7f8 Mon Sep 17 00:00:00 2001 From: Persson-dev Date: Wed, 29 Jan 2025 12:25:43 +0100 Subject: [PATCH 04/16] =?UTF-8?q?=F0=9F=97=A3=EF=B8=8F=F0=9F=94=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d74abb6..0aeec94 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ ./gradlew run ``` -### Run tests 🧐 +### Run tests 🗣️🔥 ```sh ./gradlew test From 074131b69ce142f8b8637b8b576f921ecf95c83b Mon Sep 17 00:00:00 2001 From: Persson-dev Date: Wed, 29 Jan 2025 12:42:06 +0100 Subject: [PATCH 05/16] refactor sudoku selection --- app/src/main/java/gui/SudokuSelector.java | 97 +++++++++++++++++++ app/src/main/java/gui/menu/SoloMenu.java | 76 ++------------- .../main/java/sudoku/io/SudokuSerializer.java | 1 - 3 files changed, 104 insertions(+), 70 deletions(-) create mode 100644 app/src/main/java/gui/SudokuSelector.java diff --git a/app/src/main/java/gui/SudokuSelector.java b/app/src/main/java/gui/SudokuSelector.java new file mode 100644 index 0000000..b80fc3b --- /dev/null +++ b/app/src/main/java/gui/SudokuSelector.java @@ -0,0 +1,97 @@ +package gui; + +import common.Signal; +import imgui.ImGui; +import imgui.type.ImInt; +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 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); + + public SudokuSelector(boolean canGenEmptyGrid) { + this.canGenEmptyGrid = canGenEmptyGrid; + Difficulty[] diffs = Difficulty.values(); + difficulties = new String[diffs.length]; + for (int i = 0; i < diffs.length; i++) { + difficulties[i] = diffs[i].getDisplayName(); + } + } + + 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 render() { + 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")) { + selectSudoku(SudokuFactory.createBasicEmptySquareSudoku(sudokuSize.get()), false); + } + if (canGenEmptyGrid && ImGui.button("Générer une grille vide")) { + selectSudoku(SudokuFactory.createBasicEmptySquareSudoku(sudokuSize.get()), true); + } + break; + + case RECTANGLE: + ImGui.inputInt("Largeur", sudokuHeight); + ImGui.inputInt("Longueur", sudokuWidth); + if (ImGui.button("Résoudre un sudoku")) { + selectSudoku( + SudokuFactory.createBasicEmptyRectangleSudoku(sudokuWidth.get(), sudokuHeight.get()), + false); + } + if (canGenEmptyGrid && ImGui.button("Générer une grille vide")) { + selectSudoku( + SudokuFactory.createBasicEmptyRectangleSudoku(sudokuWidth.get(), sudokuHeight.get()), true); + } + break; + + case MULTIDOKU: + ImGui.inputInt("Taille", sudokuSize); + if (ImGui.button("Résoudre un sudoku")) { + selectSudoku(SudokuFactory.createBasicXShapedMultidoku(sudokuSize.get()), false); + } + if (canGenEmptyGrid && ImGui.button("Générer une grille vide")) { + selectSudoku(SudokuFactory.createBasicXShapedMultidoku(sudokuSize.get()), true); + } + + default: + break; + } + } + + public MultiDoku getDoku() { + return 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/sudoku/io/SudokuSerializer.java b/app/src/main/java/sudoku/io/SudokuSerializer.java index 6c5978f..43308cf 100644 --- a/app/src/main/java/sudoku/io/SudokuSerializer.java +++ b/app/src/main/java/sudoku/io/SudokuSerializer.java @@ -34,7 +34,6 @@ public class SudokuSerializer { for (Cell cell : sudoku.getCells()) { if (!cellIds.contains(cell)) { cellIds.add(cell); - } Block block = cell.getBlock(); From c4a9bf6354abceca4cee57df6e82cf917daaf984 Mon Sep 17 00:00:00 2001 From: Persson-dev Date: Wed, 29 Jan 2025 14:14:54 +0100 Subject: [PATCH 06/16] gui: select from file --- app/src/main/java/gui/SudokuSelector.java | 29 +++++++++++++++++-- .../java/sudoku/structure/SudokuFactory.java | 17 ++++++++++- 2 files changed, 43 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/gui/SudokuSelector.java b/app/src/main/java/gui/SudokuSelector.java index b80fc3b..a53456d 100644 --- a/app/src/main/java/gui/SudokuSelector.java +++ b/app/src/main/java/gui/SudokuSelector.java @@ -2,6 +2,8 @@ package gui; import common.Signal; import imgui.ImGui; +import imgui.extension.imguifiledialog.ImGuiFileDialog; +import imgui.extension.imguifiledialog.flag.ImGuiFileDialogFlags; import imgui.type.ImInt; import sudoku.structure.Difficulty; import sudoku.structure.MultiDoku; @@ -15,10 +17,10 @@ public class SudokuSelector { private final boolean canGenEmptyGrid; 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; @@ -48,6 +50,25 @@ public class SudokuSelector { 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, difficulties); @@ -88,6 +109,10 @@ public class SudokuSelector { default: break; } + if (ImGui.button("À partir d'un fichier")) { + ImGuiFileDialog.openDialog("browse-sudoku", "Choisissez un fichier", ".json", "."); + } + renderFileDialog(); } public MultiDoku getDoku() { diff --git a/app/src/main/java/sudoku/structure/SudokuFactory.java b/app/src/main/java/sudoku/structure/SudokuFactory.java index 535af2c..2c3265a 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; @@ -10,6 +13,7 @@ import sudoku.constraint.BlockConstraint; import sudoku.constraint.ColumnConstraint; import sudoku.constraint.IConstraint; import sudoku.constraint.LineConstraint; +import sudoku.io.SudokuSerializer; import sudoku.solver.Solver; public class SudokuFactory { @@ -148,7 +152,7 @@ public class SudokuFactory { } return false; - } + } /** * Créée un Sudoku vide dont les Blocks sont de taille widthBlock par heightBlock. @@ -246,4 +250,15 @@ public class SudokuFactory { } 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; + } + } } From a10d2eda9aa5dc8ee9f40226e8a17341d664aff5 Mon Sep 17 00:00:00 2001 From: Persson-dev Date: Wed, 29 Jan 2025 14:42:41 +0100 Subject: [PATCH 07/16] gui: fix big grid display --- app/src/main/java/gui/SudokuRenderer.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/gui/SudokuRenderer.java b/app/src/main/java/gui/SudokuRenderer.java index 6501b99..62894e5 100644 --- a/app/src/main/java/gui/SudokuRenderer.java +++ b/app/src/main/java/gui/SudokuRenderer.java @@ -11,6 +11,7 @@ import imgui.ImVec2; import imgui.ImVec4; import imgui.flag.ImGuiCol; import imgui.flag.ImGuiStyleVar; +import imgui.flag.ImGuiWindowFlags; import sudoku.structure.Block; import sudoku.structure.Cell; import sudoku.structure.MultiDoku; @@ -71,8 +72,12 @@ 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); - ImGui.beginChild(1, new ImVec2(cellSize.x * doku.getWidth(), cellSize.y * doku.getHeight())); + 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()), ImGuiWindowFlags.HorizontalScrollbar); ImGui.pushStyleVar(ImGuiStyleVar.FrameBorderSize, 2.0f); ImGui.pushStyleVar(ImGuiStyleVar.ItemSpacing, new ImVec2(0.0f, 0.0f)); From ed9b636b58197110bf8263709160f9757bd95ea0 Mon Sep 17 00:00:00 2001 From: Persson-dev Date: Wed, 29 Jan 2025 14:59:06 +0100 Subject: [PATCH 08/16] tests: make it faster --- app/src/test/java/sudoku/SudokuSerializerTest.java | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/app/src/test/java/sudoku/SudokuSerializerTest.java b/app/src/test/java/sudoku/SudokuSerializerTest.java index cacdadb..7081417 100644 --- a/app/src/test/java/sudoku/SudokuSerializerTest.java +++ b/app/src/test/java/sudoku/SudokuSerializerTest.java @@ -41,18 +41,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); } - - - } } From 00866256a7c7643aa54529b97e2510536c3b5d98 Mon Sep 17 00:00:00 2001 From: Persson-dev Date: Wed, 29 Jan 2025 15:07:34 +0100 Subject: [PATCH 09/16] gui: revert suoku scrolling --- app/src/main/java/gui/SudokuRenderer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/gui/SudokuRenderer.java b/app/src/main/java/gui/SudokuRenderer.java index 62894e5..f1a670c 100644 --- a/app/src/main/java/gui/SudokuRenderer.java +++ b/app/src/main/java/gui/SudokuRenderer.java @@ -77,7 +77,7 @@ public class SudokuRenderer { if (offsetX > 0) { ImGui.setCursorPosX(offsetX); } - ImGui.beginChild(1, new ImVec2(cellSize.x * doku.getWidth(), cellSize.y * doku.getHeight()), ImGuiWindowFlags.HorizontalScrollbar); + ImGui.beginChild(1, new ImVec2(cellSize.x * doku.getWidth(), cellSize.y * doku.getHeight())); ImGui.pushStyleVar(ImGuiStyleVar.FrameBorderSize, 2.0f); ImGui.pushStyleVar(ImGuiStyleVar.ItemSpacing, new ImVec2(0.0f, 0.0f)); From a616ab63e4ba01b5a3dad6192136c9ead8574bbe Mon Sep 17 00:00:00 2001 From: Persson-dev Date: Wed, 29 Jan 2025 15:08:30 +0100 Subject: [PATCH 10/16] gui: save sudoku --- app/src/main/java/gui/menu/SudokuView.java | 15 +++++++++++++++ app/src/main/java/sudoku/io/SudokuSerializer.java | 8 ++++---- .../test/java/sudoku/SudokuSerializerTest.java | 10 +++------- 3 files changed, 22 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/gui/menu/SudokuView.java b/app/src/main/java/gui/menu/SudokuView.java index 39f1421..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,6 +15,7 @@ public class SudokuView extends BaseView { private final SudokuRenderer sudokuRenderer; private Thread resolveThread; private final MultiDoku doku; + private String lastSavePath = null; private boolean resolved = false; @@ -94,10 +96,23 @@ public class SudokuView extends BaseView { } } + 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/io/SudokuSerializer.java b/app/src/main/java/sudoku/io/SudokuSerializer.java index 43308cf..366342d 100644 --- a/app/src/main/java/sudoku/io/SudokuSerializer.java +++ b/app/src/main/java/sudoku/io/SudokuSerializer.java @@ -106,9 +106,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); @@ -123,9 +123,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(); } /** diff --git a/app/src/test/java/sudoku/SudokuSerializerTest.java b/app/src/test/java/sudoku/SudokuSerializerTest.java index 7081417..3ed4dbe 100644 --- a/app/src/test/java/sudoku/SudokuSerializerTest.java +++ b/app/src/test/java/sudoku/SudokuSerializerTest.java @@ -1,18 +1,14 @@ package sudoku; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; +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) { @@ -24,10 +20,10 @@ public class SudokuSerializerTest { void testSaveWithSize(int blockWidth, int blockHeight) { MultiDoku doku = SudokuFactory.createBasicEmptyRectangleSudoku(blockWidth, blockHeight); - int saveNumber = SudokuSerializer.saveMultiDoku(doku); + String savePath = SudokuSerializer.saveMultiDoku(doku); MultiDoku otherDoku = null; try { - otherDoku = SudokuSerializer.getSavedMultiDoku(saveNumber); + otherDoku = SudokuFactory.fromfile(savePath); assert (otherDoku != null); } catch (Exception e) { e.printStackTrace(); From c0a3f85f24547f1c5ffa0ebd202c64f47e30222e Mon Sep 17 00:00:00 2001 From: Persson-dev Date: Wed, 29 Jan 2025 15:12:52 +0100 Subject: [PATCH 11/16] test: clean serializer files --- app/src/test/java/sudoku/SudokuSerializerTest.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/src/test/java/sudoku/SudokuSerializerTest.java b/app/src/test/java/sudoku/SudokuSerializerTest.java index 3ed4dbe..8871b32 100644 --- a/app/src/test/java/sudoku/SudokuSerializerTest.java +++ b/app/src/test/java/sudoku/SudokuSerializerTest.java @@ -1,5 +1,6 @@ package sudoku; +import java.io.File; import java.util.Random; import org.json.JSONObject; @@ -25,6 +26,9 @@ public class SudokuSerializerTest { try { 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; From de1f3c59d6275be46b90167a3c7034ab2f0be8cc Mon Sep 17 00:00:00 2001 From: Persson-dev Date: Wed, 29 Jan 2025 15:13:43 +0100 Subject: [PATCH 12/16] refactor isValid --- app/src/main/java/sudoku/structure/MultiDoku.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/sudoku/structure/MultiDoku.java b/app/src/main/java/sudoku/structure/MultiDoku.java index a1ea69a..0f78011 100644 --- a/app/src/main/java/sudoku/structure/MultiDoku.java +++ b/app/src/main/java/sudoku/structure/MultiDoku.java @@ -112,11 +112,11 @@ public class MultiDoku { * @return boolean, true s'il est valide et false sinon. */ public boolean isValid() { - boolean result = true; for (Sudoku sudoku : this.subGrids) { - result = sudoku.isValid() && result; + if(!sudoku.isValid()) + return false; } - return result; + return true; } @Override From cd792a0f8a194bcb2f3c8f919b5efa54ee9fa8a8 Mon Sep 17 00:00:00 2001 From: Persson-dev Date: Wed, 29 Jan 2025 15:48:01 +0100 Subject: [PATCH 13/16] add diagonal constraint --- .../sudoku/constraint/DiagonalConstraint.java | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 app/src/main/java/sudoku/constraint/DiagonalConstraint.java 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..63f9ad6 --- /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, i).getSymbolIndex() == newSymbolIndex) + return false; + } + } + // not in diagonal + return true; + } + +} From 5e26bea609978b3b987692f6d34921b852e8a89a Mon Sep 17 00:00:00 2001 From: Persson-dev Date: Wed, 29 Jan 2025 16:11:56 +0100 Subject: [PATCH 14/16] refactor: remove sudokufactory difficulties --- app/src/main/java/sudoku/structure/SudokuFactory.java | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/app/src/main/java/sudoku/structure/SudokuFactory.java b/app/src/main/java/sudoku/structure/SudokuFactory.java index 2c3265a..0013bbb 100644 --- a/app/src/main/java/sudoku/structure/SudokuFactory.java +++ b/app/src/main/java/sudoku/structure/SudokuFactory.java @@ -22,13 +22,7 @@ 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. From c16f2b8f5ad2fa2b54ca064bd14ed516a2f0f1ee Mon Sep 17 00:00:00 2001 From: Persson-dev Date: Wed, 29 Jan 2025 17:19:44 +0100 Subject: [PATCH 15/16] feat: dynamic constraints (Fixes #8) --- app/src/main/java/gui/SudokuRenderer.java | 27 +++++- app/src/main/java/gui/SudokuSelector.java | 49 +++++++--- .../main/java/gui/menu/MultiPlayerView.java | 5 +- app/src/main/java/sudoku/Main.java | 33 ++++--- .../java/sudoku/constraint/Constraint.java | 52 ++++++++++ .../sudoku/constraint/DiagonalConstraint.java | 6 +- app/src/main/java/sudoku/structure/Block.java | 14 +-- .../java/sudoku/structure/Difficulty.java | 16 +++- .../main/java/sudoku/structure/Sudoku.java | 76 ++++++++++----- .../java/sudoku/structure/SudokuFactory.java | 94 ++++++++++++------- .../java/sudoku/SudokuSerializerTest.java | 10 +- .../test/java/sudoku/solver/SolverTest.java | 78 +++++++-------- 12 files changed, 311 insertions(+), 149 deletions(-) create mode 100644 app/src/main/java/sudoku/constraint/Constraint.java diff --git a/app/src/main/java/gui/SudokuRenderer.java b/app/src/main/java/gui/SudokuRenderer.java index f1a670c..ca67ce9 100644 --- a/app/src/main/java/gui/SudokuRenderer.java +++ b/app/src/main/java/gui/SudokuRenderer.java @@ -1,8 +1,10 @@ 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; @@ -11,10 +13,11 @@ import imgui.ImVec2; import imgui.ImVec4; import imgui.flag.ImGuiCol; import imgui.flag.ImGuiStyleVar; -import imgui.flag.ImGuiWindowFlags; +import sudoku.constraint.Constraint; import sudoku.structure.Block; import sudoku.structure.Cell; import sudoku.structure.MultiDoku; +import sudoku.structure.Sudoku; public class SudokuRenderer { @@ -24,13 +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() { @@ -92,12 +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()) { blockColor = new Color(blockColor.r - 0.20f, blockColor.g - 0.20f, blockColor.b - 0.20f); - } else { } ImGui.pushStyleColor(ImGuiCol.Button, new ImVec4(blockColor.r, blockColor.g, blockColor.b, 1.0f)); String cellText = ""; diff --git a/app/src/main/java/gui/SudokuSelector.java b/app/src/main/java/gui/SudokuSelector.java index a53456d..343a47f 100644 --- a/app/src/main/java/gui/SudokuSelector.java +++ b/app/src/main/java/gui/SudokuSelector.java @@ -1,10 +1,15 @@ 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; @@ -19,7 +24,7 @@ public class SudokuSelector { private final ImInt sudokuType = new ImInt(0); private final ImInt difficulty = new ImInt(Difficulty.Medium.ordinal()); - private final String[] difficulties; + private final List contraints = new ArrayList<>(); private static final String[] sudokuTypes = { "Carré", "Rectangle", "Multidoku" }; private static final int SQUARE = 0, RECTANGLE = 1, MULTIDOKU = 2; @@ -31,10 +36,21 @@ public class SudokuSelector { public SudokuSelector(boolean canGenEmptyGrid) { this.canGenEmptyGrid = canGenEmptyGrid; - Difficulty[] diffs = Difficulty.values(); - difficulties = new String[diffs.length]; - for (int i = 0; i < diffs.length; i++) { - difficulties[i] = diffs[i].getDisplayName(); + 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))); } } @@ -71,15 +87,21 @@ public class SudokuSelector { public void render() { ImGui.combo("Type de Sudoku", sudokuType, sudokuTypes); - ImGui.combo("Difficulté", difficulty, difficulties); + 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.createBasicEmptySquareSudoku(sudokuSize.get()), false); + selectSudoku(SudokuFactory.createBasicEmptySquareDoku(sudokuSize.get(), getConstraints()), false); } if (canGenEmptyGrid && ImGui.button("Générer une grille vide")) { - selectSudoku(SudokuFactory.createBasicEmptySquareSudoku(sudokuSize.get()), true); + selectSudoku(SudokuFactory.createBasicEmptySquareDoku(sudokuSize.get(), getConstraints()), true); } break; @@ -88,22 +110,25 @@ public class SudokuSelector { ImGui.inputInt("Longueur", sudokuWidth); if (ImGui.button("Résoudre un sudoku")) { selectSudoku( - SudokuFactory.createBasicEmptyRectangleSudoku(sudokuWidth.get(), sudokuHeight.get()), + SudokuFactory.createBasicEmptyRectangleDoku(sudokuWidth.get(), sudokuHeight.get(), + getConstraints()), false); } if (canGenEmptyGrid && ImGui.button("Générer une grille vide")) { selectSudoku( - SudokuFactory.createBasicEmptyRectangleSudoku(sudokuWidth.get(), sudokuHeight.get()), true); + 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()), false); + selectSudoku(SudokuFactory.createBasicXShapedMultidoku(sudokuSize.get(), getConstraints()), false); } if (canGenEmptyGrid && ImGui.button("Générer une grille vide")) { - selectSudoku(SudokuFactory.createBasicXShapedMultidoku(sudokuSize.get()), true); + selectSudoku(SudokuFactory.createBasicXShapedMultidoku(sudokuSize.get(), getConstraints()), true); } default: diff --git a/app/src/main/java/gui/menu/MultiPlayerView.java b/app/src/main/java/gui/menu/MultiPlayerView.java index 09afd83..9a0ee2e 100644 --- a/app/src/main/java/gui/menu/MultiPlayerView.java +++ b/app/src/main/java/gui/menu/MultiPlayerView.java @@ -17,7 +17,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 +37,7 @@ public class MultiPlayerView extends BaseView { } else { if (ImGui.button("Démarrer")) { // temp - MultiDoku doku = SudokuFactory.createBasicXShapedMultidoku(3); + MultiDoku doku = SudokuFactory.createBasicXShapedMultidoku(3, SudokuFactory.DEFAULT_CONSTRAINTS); this.server.startGame(doku); } } 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 index 63f9ad6..95d6842 100644 --- a/app/src/main/java/sudoku/constraint/DiagonalConstraint.java +++ b/app/src/main/java/sudoku/constraint/DiagonalConstraint.java @@ -9,12 +9,12 @@ public class DiagonalConstraint implements IConstraint { if (x == y) { for (int i = 0; i < s.getSize(); i++) { if (s.getCell(i, i).getSymbolIndex() == newSymbolIndex) - return false; + return false; } } else if (s.getSize() - x == y) { for (int i = 0; i < s.getSize(); i++) { - if (s.getCell(s.getSize() - i, i).getSymbolIndex() == newSymbolIndex) - return false; + if (s.getCell(s.getSize() - i - 1, i).getSymbolIndex() == newSymbolIndex) + return false; } } // not in diagonal 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 4aff373..b664a68 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,14 @@ 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. + * 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,11 +44,12 @@ 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()); } /** * Transforme des coordonées d'une Cell en index. + * * @param x int, abscisse. * @param y int, ordonnée. * @return int, index correspondant. @@ -56,7 +60,9 @@ public class Sudoku { /** * Vérifie que des coordonnées correspondent bien à une Cell dans le Sudoku. - * @return boolean, valant true si les coordonnées sont dans les bornes du Sudoku, false sinon. + * + * @return boolean, valant true si les coordonnées sont dans les bornes du + * Sudoku, false sinon. */ public boolean isValidCoords(int x, int y) { int index = toIndex(x, y); @@ -65,21 +71,25 @@ public class Sudoku { /** * Vérifie que l'index correspond bien à une Cell dans le Sudoku. - * @return boolean, valant true si l'index est dans les bornes du Sudoku, false sinon. + * + * @return boolean, valant true si l'index est dans les bornes du Sudoku, false + * sinon. */ public boolean isValidCoords(int index) { return index < getSize() * getSize(); } /** - * Teste si on peut placer la value dans la Cell aux coordonnées x, y d'après les contraintes du Sudoku. - * @param x int, abscisse de la Cell voulue. - * @param y int, ordonnée de la Cell voulue. + * Teste si on peut placer la value dans la Cell aux coordonnées x, y d'après + * les contraintes du Sudoku. + * + * @param x int, abscisse de la Cell voulue. + * @param y int, ordonnée de la Cell voulue. * @param value int, index du symbole qu'on veut placer. * @return boolean, true si on peut la placer et false sinon. */ public boolean canBePlaced(int x, int y, int value) { - for (IConstraint constraint : this.constraints) { + for (Constraint constraint : this.constraints) { if (!constraint.canBePlaced(this, x, y, value)) { return false; } @@ -89,8 +99,9 @@ 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 */ @@ -105,6 +116,7 @@ public class Sudoku { /** * Vide la Cell dotn les coordonnées sont renseignées de son symbole. + * * @param x int, abscisse de la Cell voulue. * @param y int, coordonnée de la Cell voulue. */ @@ -132,14 +144,15 @@ 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; } @@ -151,6 +164,7 @@ public class Sudoku { /** * Place les symboles d'index contenus dans values dans les cases du Sudoku. + * * @param values List, liste des index des symboles à placer. * @return boolean, vaut true si les symboles ont été placés, false sinon. */ @@ -168,7 +182,9 @@ public class Sudoku { } /** - * Place les symboles d'index contenus dans values dans les cases du Sudoku et rend ces cases immuables. + * Place les symboles d'index contenus dans values dans les cases du Sudoku et + * rend ces cases immuables. + * * @param values List, liste des index des symboles à placer. * @return boolean, vaut true si les symboles ont été placés, false sinon. */ @@ -205,7 +221,7 @@ public class Sudoku { return this.cells.get(i); } - public List getConstraints() { + public List getConstraints() { return constraints; } @@ -223,6 +239,7 @@ public class Sudoku { /** * Vérifie si une Cell appartient au Sudoku. + * * @param cell Cell, cellule dont on veut vérifier l'appartenance au Sudoku. * @return boolean, vaut true si la Cell appartient au Sudoku. */ @@ -232,6 +249,7 @@ public class Sudoku { /** * Localise la Cell dans le Sudoku. + * * @param c Cell, cellule dont on veut les coordonées. * @return Coordinate, coordonnées de la Cell. * @throws Exception si la Cell n'appartient pas au Sudoku. @@ -264,8 +282,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 +293,8 @@ 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.getConstraint().getPossibleSymbols(this, coord.getX(), coord.getY())); cell.setPossibleSymbols(newPossibleSymbols); } @@ -298,6 +317,7 @@ public class Sudoku { /** * Renvoie la 1re Cell vide du Sudoku. + * * @return Cell, une Cell vide, ou null s'il n'y en a pas. */ public Cell getFirstEmptyCell() { @@ -311,8 +331,10 @@ public class Sudoku { /** * Renvoie l'index des symboles possibles de la Cell passée en paramètres. + * * @param cellToFill Cell, cellule dont on cherche les symboles posisbles. - * @return List, la liste des index des symboles possibles, vide si la Cell n'appartient pas au Sudoku. + * @return List, la liste des index des symboles possibles, vide si la + * Cell n'appartient pas au Sudoku. */ public List getPossibleSymbolsOfCell(Cell cellToFill) { List result = new ArrayList<>(); @@ -323,7 +345,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 { @@ -335,7 +357,9 @@ public class Sudoku { /** * Vérifie que le Sudoku est cohérent avec ses contraintes. - * @return boolean, valant true si le Sudoku est cohérent avec ses contraintes, false sinon. + * + * @return boolean, valant true si le Sudoku est cohérent avec ses contraintes, + * false sinon. */ public boolean isValid() { for (Cell cell : this.cells) { @@ -343,7 +367,7 @@ public class Sudoku { if (cell.isEmpty()) { return false; } - for (IConstraint constraint : this.constraints) { + for (Constraint constraint : this.constraints) { Coordinate coords; try { int symbolPlaced = cell.getSymbolIndex(); @@ -389,4 +413,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 0013bbb..183785e 100644 --- a/app/src/main/java/sudoku/structure/SudokuFactory.java +++ b/app/src/main/java/sudoku/structure/SudokuFactory.java @@ -11,6 +11,8 @@ 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.SudokuSerializer; @@ -27,10 +29,12 @@ public class SudokuFactory { * 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. + * * @param size int, nombre de Cells à initialiser. * @return List, liste des Cells initialisées. */ @@ -43,9 +47,11 @@ public class SudokuFactory { } /** - * Créée des Blocks de taille width par height à partir des cellules données, et les met dans une liste. - * @param cells List, liste des Cells à découper en Blocks. - * @param width int, largeur des Blocks à créer. + * Créée des Blocks de taille width par height à partir des cellules données, et + * les met dans une liste. + * + * @param cells List, liste des Cells à découper en Blocks. + * @param width int, largeur des Blocks à créer. * @param height int, hauteur des Blocks à créer. * @return List, liste des Blocks créés. */ @@ -73,29 +79,36 @@ public class SudokuFactory { } /** - * Créée un MultiDoku vide dont les Blocks sont de taille widthBlock par heightBlock. - * @param widthBlock int, largeur des Blocks. + * Créée un MultiDoku vide dont les Blocks sont de taille widthBlock par + * heightBlock. + * + * @param widthBlock int, largeur des Blocks. * @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))); } /** * Créée un MultiDoku vide dont les Blocks sont carrés de longueur size. + * * @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 immutableCells Map, association de Coordinate coordonnées et Integer valeurs, correspondant aux cases à remplir. + * Place des Cells immutables de valeurs fournies, aux Coordinate fournies dans + * le MultiDoku doku fourni. + * + * @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) { immutableCells.forEach((coordinate, symbol) -> { @@ -114,10 +127,12 @@ public class SudokuFactory { * * @param doku MultiDoku, MultiDoku dont on doit vider des Cells. * @param nbCellsToEmpty int, nombre de cases à retirer. - * @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. + * @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 { if (nbCellsToEmpty > doku.getCells().size()) { throw new Exception(); @@ -149,34 +164,41 @@ public class SudokuFactory { } /** - * Créée un Sudoku vide dont les Blocks sont de taille widthBlock par heightBlock. - * @param widthBlock int, largeur des Blocks. + * Créée un Sudoku vide dont les Blocks sont de taille widthBlock par + * heightBlock. + * + * @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(); @@ -193,6 +215,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++) { @@ -208,24 +231,27 @@ public class SudokuFactory { } /** - * Créée un MultiDoku de Blocks carrés de taille size composé de cinq Sudokus, dont un central qui partage chacun de ses Blockss d'angle avec un autre Sudoku. + * Créée un MultiDoku de Blocks carrés de taille size composé de cinq Sudokus, + * dont un central qui partage chacun de ses Blockss d'angle avec un autre + * Sudoku. + * * @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); /* * 2 3 - * 1 + * 1 * 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)); @@ -237,7 +263,7 @@ public class SudokuFactory { public static void fillDoku(MultiDoku doku, Difficulty difficulty) throws Exception { Solver.solveRandom(doku, random); - int nbCellsToEmpty = (int)(difficulty.getFactor()*doku.getNbCells()); + 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"); diff --git a/app/src/test/java/sudoku/SudokuSerializerTest.java b/app/src/test/java/sudoku/SudokuSerializerTest.java index 8871b32..d08fe19 100644 --- a/app/src/test/java/sudoku/SudokuSerializerTest.java +++ b/app/src/test/java/sudoku/SudokuSerializerTest.java @@ -13,14 +13,16 @@ import sudoku.structure.SudokuFactory; 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); + MultiDoku doku = SudokuFactory.createBasicEmptyRectangleDoku(blockWidth, blockHeight, + SudokuFactory.DEFAULT_CONSTRAINTS); String savePath = SudokuSerializer.saveMultiDoku(doku); MultiDoku otherDoku = null; try { @@ -33,7 +35,7 @@ public class SudokuSerializerTest { e.printStackTrace(); assert false; } - assert(doku.equals(otherDoku)); + assert (doku.equals(otherDoku)); } @Test diff --git a/app/src/test/java/sudoku/solver/SolverTest.java b/app/src/test/java/sudoku/solver/SolverTest.java index 85a38c4..88ea0c3 100644 --- a/app/src/test/java/sudoku/solver/SolverTest.java +++ b/app/src/test/java/sudoku/solver/SolverTest.java @@ -16,78 +16,72 @@ 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.isValid()); + assert (dokuResult.isValid()); Solver.solveRandom(dokuToTest, rand); - System.out.println("\n****************************\nDoku solved"); SudokuPrinter.printRectangleSudoku(dokuToTest.getSubGrid(0), 3, 3); + assert (dokuToTest.isValid()); - assert(dokuToTest.isValid()); + assert (dokuToTest.equals(dokuResult)); - 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); From ff85cbef01e09f7e6294dfd7773f61c4600ad69a Mon Sep 17 00:00:00 2001 From: Persson-dev Date: Wed, 29 Jan 2025 18:32:50 +0100 Subject: [PATCH 16/16] Fix #4 --- .../main/java/gui/menu/MultiPlayerView.java | 5 ++++- .../main/java/sudoku/io/SudokuSerializer.java | 18 +++++++++++++++++- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/gui/menu/MultiPlayerView.java b/app/src/main/java/gui/menu/MultiPlayerView.java index 9a0ee2e..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; @@ -37,7 +40,7 @@ public class MultiPlayerView extends BaseView { } else { if (ImGui.button("Démarrer")) { // temp - MultiDoku doku = SudokuFactory.createBasicXShapedMultidoku(3, SudokuFactory.DEFAULT_CONSTRAINTS); + MultiDoku doku = SudokuFactory.createBasicXShapedMultidoku(3, Arrays.asList(Constraint.Diagonal)); this.server.startGame(doku); } } diff --git a/app/src/main/java/sudoku/io/SudokuSerializer.java b/app/src/main/java/sudoku/io/SudokuSerializer.java index 366342d..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; @@ -73,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); @@ -90,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()); @@ -211,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); @@ -225,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); }