import org.chocosolver.solver.Model; import org.chocosolver.solver.Solver; import org.chocosolver.solver.search.limits.FailCounter; import org.chocosolver.solver.search.strategy.Search; import org.chocosolver.solver.search.strategy.selectors.variables.DomOverWDeg; import org.chocosolver.solver.search.strategy.selectors.variables.ImpactBased; import org.chocosolver.solver.variables.IntVar; public class CarreMagique { public static final int HEURISTIQUE_DEFAUT = 0; public static final int HEURISTIQUE_DOMOVERWDEG = 1; public static final int HEURISTIQUE_IMPACT_BASED_SEARCH = 2; public static final int HEURISTIQUE_ACTIVITY = 3; public static final String COHERENCE_BORNES = "BC"; public static final String COHERENCE_DOMAINES = "AC"; public static final int RESTART_AUCUN = 0; public static final int RESTART_LUBY = 1; public static final int RESTART_GEOMETRIQUE = 2; public static void main(String[] args) { final int n = 12; final int heuristique = HEURISTIQUE_ACTIVITY; final boolean bris_symetries = true; final int restart = RESTART_GEOMETRIQUE; final String coherence = COHERENCE_BORNES; Model model = new Model("Carré magique"); // Creation d'une matrice de dimensions n x n de variables dont les domaines sont les entiers de 1 a n^2. IntVar[][] lignes = model.intVarMatrix("x", n, n, 1, n * n); // Vecteur contenant toutes les variables de la matrice dans un seul vecteur IntVar[] toutesLesVariables = new IntVar[n * n]; for (int i = 0; i < n * n; i++) { toutesLesVariables[i] = lignes[i / n][i % n]; } // Ajout d'une contrainte forcant toutes les variables a prendre des variables differentes model.allDifferent(toutesLesVariables, coherence).post(); // Creation de la tranpose de la matrice lignes. IntVar[][] colonnes = new IntVar[n][n]; for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { colonnes[i][j] = lignes[j][i]; } } final int sommeMagique = n * (n * n + 1) / 2; // Creation d'une variable n'ayant qu'une seule valeur dans son domaine IntVar variableSommeMagique = model.intVar(sommeMagique); IntVar[] diagonale1 = new IntVar[n]; // Contient les variables sur la diagonale negative de la matrice IntVar[] diagonale2 = new IntVar[n]; // Contient les variables sur la diagonale positive de la matrice for (int i = 0; i < n; i++) { // Ajout de deux contraintes forcant les sommes des lignes et des colonnes a etre egales a la constante magique model.sum(lignes[i], "=", variableSommeMagique).post(); model.sum(colonnes[i], "=", variableSommeMagique).post(); diagonale1[i] = lignes[i][i]; diagonale2[i] = lignes[n - i - 1][i]; } model.sum(diagonale1, "=", variableSommeMagique).post(); model.sum(diagonale2, "=", variableSommeMagique).post(); if (bris_symetries) { for (int i = 1; i < n / 2; i++) model.arithm(lignes[i - 1][i - 1], "<", lignes[i][i]).post(); model.arithm(lignes[0][0], "<", lignes[n - 1][0]).post(); model.arithm(lignes[0][0], "<", lignes[0][n - 1]).post(); model.arithm(lignes[0][0], "<", lignes[n - 1][n - 1]).post(); // model.arithm(lignes[n - 1][0], "<", lignes[0][n - 1]).post(); } // Creation du solveur Solver solver = model.getSolver(); switch(heuristique) { case HEURISTIQUE_DOMOVERWDEG: solver.setSearch(Search.domOverWDegSearch(toutesLesVariables)); break; case HEURISTIQUE_IMPACT_BASED_SEARCH: solver.setSearch(new ImpactBased(toutesLesVariables, true)); break; case HEURISTIQUE_ACTIVITY: solver.setSearch(Search.activityBasedSearch(toutesLesVariables)); break; } switch(restart) { case RESTART_LUBY: solver.setLubyRestart(2, new FailCounter(model, 2), 25000); break; case RESTART_GEOMETRIQUE: solver.setGeometricalRestart(2, 2.1, new FailCounter(model, 2), 25000); break; } solver.findSolution(); for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { if (lignes[i][j].getValue() < 10) System.out.print(" "); if (lignes[i][j].getValue() < 100) System.out.print(" "); System.out.print(lignes[i][j].getValue()); System.out.print(" "); } System.out.println(""); } solver.printStatistics(); } }