diff --git a/app/src/main/java/gui/menu/SudokuView.java b/app/src/main/java/gui/menu/SudokuView.java index 39d01ef..a416bf6 100644 --- a/app/src/main/java/gui/menu/SudokuView.java +++ b/app/src/main/java/gui/menu/SudokuView.java @@ -7,9 +7,11 @@ import imgui.ImGui; import imgui.ImGuiStyle; import sudoku.io.SudokuSerializer; import sudoku.solver.BacktrackingSolver; +import sudoku.solver.HintHelper; import sudoku.solver.HumanSolver; import sudoku.solver.MixedSolver; import sudoku.solver.Solver; +import sudoku.solver.HintHelper.Hint; import sudoku.structure.MultiDoku; public class SudokuView extends BaseView { @@ -68,6 +70,16 @@ public class SudokuView extends BaseView { stopResolve(); } + private void renderHintButton() { + if (!this.resolved && centeredButton("Indice")) { + Hint hint = HintHelper.getHint(this.doku, new BacktrackingSolver()); + assert (hint != null); + hint.cell().setSymbolIndex(hint.newValue()); + if (this.doku.isSolved()) + this.sudokuRenderer.onResolve.emit(); + } + } + private void startSolve(Solver solver) { resolveThread = new Thread(() -> { try { @@ -102,7 +114,6 @@ public class SudokuView extends BaseView { ImGui.beginDisabled(); if (!this.resolved && centeredButton("Résoudre")) { - // beginSolve = true; ImGui.openPopup("solve"); } @@ -131,6 +142,7 @@ public class SudokuView extends BaseView { @Override public void render() { sudokuRenderer.render(); + renderHintButton(); renderSolveButton(); renderSaveButton(); renderCancelButton(); diff --git a/app/src/main/java/sudoku/solver/HintHelper.java b/app/src/main/java/sudoku/solver/HintHelper.java new file mode 100644 index 0000000..b59fd3e --- /dev/null +++ b/app/src/main/java/sudoku/solver/HintHelper.java @@ -0,0 +1,54 @@ +package sudoku.solver; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Random; + +import sudoku.structure.Cell; +import sudoku.structure.MultiDoku; + +public class HintHelper { + + public static record Hint(Cell cell, int newValue) { + + } + + public static Hint getHint(MultiDoku doku, Solver solver) { + doku.getStateManager().pushState(); + doku.clearMutableCells(); + if (!solver.solve(doku)) + return null; + var stateSolved = doku.getStateManager().popAndGetState(); + // find differences + Map newValues = new HashMap<>(); + for (var entry : stateSolved.entrySet()) { + Cell cell = entry.getKey(); + // we only want the cells that can be filled + if (!cell.isMutable()) + continue; + int oldValue = cell.getSymbolIndex(); + int newValue = stateSolved.get(cell); + if (oldValue == newValue) + continue; + // we have to clear the cell + if (newValue == Cell.NOSYMBOL) + return new Hint(cell, newValue); + // we have to change the cell value + if (oldValue != Cell.NOSYMBOL && newValue != oldValue) + return new Hint(cell, newValue); + + // there is a valid move + newValues.put(cell, newValue); + } + + // this is too complex just for fetching a random entry, but whatever ... + Random r = new Random(); + List cells = new ArrayList<>(newValues.keySet()); + Cell randomCell = cells.get(r.nextInt(cells.size())); + int randomCellValue = newValues.get(randomCell); + return new Hint(randomCell, randomCellValue); + } + +} diff --git a/app/src/main/java/sudoku/structure/StateManager.java b/app/src/main/java/sudoku/structure/StateManager.java index 8ea9feb..9307955 100644 --- a/app/src/main/java/sudoku/structure/StateManager.java +++ b/app/src/main/java/sudoku/structure/StateManager.java @@ -15,27 +15,35 @@ public class StateManager { this.doku = doku; } - public void pushState() { - states.add(new HashMap<>()); - saveState(); + public Map pushState() { + states.add(saveState()); + return states.getLast(); } public void popState() { assert (states.size() > 0); - restoreState(); - states.pop(); + restoreState(states.pop()); } - private void restoreState() { - for (var entry : this.states.getLast().entrySet()) { + public Map popAndGetState() { + assert (states.size() > 0); + var currentState = saveState(); + restoreState(states.pop()); + return currentState; + } + + private void restoreState(Map state) { + for (var entry : state.entrySet()) { entry.getKey().setSymbolIndex(entry.getValue()); } } - private void saveState() { + private Map saveState() { + Map state = new HashMap<>(); for (Cell cell : this.doku.getCells()) { - states.getLast().put(cell, cell.getSymbolIndex()); + state.put(cell, cell.getSymbolIndex()); } + return state; } }