feat : mixedSolve
All checks were successful
Linux arm64 / Build (push) Successful in 37s

This commit is contained in:
Melvyn
2025-01-30 14:32:15 +01:00
parent 44a4432ac0
commit d6c3504bc7
2 changed files with 88 additions and 57 deletions

View File

@@ -65,6 +65,7 @@ public class Solver {
/**
* Compte le nombre de solutions possibles au MultiDoku passé en paramètres.
*
* @param doku MultiDoku, MultiDoku dont on veut le nombre de solutions.
* @return int, nombre de solutions possibles.
*/
@@ -95,6 +96,7 @@ public class Solver {
/**
* Résout le MultiDoku passé en paramètre, avec backtracking.
*
* @param doku MultiDoku, MultiDoku à résoudre.
* @return boolean, valant true si le MultiDoku est résolu, false sinon.
*/
@@ -131,6 +133,7 @@ public class Solver {
/**
* Résout le MultiDoku passé en paramètre, avec règles de déduction.
*
* @param doku MultiDoku, MultiDoku à résoudre.
* @return boolean, valant true si le MultiDoku est résolu, false sinon.
*/
@@ -138,33 +141,31 @@ public class Solver {
if (Thread.interrupted())
throw new CancellationException("User wants to stop the solver");
Sudoku sudoku = doku.getSubGrid(0);
logger.log(Level.FINE,
'\n' + SudokuPrinter.toStringRectangleSudoku(sudoku,
sudoku.getBlockWidth() == 0 ? sudoku.getSize() : sudoku.getBlockWidth(),
sudoku.getBlockWidth() == 0 ? sudoku.getSize() : sudoku.getSize() / sudoku.getBlockWidth()));
if (doku.isSolved()) {
return true;
}
List<Cell> cellsToFill = doku.getEmptyCells();
if (cellsToFill.isEmpty()) {
return false;
}
while (!cellsToFill.isEmpty()) {
for (Cell cellToFill : cellsToFill) {
Sudoku sudoku = doku.getSubGrid(0);
logger.log(Level.FINE,
'\n' + SudokuPrinter.toStringRectangleSudoku(sudoku,
sudoku.getBlockWidth() == 0 ? sudoku.getSize() : sudoku.getBlockWidth(),
sudoku.getBlockWidth() == 0 ? sudoku.getSize() : sudoku.getSize() / sudoku.getBlockWidth()));
boolean blocked = true;
for (Cell cellToFill : cellsToFill) {
List<Integer> possibleSymbols = cellToFill.getPossibleSymbols();
if (possibleSymbols.size() != 1) {
continue;
}
cellToFill.setSymbolIndex(possibleSymbols.getFirst());
cellsToFill.remove(cellToFill);
blocked = false;
break;
List<Integer> possibleSymbols = cellToFill.getPossibleSymbols();
if (possibleSymbols.size() != 1) {
continue;
}
if (blocked) {
break;
}
cellToFill.setSymbolIndex(possibleSymbols.getFirst());
return Solver.humanSolve(doku);
}
return doku.isSolved();
@@ -172,42 +173,64 @@ public class Solver {
/**
* Résout le MultiDoku passé en paramètre, avec règles de déduction et backtracking.
*
* @param doku MultiDoku, MultiDoku à résoudre.
* @param rand Random, pour tester aléatoirement les symboles, lors du backtracking.
* @return boolean, valant true si le MultiDoku est résolu, false sinon.
*/
public static boolean mixedSolve(MultiDoku doku) {
if (Thread.interrupted())
public static boolean mixedSolve(MultiDoku doku, Random rand) {
if (Thread.interrupted()) {
throw new CancellationException("User wants to stop the solver");
List<Cell> cellsToFill = doku.getEmptyCells();
while (!cellsToFill.isEmpty()) {
Sudoku sudoku = doku.getSubGrid(0);
logger.log(Level.FINE,
'\n' + SudokuPrinter.toStringRectangleSudoku(sudoku,
sudoku.getBlockWidth() == 0 ? sudoku.getSize() : sudoku.getBlockWidth(),
sudoku.getBlockWidth() == 0 ? sudoku.getSize() : sudoku.getSize() / sudoku.getBlockWidth()));
boolean blocked = true;
for (Cell cellToFill : cellsToFill) {
List<Integer> possibleSymbols = cellToFill.getPossibleSymbols();
if (possibleSymbols.size() != 1) {
continue;
}
cellToFill.setSymbolIndex(possibleSymbols.getFirst());
cellsToFill.remove(cellToFill);
blocked = false;
break;
}
if (blocked) {
break;
}
}
return doku.isSolved();
Sudoku sudoku = doku.getSubGrid(0);
logger.log(Level.FINE,
'\n' + SudokuPrinter.toStringRectangleSudoku(
sudoku,
sudoku.getBlockWidth() == 0 ? sudoku.getSize() : sudoku.getBlockWidth(),
sudoku.getBlockWidth() == 0 ? sudoku.getSize() : sudoku.getSize() / sudoku.getBlockWidth())
);
if (doku.isSolved()) {
return true;
}
List<Cell> cellsToFill = doku.getEmptyCells();
if (cellsToFill.isEmpty()) {
return false;
}
//Règles de déduction
for (Cell cellToFill : cellsToFill) {
List<Integer> possibleSymbols = cellToFill.getPossibleSymbols();
if (possibleSymbols.size() != 1) {
continue;
}
cellToFill.setSymbolIndex(possibleSymbols.getFirst());
return Solver.mixedSolve(doku, rand);
}
//Si ça ne marche pas
//On fait du backtracking
Cell cellToFill = doku.getRandomEmptyCell(rand);
List<Integer> possibleSymbols = cellToFill.getPossibleSymbols();
while (!possibleSymbols.isEmpty()) {
int nextPossibleSymbolIndex = rand.nextInt(possibleSymbols.size());
int nextSymbol = possibleSymbols.get(nextPossibleSymbolIndex);
cellToFill.setSymbolIndex(nextSymbol);
if (Solver.mixedSolve(doku, rand)) {
return true;
}
cellToFill.setSymbolIndex(Cell.NOSYMBOL);
possibleSymbols.remove(nextPossibleSymbolIndex);
}
return false;
}
}

View File

@@ -1,9 +1,6 @@
package sudoku.structure;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.*;
import sudoku.io.SudokuSerializer;
@@ -170,4 +167,15 @@ public class MultiDoku {
return stateManager;
}
/**
* Renvoie une Cell vide choisie aléatoirement.
*
* @param rand Random, pour le choix aléatoire.
* @return Cell, une Cell vide.
*/
public Cell getRandomEmptyCell(Random rand) {
List<Cell> emptyCells = getEmptyCells();
int randomIndex = rand.nextInt(emptyCells.size());
return emptyCells.get(randomIndex);
}
}