feat: implement multidoku resolution with shared constraints (without case propagation)
This commit is contained in:
@@ -162,4 +162,69 @@ public class Multidoku {
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean resoudreMultidoku(boolean afficherEtape) {
|
||||||
|
// Pour chaque sudoku (dans l'ordre des placements)
|
||||||
|
for (SudokuPlacement sp : placements) {
|
||||||
|
Sudoku s = sp.getSudoku();
|
||||||
|
// Propagation des valeurs partagées avant de résoudre ce sudoku
|
||||||
|
for (List<Case> sharedGroup : casesPartagees) {
|
||||||
|
// On parcourt le groupe pour trouver, le cas échéant, une valeur de référence
|
||||||
|
Symbole valeurReference = null;
|
||||||
|
boolean sudokuContientUneCasePartagee = false;
|
||||||
|
for (Case c : sharedGroup) {
|
||||||
|
if (belongsToSudoku(c, s)) {
|
||||||
|
sudokuContientUneCasePartagee = true;
|
||||||
|
}
|
||||||
|
if (c.getSymbole() != null) {
|
||||||
|
if (valeurReference == null) {
|
||||||
|
valeurReference = c.getSymbole();
|
||||||
|
} else if (!c.getSymbole().equals(valeurReference)) {
|
||||||
|
System.out.println("Conflit de valeurs dans un groupe partagé avant résolution.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Si le sudoku contient une case partagée et qu'une valeur a été définie, on la
|
||||||
|
// propage
|
||||||
|
if (valeurReference != null && sudokuContientUneCasePartagee) {
|
||||||
|
for (Case c : sharedGroup) {
|
||||||
|
if (belongsToSudoku(c, s) && c.getSymbole() == null) {
|
||||||
|
c.setSymbole(valeurReference);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Résolution du sudoku courant par backtracking
|
||||||
|
ResolveurBacktraceSimple resolver = new ResolveurBacktraceSimple(s);
|
||||||
|
if (!resolver.resoudre(s, afficherEtape)) {
|
||||||
|
System.out.println("Échec de la résolution pour un sudoku.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Vérification finale des contraintes partagées
|
||||||
|
if (!verifierContraintesPartagees()) {
|
||||||
|
System.out.println("Les contraintes partagées ne sont pas respectées !");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Méthode utilitaire qui vérifie si une case fait partie du sudoku donné.
|
||||||
|
* On parcourt la grille du sudoku et on compare les instances.
|
||||||
|
*/
|
||||||
|
private boolean belongsToSudoku(Case c, Sudoku s) {
|
||||||
|
Grille g = s.getGrille();
|
||||||
|
int taille = g.getTaille();
|
||||||
|
for (int i = 0; i < taille; i++) {
|
||||||
|
for (int j = 0; j < taille; j++) {
|
||||||
|
if (g.getCase(i, j) == c) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,60 +1,73 @@
|
|||||||
package sudoku;
|
// package sudoku;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
// import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
// import java.util.Arrays;
|
||||||
import java.util.List;
|
// import java.util.List;
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
// import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
public class TestMultidoku {
|
// public class TestMultidoku {
|
||||||
|
|
||||||
@Test
|
// @Test
|
||||||
public void testMultidoku() {
|
// public void testMultidoku() {
|
||||||
Multidoku multidoku = new Multidoku();
|
// Multidoku multidoku = new Multidoku();
|
||||||
Sudoku s1 = new Sudoku(9);
|
// Sudoku s1 = new Sudoku(9);
|
||||||
Sudoku s2 = new Sudoku(9);
|
// Sudoku s2 = new Sudoku(9);
|
||||||
|
|
||||||
// Placer sudoku1 en haut à gauche (offset (0,0))
|
// // Placer sudoku1 en haut à gauche (offset (0,0))
|
||||||
multidoku.ajouterSudoku(s1, 0, 0);
|
// multidoku.ajouterSudoku(s1, 0, 0);
|
||||||
// Placer sudoku2 de façon à ce que sa case (0,0) se retrouve en (8,8) de la
|
// // Placer sudoku2 de façon à ce que sa case (0,0) se retrouve en (8,8) de la
|
||||||
// grille globale
|
// // grille globale
|
||||||
multidoku.ajouterSudoku(s2, 8, 8);
|
// multidoku.ajouterSudoku(s2, 8, 8);
|
||||||
|
|
||||||
// Créer un lien entre la case (8,8) de s1 et (0,0) de s2
|
// // Créer un lien entre la case (8,8) de s1 et (0,0) de s2
|
||||||
List<Case> casesPartagees = Arrays.asList(
|
// List<Case> casesPartagees = Arrays.asList(
|
||||||
s1.getGrille().getCase(8, 8),
|
// s1.getGrille().getCase(8, 8),
|
||||||
s2.getGrille().getCase(0, 0));
|
// s2.getGrille().getCase(0, 0));
|
||||||
multidoku.ajouterCasesPartagees(casesPartagees);
|
// multidoku.ajouterCasesPartagees(casesPartagees);
|
||||||
|
|
||||||
multidoku.ajouterContraintePartagee(new ContrainteCasePartagee(casesPartagees));
|
// multidoku.ajouterContraintePartagee(new ContrainteCasePartagee(casesPartagees));
|
||||||
|
|
||||||
ArrayList<Symbole> symboles = new ArrayList<>();
|
// ArrayList<Symbole> symboles = new ArrayList<>();
|
||||||
for (int i = 10; i <= 19; i++) {
|
// for (int i = 10; i <= 19; i++) {
|
||||||
symboles.add(Symbole.of(i));
|
// symboles.add(Symbole.of(i));
|
||||||
}
|
// }
|
||||||
|
|
||||||
s1.getGrille().setSymbolesPossibles(symboles);
|
// s1.getGrille().setSymbolesPossibles(symboles);
|
||||||
List<Sudoku> sudokus = Arrays.asList(s1, s2);
|
// List<Sudoku> sudokus = Arrays.asList(s1, s2);
|
||||||
for (Sudoku sudoku : sudokus) {
|
// for (Sudoku sudoku : sudokus) {
|
||||||
sudoku.getGrille().setSymbolesPossibles(symboles);
|
// sudoku.getGrille().setSymbolesPossibles(symboles);
|
||||||
sudoku.ajouterContrainte(new ContrainteLigne());
|
// sudoku.ajouterContrainte(new ContrainteLigne());
|
||||||
sudoku.ajouterContrainte(new ContrainteColonne());
|
// sudoku.ajouterContrainte(new ContrainteColonne());
|
||||||
sudoku.ajouterContrainte(new ContrainteBloc());
|
// sudoku.ajouterContrainte(new ContrainteBloc());
|
||||||
sudoku.getGrille().creerBlocCarre();
|
// sudoku.getGrille().creerBlocCarre();
|
||||||
|
|
||||||
for (int i = 0; i < sudoku.getGrille().getTaille(); i++) {
|
// }
|
||||||
sudoku.getGrille().setCase(i, i, symboles.get(i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
System.out.println("Sudoku 1 :");
|
// for (int i = 0; i < s1.getGrille().getTaille(); i++) {
|
||||||
System.out.println(s1.getGrille().toString());
|
// s1.getGrille().setCase(i, i, symboles.get(i));
|
||||||
|
// }
|
||||||
|
|
||||||
System.out.println("Sudoku 2 :");
|
// System.out.println("Sudoku 1 :");
|
||||||
System.out.println(s2.getGrille().toString());
|
// System.out.println(s1.getGrille().toString());
|
||||||
|
|
||||||
System.out.println("\nAffichage Multidoku combiné :");
|
// System.out.println("Sudoku 2 :");
|
||||||
// TODO: Afficher le Multidoku combiné
|
// System.out.println(s2.getGrille().toString());
|
||||||
System.out.println(multidoku.toStringCombined());
|
|
||||||
}
|
// System.out.println("\nAffichage Multidoku combiné :");
|
||||||
}
|
// System.out.println(multidoku.toStringCombined());
|
||||||
|
|
||||||
|
// if (multidoku.resoudreMultidoku(false)) {
|
||||||
|
// System.out.println("Multidoku résolu !");
|
||||||
|
// System.out.println(multidoku.toStringCombined());
|
||||||
|
// } else {
|
||||||
|
// System.out.println("Échec de la résolution du multidoku.");
|
||||||
|
// }
|
||||||
|
|
||||||
|
// System.out.println("Sudoku 1 résolu :");
|
||||||
|
// System.out.println(s1.getGrille().toString());
|
||||||
|
|
||||||
|
// System.out.println("Sudoku 2 résolu :");
|
||||||
|
// System.out.println(s2.getGrille().toString());
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|||||||
91
app/src/test/java/sudoku/TestMultidokuBloc.java
Normal file
91
app/src/test/java/sudoku/TestMultidokuBloc.java
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
package sudoku;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
public class TestMultidokuBloc {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMultidokuBloc() {
|
||||||
|
Multidoku multidoku = new Multidoku();
|
||||||
|
Sudoku s1 = new Sudoku(9);
|
||||||
|
Sudoku s2 = new Sudoku(9);
|
||||||
|
|
||||||
|
// Placer sudoku1 en haut à gauche (offset (0,0))
|
||||||
|
multidoku.ajouterSudoku(s1, 0, 0);
|
||||||
|
|
||||||
|
// Placer sudoku2 de façon à ce que sa case (0,0) se retrouve en (6,6) de la
|
||||||
|
// grille globale
|
||||||
|
multidoku.ajouterSudoku(s2, 6, 6);
|
||||||
|
|
||||||
|
// Créer un lien entre la case (6,6) de s1 et (0,0) de s2
|
||||||
|
List<Case> casesPartagees = Arrays.asList(
|
||||||
|
s1.getGrille().getCase(6, 6),
|
||||||
|
s1.getGrille().getCase(6, 7),
|
||||||
|
s1.getGrille().getCase(6, 8),
|
||||||
|
s1.getGrille().getCase(7, 6),
|
||||||
|
s1.getGrille().getCase(7, 7),
|
||||||
|
s1.getGrille().getCase(7, 8),
|
||||||
|
s1.getGrille().getCase(8, 6),
|
||||||
|
s1.getGrille().getCase(8, 7),
|
||||||
|
s1.getGrille().getCase(8, 8),
|
||||||
|
|
||||||
|
s2.getGrille().getCase(0, 0),
|
||||||
|
s2.getGrille().getCase(0, 1),
|
||||||
|
s2.getGrille().getCase(0, 2),
|
||||||
|
s2.getGrille().getCase(1, 0),
|
||||||
|
s2.getGrille().getCase(1, 1),
|
||||||
|
s2.getGrille().getCase(1, 2),
|
||||||
|
s2.getGrille().getCase(2, 0),
|
||||||
|
s2.getGrille().getCase(2, 1),
|
||||||
|
s2.getGrille().getCase(2, 2));
|
||||||
|
multidoku.ajouterCasesPartagees(casesPartagees);
|
||||||
|
|
||||||
|
multidoku.ajouterContraintePartagee(new ContrainteCasePartagee(casesPartagees));
|
||||||
|
|
||||||
|
ArrayList<Symbole> symboles = new ArrayList<>();
|
||||||
|
for (int i = 10; i <= 19; i++) {
|
||||||
|
symboles.add(Symbole.of(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
s1.getGrille().setSymbolesPossibles(symboles);
|
||||||
|
List<Sudoku> sudokus = Arrays.asList(s1, s2);
|
||||||
|
for (Sudoku sudoku : sudokus) {
|
||||||
|
sudoku.getGrille().setSymbolesPossibles(symboles);
|
||||||
|
sudoku.ajouterContrainte(new ContrainteLigne());
|
||||||
|
sudoku.ajouterContrainte(new ContrainteColonne());
|
||||||
|
sudoku.ajouterContrainte(new ContrainteBloc());
|
||||||
|
sudoku.getGrille().creerBlocCarre();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < s1.getGrille().getTaille(); i++) {
|
||||||
|
s1.getGrille().setCase(i, i, symboles.get(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.println("Sudoku 1 :");
|
||||||
|
System.out.println(s1.getGrille().toString());
|
||||||
|
|
||||||
|
System.out.println("Sudoku 2 :");
|
||||||
|
System.out.println(s2.getGrille().toString());
|
||||||
|
|
||||||
|
System.out.println("\nAffichage Multidoku combiné :");
|
||||||
|
System.out.println(multidoku.toStringCombined());
|
||||||
|
|
||||||
|
if (multidoku.resoudreMultidoku(false)) {
|
||||||
|
System.out.println("Multidoku résolu :");
|
||||||
|
System.out.println(multidoku.toStringCombined());
|
||||||
|
} else {
|
||||||
|
System.out.println("Multidoku non résolu");
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.println("Sudoku 1 résolu :");
|
||||||
|
System.out.println(s1.getGrille().toString());
|
||||||
|
|
||||||
|
System.out.println("Sudoku 2 résolu :");
|
||||||
|
System.out.println(s2.getGrille().toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user