diff --git a/app/src/main/java/gui/menu/StateMachine.java b/app/src/main/java/gui/menu/StateMachine.java index db25a51..85ea897 100644 --- a/app/src/main/java/gui/menu/StateMachine.java +++ b/app/src/main/java/gui/menu/StateMachine.java @@ -25,7 +25,7 @@ public class StateMachine { private void checkEscape() { if (ImGui.isKeyPressed(ImGuiKey.Escape) && menus.size() > 1) { - popState(); + menus.getLast().closeMenu(); } } diff --git a/app/src/main/java/gui/menu/SudokuView.java b/app/src/main/java/gui/menu/SudokuView.java index 1e218d0..a00b2e9 100644 --- a/app/src/main/java/gui/menu/SudokuView.java +++ b/app/src/main/java/gui/menu/SudokuView.java @@ -3,6 +3,7 @@ package gui.menu; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.concurrent.CancellationException; import gui.ColorGenerator; import gui.ColorGenerator.Color; @@ -11,7 +12,7 @@ import imgui.ImVec2; import imgui.ImVec4; import imgui.flag.ImGuiCol; import imgui.flag.ImGuiStyleVar; -import sudoku.solver.Solver; +import sudoku.solver.StupidSolver; import sudoku.structure.Block; import sudoku.structure.Cell; import sudoku.structure.MultiDoku; @@ -23,6 +24,7 @@ public class SudokuView extends BaseView { private final MultiDoku doku; private int currentIndex = -1; private final Map colorPalette; + private volatile Thread resolveThread = null; public SudokuView(StateMachine stateMachine, int width, int height) { super(stateMachine); @@ -31,6 +33,13 @@ public class SudokuView extends BaseView { initColors(); } + private void stopResolve() { + if (resolveThread != null && resolveThread.isAlive()) { + resolveThread.interrupt(); + resolveThread = null; + } + } + private void initColors() { List colors = ColorGenerator.greatPalette(doku.getSubGrid(0).getSize()); int index = 0; @@ -80,10 +89,44 @@ public class SudokuView extends BaseView { } } renderPopup(); + if (resolveThread != null) + ImGui.beginDisabled(); + if (ImGui.button("Résoudre")) { - Solver.solve(doku); + resolveThread = new Thread(new Runnable() { + @Override + public void run() { + try { + doku.getSubGrid(0).clear(); + StupidSolver.solve(doku); + Thread.sleep(200); + } catch (CancellationException | InterruptedException e) { + System.out.println("The user is bored !"); + } + stopResolve(); + } + }); } + boolean wantsToStop = false; + if (resolveThread != null && resolveThread.isAlive()){ + ImGui.endDisabled(); + if (ImGui.button("Annuler")) { + // we can't stop the Thread right now + wantsToStop = true; + } + } + if (resolveThread != null && !resolveThread.isAlive()) { + resolveThread.start(); + } + if (wantsToStop) + stopResolve(); renderReturnButton(); } + @Override + public void closeMenu() { + super.closeMenu(); + stopResolve(); + } + } diff --git a/app/src/main/java/sudoku/solver/StupidSolver.java b/app/src/main/java/sudoku/solver/StupidSolver.java new file mode 100644 index 0000000..9ed1b8a --- /dev/null +++ b/app/src/main/java/sudoku/solver/StupidSolver.java @@ -0,0 +1,48 @@ +package sudoku.solver; + +import java.util.concurrent.CancellationException; + +import sudoku.structure.MultiDoku; +import sudoku.structure.Sudoku; + +public class StupidSolver { + + private static boolean solve(Sudoku sudoku, int index) { + // mécanisme d'abandon + if (Thread.interrupted()) + throw new CancellationException("User wants to stop the solver"); + + // si tout est bon avant, on a gagné + if (!sudoku.isValidCoords(index)) + return true; + + // si la case n'est pas modifiable, on passe à la suivante + if (!sudoku.getCell(index).isMutable()) + return solve(sudoku, index + 1); + + var coords = sudoku.toCoords(index); + for (int symbol = 0; symbol < sudoku.getSize(); symbol++) { + if (sudoku.tryPlaceCellSymbol(coords[0], coords[1], symbol)) { + // on tente de placer sur la case suivante + if (solve(sudoku, index + 1)) { + return true; + } + } + } + // on a tout essayé et rien n'a fonctionné + sudoku.clearCell(coords[0], coords[1]); + return false; + } + + public static boolean solve(MultiDoku doku) { + if (doku.isValid()) + return true; + + for (Sudoku sudoku : doku.getSubGrids()) { + if (!solve(sudoku, 0)) + return false; + } + return true; + } + +} diff --git a/app/src/main/java/sudoku/structure/Sudoku.java b/app/src/main/java/sudoku/structure/Sudoku.java index df7fe77..8d88bde 100644 --- a/app/src/main/java/sudoku/structure/Sudoku.java +++ b/app/src/main/java/sudoku/structure/Sudoku.java @@ -22,14 +22,55 @@ public class Sudoku { this.constraints = constraints; } + public int[] toCoords(int index) { + return new int[]{index % getSize(), index / getSize()}; + } + + public int toIndex(int x, int y) { + return y * getSize() + x; + } + /** * @return wether the coords are in the sudoku */ public boolean isValidCoords(int x, int y) { - int index = y * getSize() + x; + int index = toIndex(x, y); + return isValidCoords(index); + } + + /** + * @return wether the coords are in the sudoku + */ + public boolean isValidCoords(int index) { return index < getSize() * getSize(); } + public boolean tryPlaceCellSymbol(int x, int y, int value) { + assert (isValidCoords(x, y)); + for (IConstraint constraint : this.constraints) { + if (!constraint.canBePlaced(this, x, y, value)) { + return false; + } + } + Cell cell = getCell(x, y); + cell.setSymbolIndex(value); + return true; + } + + public void clearCell(int x, int y) { + assert (isValidCoords(x, y)); + Cell cell = getCell(x, y); + cell.setSymbolIndex(Cell.NOSYMBOL); + } + + public void clear() { + for (int i = 0; i < getSize() * getSize(); i++) { + Cell cell = getCell(i); + if (cell.isMutable()) + cell.setSymbolIndex(Cell.NOSYMBOL); + } + } + /** * Try to place a cell at the given coordinate * @@ -53,7 +94,7 @@ public class Sudoku { } for (int i = 0; i < values.size(); i++) { int x = i % this.blocks.size(); - int y = (i-x) / this.blocks.size(); + int y = (i - x) / this.blocks.size(); int value = values.get(i); this.setCellSymbol(x, y, value); } @@ -65,8 +106,8 @@ public class Sudoku { return false; } for (int i = 0; i < values.size(); i++) { - int x = i%this.blocks.size(); - int y = (i-x)/this.blocks.size(); + int x = i % this.blocks.size(); + int y = (i - x) / this.blocks.size(); int value = values.get(i); if (value != Cell.NOSYMBOL) { Cell cellPlaced = this.setCellSymbol(x, y, value); @@ -79,12 +120,11 @@ public class Sudoku { return true; } - public Cell getCell(int x, int y) { int index = y * getSize() + x; assert (isValidCoords(x, y)); try { - return this.cells.get(index); + return this.cells.get(index); } catch (IndexOutOfBoundsException e) { return null; } @@ -212,7 +252,8 @@ public class Sudoku { coords = this.getCoordinateCell(cell); cell.setSymbolIndex(Cell.NOSYMBOL); - List possibleSymbols = constraint.getPossibleSymbols(this, coords.getX(), coords.getY()); + List possibleSymbols = constraint.getPossibleSymbols(this, coords.getX(), + coords.getY()); cell.setSymbolIndex(symbolPlaced); if (possibleSymbols.size() != 1 || possibleSymbols.get(0) != symbolPlaced) { return false;