canellable stupid solver
All checks were successful
Linux arm64 / Build (push) Successful in 24m8s

This commit is contained in:
2025-01-24 21:41:12 +01:00
parent 00941edb19
commit 4b4ed76eb8
4 changed files with 142 additions and 10 deletions

View File

@@ -25,7 +25,7 @@ public class StateMachine {
private void checkEscape() {
if (ImGui.isKeyPressed(ImGuiKey.Escape) && menus.size() > 1) {
popState();
menus.getLast().closeMenu();
}
}

View File

@@ -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<Block, Color> 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<Color> 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();
}
}

View File

@@ -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;
}
}

View File

@@ -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<Integer> possibleSymbols = constraint.getPossibleSymbols(this, coords.getX(), coords.getY());
List<Integer> possibleSymbols = constraint.getPossibleSymbols(this, coords.getX(),
coords.getY());
cell.setSymbolIndex(symbolPlaced);
if (possibleSymbols.size() != 1 || possibleSymbols.get(0) != symbolPlaced) {
return false;