feat: implement multidoku resolution with shared constraints (without case propagation)

This commit is contained in:
2025-02-07 18:25:02 +01:00
parent dd21b9a13a
commit bf9bfc8323
3 changed files with 216 additions and 47 deletions

View File

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

View File

@@ -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());
// }
// }

View 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());
}
}