/// <summary> /// Algorithme permettant de verifier avec un temps d'avance si des valeurs legales ne pourront jamais etre assigne a une variable /// </summary> /// <param name="cspBase">Les contraintes actuelles sur le sudoku</param> /// <param name="assignement">L'attribution actuelle des variables</param> /// <param name="lastAssignedVariable">La derniere variable attribue</param> /// <returns>Les contraintes possiblement avec des valeurs legales en moins</returns> public static SudokuCSP ACThree(SudokuCSP cspBase, SudokuSolver.SudokuAssignment assignement, SudokuSolver.SudokuVariable lastAssignedVariable) { // Le fait d'effectuer une copie permet de ne pas avoir a s'inquieter de reset les changements qui on ete effectue // dans l'algorithme si le chemin n'est pas retenue // Cela amene cependant une complexite suplementaire dans l'algorithme SudokuCSP newCsp = new SudokuCSP(cspBase); // On modifie a jour le domaine de la derniere variable assigne // Cela est fait dans cette fonction car cela permet de ne pas avoir a se souvenir du domaine modifie // si jamais l'assignement de cette variable ne permet pas de resoudre le sudoku newCsp.m_variablesDomain[lastAssignedVariable.X, lastAssignedVariable.Y].Clear(); newCsp.m_variablesDomain[lastAssignedVariable.X, lastAssignedVariable.Y].Add(assignement.Grid[lastAssignedVariable.X, lastAssignedVariable.Y]); foreach (SudokuSolver.SudokuVariable neighbor in newCsp.m_variableRemainingNeighbor[lastAssignedVariable.X, lastAssignedVariable.Y]) { newCsp.m_variableRemainingNeighbor[neighbor.X, neighbor.Y].Remove(lastAssignedVariable); } Queue <Tuple <SudokuSolver.SudokuVariable, SudokuSolver.SudokuVariable> > arcs = new Queue <Tuple <SudokuSolver.SudokuVariable, SudokuSolver.SudokuVariable> >(); // On fait d'abord un tour sur les arcs entre toute les variables restantes et leur voisin foreach (SudokuSolver.SudokuVariable remainingVariable in assignement.RemainingVariable) { // Ici du fait que l'on sache dans quel variable on va modifier les domaines, on peut se permettre de ne pas rajouter ses voisins // a chaque fois qu'on lui enleve un domaine bool remove = false; foreach (SudokuSolver.SudokuVariable neighbor in newCsp.m_variablesNeighbors[remainingVariable.X, remainingVariable.Y]) { remove |= RemoveInconsistentValue(newCsp, remainingVariable, neighbor); } if (remove) { foreach (SudokuSolver.SudokuVariable remainingNeighbor in newCsp.m_variableRemainingNeighbor[remainingVariable.X, remainingVariable.Y]) { arcs.Enqueue(new Tuple <SudokuSolver.SudokuVariable, SudokuSolver.SudokuVariable>(remainingNeighbor, remainingVariable)); } } } // On effectue ensuite les operations necessaire sur la queue jusqu'a ce que celle-ci soit vide while (arcs.Count != 0) { Tuple <SudokuSolver.SudokuVariable, SudokuSolver.SudokuVariable> arc = arcs.Dequeue(); if (RemoveInconsistentValue(newCsp, arc.Item1, arc.Item2)) { foreach (SudokuSolver.SudokuVariable remainingNeighbor in newCsp.m_variableRemainingNeighbor[arc.Item1.X, arc.Item1.Y]) { arcs.Enqueue(new Tuple <SudokuSolver.SudokuVariable, SudokuSolver.SudokuVariable>(remainingNeighbor, arc.Item1)); } } } return(newCsp); }
/// <summary> /// Retourne une liste des variables auquel il reste le moins de variables legales /// </summary> /// <param name="assignment"></param> /// <returns>Les variables qui contiennent le moins de valeurs legales</returns> public List <SudokuSolver.SudokuVariable> MinimumRemainingValues(SudokuSolver.SudokuAssignment assignment) { int mrv = 10; List <SudokuSolver.SudokuVariable> values = new List <SudokuSolver.SudokuVariable>(); foreach (SudokuSolver.SudokuVariable variable in assignment.RemainingVariable) { // Recupere le nombre de valeurs restante de la variable // On peut se permettre de faire ca car on utilise le forward checking // Dans le cas contraire il aurait fallu regarder tous les voisin pour chaque variables int domainSize = m_variablesDomain[variable.X, variable.Y].Count; if (domainSize < mrv) { mrv = domainSize; values.Clear(); values.Add(variable); } else if (domainSize == mrv) { values.Add(variable); } } return(values); }
/// <summary> /// Constructeur /// </summary> /// <param name="assignment">Attribution initiale du sudoku</param> public SudokuCSP(SudokuSolver.SudokuAssignment assignment) { m_size = assignment.Size; int[,] grid = assignment.Grid; m_variablesDomain = new List <int> [m_size, m_size]; m_variablesNeighbors = new List <SudokuSolver.SudokuVariable> [m_size, m_size]; m_variableRemainingNeighbor = new List <SudokuSolver.SudokuVariable> [m_size, m_size]; SudokuSolver.SudokuVariable[,] tempVariableGrid = new SudokuSolver.SudokuVariable[m_size, m_size]; // Creer les variables for (int x = 0; x < m_size; x++) { for (int y = 0; y < m_size; y++) { tempVariableGrid[x, y] = new SudokuSolver.SudokuVariable(x, y); m_variablesDomain[x, y] = new List <int>(Enumerable.Range(1, m_size)); m_variablesNeighbors[x, y] = new List <SudokuSolver.SudokuVariable>(); m_variableRemainingNeighbor[x, y] = new List <SudokuSolver.SudokuVariable>(); } } int squareSize = (int)Math.Sqrt(m_size); // Creer les contraintes for (int x = 0; x < m_size; x++) { for (int y = 0; y < m_size; y++) { // Si la variable a deja ete assigne on peut mettre a jour son domaine et ne pas chercher ses voisins if (grid[x, y] != -1) { m_variablesDomain[x, y].Clear(); m_variablesDomain[x, y].Add(grid[x, y]); continue; } // Sinon on l'ajoute a la liste des variable non assignes assignment.AddRemainingVariable(tempVariableGrid[x, y]); // On va aussi chercher tous ses voisins // Si l'un d'entre eux a ete assigne on enleve sa valeur des valeurs legal de la variable courente, il n'est aussi pas // necessaire de l'ajouter a la liste des voisins restant de cette variables // Colonnes for (int k = 0; k < m_size; k++) { if (k != y) { m_variablesNeighbors[x, y].Add(tempVariableGrid[x, k]); if (grid[x, k] != -1) { m_variablesDomain[x, y].Remove(grid[x, k]); } else { m_variableRemainingNeighbor[x, y].Add(tempVariableGrid[x, k]); } } } // Lignes for (int k = 0; k < m_size; k++) { if (k != x) { m_variablesNeighbors[x, y].Add(tempVariableGrid[k, y]); if (grid[k, y] != -1) { m_variablesDomain[x, y].Remove(grid[k, y]); } else { m_variableRemainingNeighbor[x, y].Add(tempVariableGrid[k, y]); } } } // Carre for (int k = (x / squareSize) * squareSize; k < (x / squareSize) * squareSize + squareSize; k++) { for (int l = (y / squareSize) * squareSize; l < (y / squareSize) * squareSize + squareSize; l++) { if (x != k && y != l) { m_variablesNeighbors[x, y].Add(tempVariableGrid[k, l]); if (grid[k, l] != -1) { m_variablesDomain[x, y].Remove(grid[k, l]); } else { m_variableRemainingNeighbor[x, y].Add(tempVariableGrid[k, l]); } } } } } } }