@@ -1,5 +1,6 @@
|
||||
package sudoku.solver;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CancellationException;
|
||||
|
||||
@@ -8,17 +9,27 @@ import sudoku.structure.MultiDoku;
|
||||
|
||||
public class MixedSolver implements Solver {
|
||||
|
||||
private Cell findCellToBacktrack(MultiDoku doku, int maxPossibilities) {
|
||||
private List<Cell> findCellToBacktrack(MultiDoku doku, int maxPossibilities) {
|
||||
int symbolCount = doku.getSubGrid(0).getSize();
|
||||
if (maxPossibilities > symbolCount)
|
||||
return null;
|
||||
|
||||
List<Cell> backtrackCells = new ArrayList<>();
|
||||
|
||||
for (Cell cell : doku.getCells()) {
|
||||
if (!cell.isMutable() || !cell.isEmpty())
|
||||
continue;
|
||||
|
||||
List<Integer> possibleSymbols = cell.getPossibleSymbols();
|
||||
if (possibleSymbols.size() == maxPossibilities) {
|
||||
return cell;
|
||||
backtrackCells.add(cell);
|
||||
}
|
||||
|
||||
// grille non résolvable
|
||||
if (possibleSymbols.size() == 0)
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
return backtrackCells;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -34,41 +45,54 @@ public class MixedSolver implements Solver {
|
||||
throw new CancellationException("User wants to stop the solver");
|
||||
}
|
||||
|
||||
while (!doku.isSolved()) {
|
||||
boolean filledCell = false;
|
||||
for (Cell cell : doku.getCells()) {
|
||||
if (!cell.isMutable() || !cell.isEmpty())
|
||||
continue;
|
||||
int symbolCount = doku.getSubGrid(0).getSize();
|
||||
|
||||
List<Integer> possibleSymbols = cell.getPossibleSymbols();
|
||||
if (possibleSymbols.size() == 1) {
|
||||
cell.setSymbolIndex(possibleSymbols.getFirst());
|
||||
addStep(cell, steps);
|
||||
filledCell = true;
|
||||
}
|
||||
}
|
||||
// on ne peut plus remplir de cases, on tente de backtrack
|
||||
if (!filledCell) {
|
||||
int maxPossibilities = 2;
|
||||
Cell backtrackCell = null;
|
||||
while (backtrackCell == null) {
|
||||
backtrackCell = findCellToBacktrack(doku, maxPossibilities);
|
||||
maxPossibilities++;
|
||||
}
|
||||
// on fait du backtracking
|
||||
List<Integer> possibilities = backtrackCell.getPossibleSymbols();
|
||||
for (int symbol : possibilities) {
|
||||
doku.getStateManager().pushState();
|
||||
backtrackCell.setSymbolIndex(symbol);
|
||||
if (solve(doku, steps))
|
||||
return true;
|
||||
doku.getStateManager().popState();
|
||||
}
|
||||
}
|
||||
// on remplit les cases par déduction
|
||||
for (Cell cell : doku.getCells()) {
|
||||
if (!cell.isMutable() || !cell.isEmpty())
|
||||
continue;
|
||||
|
||||
List<Integer> possibleSymbols = cell.getPossibleSymbols();
|
||||
if (possibleSymbols.size() == 1) {
|
||||
cell.setSymbolIndex(possibleSymbols.getFirst());
|
||||
addStep(cell, steps);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
if (doku.isSolved())
|
||||
return true;
|
||||
|
||||
// on ne peut plus remplir de cases, on tente de backtrack
|
||||
for (int maxPossibilities = 2; maxPossibilities <= symbolCount; maxPossibilities++) {
|
||||
List<Cell> backtrackCells = new ArrayList<>();
|
||||
while (backtrackCells.isEmpty()) {
|
||||
backtrackCells = findCellToBacktrack(doku, maxPossibilities);
|
||||
// grille non résolvable
|
||||
if (backtrackCells == null) {
|
||||
return false;
|
||||
}
|
||||
maxPossibilities++;
|
||||
}
|
||||
// on fait du backtracking
|
||||
for (Cell backtrackCell : backtrackCells) {
|
||||
List<Integer> possibilities = backtrackCell.getPossibleSymbols();
|
||||
|
||||
// System.out.println("Backtraing on " + backtrackCell);
|
||||
|
||||
// on tente de placer chacun des symboles
|
||||
for (int symbol : possibilities) {
|
||||
var state = doku.getStateManager().pushState();
|
||||
backtrackCell.setSymbolIndex(symbol);
|
||||
if (solve(doku, steps)) {
|
||||
// doku.getStateManager().forgetState();
|
||||
return true;
|
||||
}
|
||||
doku.getStateManager().popState();
|
||||
doku.getStateManager().restoreState(state);
|
||||
}
|
||||
}
|
||||
}
|
||||
return doku.isSolved();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -25,6 +25,10 @@ public class StateManager {
|
||||
this.doku = doku;
|
||||
}
|
||||
|
||||
public void forgetState() {
|
||||
states.pop();
|
||||
}
|
||||
|
||||
public Map<Cell, Integer> pushState() {
|
||||
states.add(saveState());
|
||||
return states.getLast();
|
||||
@@ -42,7 +46,7 @@ public class StateManager {
|
||||
return currentState;
|
||||
}
|
||||
|
||||
private void restoreState(Map<Cell, Integer> state) {
|
||||
public void restoreState(Map<Cell, Integer> state) {
|
||||
for (var entry : state.entrySet()) {
|
||||
entry.getKey().setSymbolIndex(entry.getValue());
|
||||
}
|
||||
|
||||
78
app/src/main/java/sudoku/structure/SudokuFiller.java
Normal file
78
app/src/main/java/sudoku/structure/SudokuFiller.java
Normal file
@@ -0,0 +1,78 @@
|
||||
package sudoku.structure;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
import sudoku.solver.BacktrackingSolver;
|
||||
import sudoku.solver.HumanSolver;
|
||||
import sudoku.solver.MixedSolver;
|
||||
import sudoku.solver.RandomSolver;
|
||||
import sudoku.solver.Solver;
|
||||
|
||||
public class SudokuFiller {
|
||||
|
||||
private static boolean isPossiblySolvable(MultiDoku doku) {
|
||||
for (Cell cell : doku.getEmptyCells()) {
|
||||
if (cell.getPossibleSymbols().size() == 0)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void tryFillRandomCells(MultiDoku doku) {
|
||||
Random r = new Random();
|
||||
while (isPossiblySolvable(doku)) {
|
||||
int cellCount = doku.getEmptyCells().size();
|
||||
if (cellCount == 0)
|
||||
return;
|
||||
Cell cellToFill = doku.getEmptyCells().get(r.nextInt(cellCount));
|
||||
if (!cellToFill.isEmpty() || !cellToFill.isMutable())
|
||||
continue;
|
||||
|
||||
List<Integer> possibleSymbols = cellToFill.getPossibleSymbols();
|
||||
int symbolCount = possibleSymbols.size();
|
||||
// la cellule n'a pas de valeur possible
|
||||
if (symbolCount == 0)
|
||||
return;
|
||||
|
||||
cellToFill.setSymbolIndex(possibleSymbols.get(r.nextInt(symbolCount)));
|
||||
}
|
||||
}
|
||||
|
||||
private static void removeRandomCell(MultiDoku doku) {
|
||||
Random r = new Random();
|
||||
int cellCount = doku.getFilledCells().size();
|
||||
doku.getFilledCells().get(r.nextInt(cellCount)).clearCurrentSymbol();
|
||||
}
|
||||
|
||||
private static void makeSolvable(MultiDoku doku) {
|
||||
while (!isPossiblySolvable(doku)) {
|
||||
removeRandomCell(doku);
|
||||
}
|
||||
Solver solver = new BacktrackingSolver();
|
||||
boolean solvable = false;
|
||||
while (!solvable) {
|
||||
removeRandomCell(doku);
|
||||
doku.getStateManager().pushState();
|
||||
solvable = solver.solve(doku);
|
||||
doku.getStateManager().popState();
|
||||
System.out.println("eeeeeeeeeeeee");
|
||||
}
|
||||
}
|
||||
|
||||
private static void fillDoku(MultiDoku doku) {
|
||||
tryFillRandomCells(doku);
|
||||
makeSolvable(doku);
|
||||
}
|
||||
|
||||
private static void setCellsImmutable(MultiDoku doku) {
|
||||
for (Cell cell : doku.getFilledCells())
|
||||
cell.setImmutable();
|
||||
}
|
||||
|
||||
public static void fillDoku(MultiDoku doku, Difficulty difficulty) {
|
||||
fillDoku(doku);
|
||||
setCellsImmutable(doku);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user