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. * Compte le nombre de solutions possibles au MultiDoku passé en paramètres.
*
* @param doku MultiDoku, MultiDoku dont on veut le nombre de solutions. * @param doku MultiDoku, MultiDoku dont on veut le nombre de solutions.
* @return int, nombre de solutions possibles. * @return int, nombre de solutions possibles.
*/ */
@@ -95,6 +96,7 @@ public class Solver {
/** /**
* Résout le MultiDoku passé en paramètre, avec backtracking. * Résout le MultiDoku passé en paramètre, avec backtracking.
*
* @param doku MultiDoku, MultiDoku à résoudre. * @param doku MultiDoku, MultiDoku à résoudre.
* @return boolean, valant true si le MultiDoku est résolu, false sinon. * @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. * Résout le MultiDoku passé en paramètre, avec règles de déduction.
*
* @param doku MultiDoku, MultiDoku à résoudre. * @param doku MultiDoku, MultiDoku à résoudre.
* @return boolean, valant true si le MultiDoku est résolu, false sinon. * @return boolean, valant true si le MultiDoku est résolu, false sinon.
*/ */
@@ -138,33 +141,31 @@ public class Solver {
if (Thread.interrupted()) if (Thread.interrupted())
throw new CancellationException("User wants to stop the solver"); 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(); List<Cell> cellsToFill = doku.getEmptyCells();
if (cellsToFill.isEmpty()) {
return false;
}
while (!cellsToFill.isEmpty()) { for (Cell cellToFill : cellsToFill) {
Sudoku sudoku = doku.getSubGrid(0); List<Integer> possibleSymbols = cellToFill.getPossibleSymbols();
logger.log(Level.FINE, if (possibleSymbols.size() != 1) {
'\n' + SudokuPrinter.toStringRectangleSudoku(sudoku, continue;
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) { cellToFill.setSymbolIndex(possibleSymbols.getFirst());
break;
} return Solver.humanSolve(doku);
} }
return doku.isSolved(); 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. * Résout le MultiDoku passé en paramètre, avec règles de déduction et backtracking.
*
* @param doku MultiDoku, MultiDoku à résoudre. * @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. * @return boolean, valant true si le MultiDoku est résolu, false sinon.
*/ */
public static boolean mixedSolve(MultiDoku doku) { public static boolean mixedSolve(MultiDoku doku, Random rand) {
if (Thread.interrupted()) if (Thread.interrupted()) {
throw new CancellationException("User wants to stop the solver"); 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; package sudoku.structure;
import java.util.ArrayList; import java.util.*;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import sudoku.io.SudokuSerializer; import sudoku.io.SudokuSerializer;
@@ -170,4 +167,15 @@ public class MultiDoku {
return stateManager; 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);
}
} }