public bool Resolve(GrilleSudoku s) // La fonction solve va pemettre de choisir la solution valide satsifaisant les contraintes de sodoku { for (int ligne = 0; ligne < Size; ligne++) // parcourt les lignes { for (int col = 0; col < Size; col++) // parcourt les colonnes { // Ce double for parcourt chaque colonne pour une ligne donnée if (s.GetCellule(ligne, col) == 0) // empty: si la cellule est vide alors on va rentrer dans la boucle for { for (int value = 1; value <= 9; value++) // qui va tester les valeur de 1 à 9 { if (IsValid(s, ligne, col, value)) // Si la valeur est valide avec les conditions de validité qu'on va définirapres dans le code { s.SetCell(ligne, col, value); // Alors on remplie la case vide avec la valeur valide if (Resolve(s)) // Et on appelle la fonction elle-meme pour la récursivité : Principe de backtracking { return(true); // On on valide la solution } else { s.SetCell(ligne, col, 0); // Sinon on réinitialise la valeur à 0 } } } return(false); // On refait le même processus } } } return(true); // Jusqu'à ce qu'on trouve une solution valide et on la garde }
public void AC3(GrilleSudoku s, List <List <int> > possibilites) { bool test = true; int CaseCheck; while (test) { test = false; for (int i = 0; i < 81; i++) { if (possibilites[i].Count == 1 && possibilites[i][0] != 10) { test = true; } } if (test == true) { CaseCheck = getNextMRV(possibilites); //AC3 ETAPE : 1 //Nb Possibilites = 1 if (possibilites[CaseCheck].Count == 1) { s.SetCell(CaseCheck / 9, CaseCheck % 9, possibilites[CaseCheck][0]); DeletePossibilites(s, possibilites, CaseCheck, possibilites[CaseCheck][0]); } } } }
public void assign(GrilleSudoku s, int cell, int value, List <int> assignment, List <List <int> > possibilites, List <List <int> > pruned) { assignment.Add(cell); s.SetCell(cell / 9, cell % 9, value); if (possibilites[cell].Contains(value)) { possibilites[cell].Remove(value); } if (!pruned[cell].Contains(value)) { pruned[cell].Add(value); } if (possibilites[cell].Count == 0) { possibilites[cell].Add(10); } // supp la Valeur des Possibilités des Voisins de la Cellule foreach (int neighboor_value in Cell_Neighboor(s, cell)) { if (possibilites[neighboor_value].Contains(value)) { possibilites[neighboor_value].Remove(value); } if (!pruned[neighboor_value].Contains(value)) { pruned[neighboor_value].Add(value); } } }
public void Solve(GrilleSudoku s) { List <List <int> > list_cell = new List <List <int> >(); foreach (var i in System.Linq.Enumerable.Range(0, 9)) { var ligne = new List <int>(9); list_cell.Add(ligne); foreach (var j in System.Linq.Enumerable.Range(0, 9)) { ligne.Add(s.GetCellule(j, i)); } } var monTableau = list_cell.Select(l => l.ToArray()).ToArray(); var monPuzzle = new Puzzle(monTableau, false); var monSolver = new Solver(monPuzzle); monSolver.DoWork(this, new System.ComponentModel.DoWorkEventArgs(null)); foreach (var i in System.Linq.Enumerable.Range(0, 9)) { foreach (var j in System.Linq.Enumerable.Range(0, 9)) { s.SetCell(i, j, monPuzzle.Rows[i][j].Value); } } }
public void Solve(GrilleSudoku grid) { Sud = new Sudoku(grid); s.sudoku = Sud; s.Solve(); Sud = s.sudoku; for (int i = 0; i < 9; i++) { for (int j = 0; j < 9; j++) { grid.SetCell(i, j, Sud.getCaseSudoku(i, j)); } } }
public void Solve(GrilleSudoku s) { var game = String.Concat(s.Cellules.Select(c => (c == 0) ? "." : c.ToString())); var solution = LinqSudokuSolver.search(LinqSudokuSolver.parse_grid(game)); foreach (var r in Enumerable.Range(0, 9)) { foreach (var c in Enumerable.Range(0, 9)) { var cellules = Int32.Parse(solution[LinqSudokuSolver.rows[r].ToString() + LinqSudokuSolver.cols[c].ToString()]); s.SetCell(r, c, cellules); } } }
public void Solve(GrilleSudoku s) { string game = string.Concat(s.Cellules.Select(c => (c == 0) ? "." : c.ToString())); Dictionary <string, string> solution = LinqSudokuSolver.Search(LinqSudokuSolver.Parse_grid(game)); for (int r = 0; r < cellIndices.Count(); r++) { for (int c = 0; c < cellIndices.Count(); c++) { var cellules = Int32.Parse(solution[LinqSudokuSolver.Rows[r].ToString() + LinqSudokuSolver.Cols[c].ToString()]); s.SetCell(r, c, cellules); } } }
public void unassign(GrilleSudoku s, int cell, List <int> assignment, List <List <int> > possibilites, List <List <int> > pruned) { int val_cell = s.GetCellule(cell / 9, cell % 9); if (assignment.Contains(cell)) { if (!possibilites[cell].Contains(val_cell)) { possibilites[cell].Add(val_cell); } if (possibilites[cell].Contains(10)) { possibilites[cell].Remove(10); } assignment.Remove(cell); s.SetCell(cell / 9, cell % 9, 0); List <int> l = new List <int>(); pruned[cell] = l; foreach (int neighboor_value in Cell_Neighboor(s, cell)) { List <int> r = new List <int>(); if (!possibilites[neighboor_value].Contains(val_cell)) { if (Is_present(s, possibilites, val_cell, neighboor_value)) { possibilites[neighboor_value].Add(val_cell); //Console.WriteLine("Voisin : {0} Re add dans poss : {1}", neighboor_value, val_cell); } } if (pruned[neighboor_value].Contains(val_cell)) { pruned[neighboor_value].Remove(val_cell); } } } else { Console.WriteLine("ERROOR 265 : UNSIGN A NON SIGN"); } }
public void Solve(GrilleSudoku s) { var substExprs = new List <Expr>(); var substVals = new List <Expr>(); for (int i = 0; i < 9; i++) { for (int j = 0; j < 9; j++) { if (s.GetCellule(i, j) != 0) { substExprs.Add(X[i][j]); substVals.Add(z3Context.MkInt(s.GetCellule(i, j))); } } } BoolExpr instance_c = (BoolExpr)GenericContraints.Substitute(substExprs.ToArray(), substVals.ToArray()); var z3Solver = GetSolver(); z3Solver.Assert(instance_c); if (z3Solver.Check() == Status.SATISFIABLE) { Model m = z3Solver.Model; for (int i = 0; i < 9; i++) { for (int j = 0; j < 9; j++) { if (s.GetCellule(i, j) == 0) { s.SetCell(i, j, ((IntNum)m.Evaluate(X[i][j])).Int); } } } } else { Console.WriteLine("Failed to solve sudoku"); } }
private static void SolutionToGrid(GrilleSudoku sudoku, IReadOnlyList <Tuple <int, int, int, bool> > internalRows, Solution solution) { var rowStrings = solution.RowIndexes .Select(rowIndex => internalRows[rowIndex]) .OrderBy(t => t.Item1) .ThenBy(t => t.Item2) .GroupBy(t => t.Item1, t => t.Item3) .Select(value => string.Concat(value)) .ToImmutableList(); String w = rowStrings.ItemRef(0); for (int a = 1; a <= 8; a++) { w = w + rowStrings.ItemRef(a); } for (int a = 1; a <= 162; a++) { if (a % 2 == 1) { w = w.Insert(a, " "); } } String[] Sub = w.Split(' '); int cpt = 0; for (int i = 0; i <= 8; i++) { for (int j = 0; j <= 8; j++) { sudoku.SetCell(i, j, int.Parse(Sub[cpt])); cpt = cpt + 1; } } // Console.WriteLine(sudoku.ToString()); }
public void Solve(GrilleSudoku s) { int[][] sJaggedTableau = Enumerable.Range(0, 9).Select(i => Enumerable.Range(0, 9).Select(j => s.GetCellule(i, j)).ToArray()).ToArray(); var sTableau = To2D(sJaggedTableau); Program.estValide(sTableau, 0); Enumerable.Range(0, 9).ToList().ForEach(i => Enumerable.Range(0, 9).ToList().ForEach(j => s.SetCell(i, j, sTableau[i, j]))); }
//NOUVEAU CODE public void Solve2(GrilleSudoku s) { bool solved = false; bool full = false; // If this is true after a segment, the puzzle is solved and we can break bool deadEnd = false; List <List <int> > list_cell = new List <List <int> >(); foreach (var i in System.Linq.Enumerable.Range(0, 9)) { var ligne = new List <int>(9); list_cell.Add(ligne); foreach (var j in System.Linq.Enumerable.Range(0, 9)) { ligne.Add(s.GetCellule(j, i)); } } var monTableau = list_cell.Select(l => l.ToArray()).ToArray(); var monPuzzle = new Puzzle(monTableau, false); var monSolver = new Solver(monPuzzle); //monSolver.DoWork(this, new System.ComponentModel.DoWorkEventArgs(null)); List <Cell> allCells = null; Stack <BackTrackingState> exploredCellValues = null; monPuzzle.RefreshCandidates(); do { deadEnd = false; // First we do human inference do { full = true; bool changed = false; // Check for naked singles or a completed puzzle for (int x = 0; x < 9; x++) { for (int y = 0; y < 9; y++) { Cell cell = monPuzzle[x, y]; if (cell.Value == 0) { full = false; // Check for naked singles int[] a = cell.Candidates.ToArray(); // Copy if (a.Length == 1) { cell.Set(a[0]); changed = true; } } } } // Solved or failed to solve if (full || (!changed && !monSolver.RunTechnique())) { break; } } while (true); full = monPuzzle.Rows.All(row => row.All(c => c.Value != 0)); //full = s.SetCell(x, y, monPuzzle.Rows[x][y].Value); // If puzzle isn't full, we do exploration if (!full) { // Les Sudokus les plus difficiles ne peuvent pas être résolus avec un stylo bille, c'est à dire en inférence pure. // Il va falloir lacher le stylo bille et prendre le crayon à papier et la gomme pour commencer une exploration fondée sur des hypothèses avec possible retour en arrière if (allCells == null) { allCells = monPuzzle.Rows.SelectMany((row, rowIdx) => row).ToList(); exploredCellValues = new Stack <BackTrackingState>(); } //puzzle.RefreshCandidates(); // Pour accélérer l'exploration et éviter de traverser la feuille en gommant trop souvent, on va utiliser les heuristiques des problèmes à satisfaction de contraintes // cf. les slides et le problème du "coffre de voiture" abordé en cours //heuristique MRV var minCandidates = allCells.Min(cell => cell.Candidates.Count > 0 ? cell.Candidates.Count : int.MaxValue); if (minCandidates != int.MaxValue) { // Utilisation de l'heuristique Deg: de celles qui ont le moins de candidats à égalité, on choisi celle la plus contraignante, celle qui a le plus de voisins (on pourrait faire mieux avec le nombre de candidats en commun avec ses voisins) var candidateCells = allCells.Where(cell => cell.Candidates.Count == minCandidates); //var degrees = candidateCells.Select(candidateCell => new {Cell = candidateCell, Degree = candidateCell.GetCellsVisible().Aggregate(0, (sum, neighbour) => sum + neighbour.Candidates.Count) }); var degrees = candidateCells.Select(candidateCell => new { Cell = candidateCell, Degree = candidateCell.GetCellsVisible().Count(c => c.Value == 0) }).ToList(); //var targetCell = list_cell.First(cell => cell.Candidates.Count == minCandidates); var maxDegree = degrees.Max(deg1 => deg1.Degree); var targetCell = degrees.First(deg => deg.Degree == maxDegree).Cell; //dernière exploration pour ne pas se mélanger les pinceaux BackTrackingState currentlyExploredCellValues; if (exploredCellValues.Count == 0 || !exploredCellValues.Peek().Cell.Equals(targetCell)) { currentlyExploredCellValues = new BackTrackingState() { Board = monPuzzle.GetBoard(), Cell = targetCell, ExploredValues = new List <int>() }; exploredCellValues.Push(currentlyExploredCellValues); } else { currentlyExploredCellValues = exploredCellValues.Peek(); } //utilisation de l'heuristique LCV: on choisi la valeur la moins contraignante pour les voisins var candidateValues = targetCell.Candidates.Where(i => !currentlyExploredCellValues.ExploredValues.Contains(i)); var neighbourood = targetCell.GetCellsVisible(); var valueConstraints = candidateValues.Select(v => new { Value = v, ContraintNb = neighbourood.Count(neighboor => neighboor.Candidates.Contains(v)) }).ToList(); var minContraints = valueConstraints.Min(vc => vc.ContraintNb); var exploredValue = valueConstraints.First(vc => vc.ContraintNb == minContraints).Value; currentlyExploredCellValues.ExploredValues.Add(exploredValue); targetCell.Set(exploredValue); //targetCell.Set(exploredValue, true); } else { //Plus de candidats possibles, on atteint un cul-de-sac if (monPuzzle.IsValid()) { solved = true; } else { deadEnd = true; } //deadEnd = true; } } else { //If puzzle is full, it's either solved or a deadend if (monPuzzle.IsValid()) { solved = true; } else { deadEnd = true; } } if (deadEnd) { //On se retrouve bloqué, il faut gommer et tenter d'autres hypothèses BackTrackingState currentlyExploredCellValues = exploredCellValues.Peek(); //On annule la dernière assignation currentlyExploredCellValues.Backtrack(monPuzzle); var targetCell = currentlyExploredCellValues.Cell; //targetCell.Set(0, true); while (targetCell.Candidates.All(i => currentlyExploredCellValues.ExploredValues.Contains(i))) { //on a testé toutes les valeurs possibles, On est à un cul de sac, il faut revenir en arrière exploredCellValues.Pop(); if (exploredCellValues.Count == 0) { Debug.WriteLine("bug in the algorithm techniques humaines"); } currentlyExploredCellValues = exploredCellValues.Peek(); //On annule la dernière assignation currentlyExploredCellValues.Backtrack(monPuzzle); targetCell = currentlyExploredCellValues.Cell; //targetCell.Set(0, true); } // D'autres valeurs sont possible pour la cellule courante, on les tente //utilisation de l'heuristique LCV var candidateValues = targetCell.Candidates.Where(i => !currentlyExploredCellValues.ExploredValues.Contains(i)); var neighbourood = targetCell.GetCellsVisible(); var valueConstraints = candidateValues.Select(v => new { Value = v, ContraintNb = neighbourood.Count(neighboor => neighboor.Candidates.Contains(v)) }).ToList(); var minContraints = valueConstraints.Min(vc => vc.ContraintNb); var exploredValue = valueConstraints.First(vc => vc.ContraintNb == minContraints).Value; currentlyExploredCellValues.ExploredValues.Add(exploredValue); targetCell.Set(exploredValue); } } while (!solved); foreach (var i in System.Linq.Enumerable.Range(0, 9)) { foreach (var j in System.Linq.Enumerable.Range(0, 9)) { s.SetCell(i, j, monPuzzle.Rows[i][j].Value); } } }
public void Solve(GrilleSudoku s) { //Création d'un solver Or-tools Solver solver = new Solver("Sudoku"); //Création de la grille de variables //Variables de décision IntVar[,] grid = solver.MakeIntVarMatrix(9, 9, 1, 9, "grid"); //VERIFIER IntVar[] grid_flat = grid.Flatten(); //VERIFIER //Masque de résolution for (int i = 0; i < cellIndices.Count(); i++) { for (int j = 0; j < cellIndices.Count(); j++) { if (s.GetCellule(i, j) > 0) { solver.Add(grid[i, j] == s.GetCellule(i, j)); } } } //Un chiffre ne figure qu'une seule fois par ligne/colonne/cellule for (int i = 0; i < cellIndices.Count(); i++) { // Lignes solver.Add((from j in cellIndices select grid[i, j]).ToArray().AllDifferent()); // Colonnes solver.Add((from j in cellIndices select grid[j, i]).ToArray().AllDifferent()); } //Cellules for (int i = 0; i < CELL.Count(); i++) { for (int j = 0; j < CELL.Count(); j++) { solver.Add((from di in CELL from dj in CELL select grid[i * cell_size + di, j * cell_size + dj] ).ToArray().AllDifferent()); } } //Début de la résolution DecisionBuilder db = solver.MakePhase(grid_flat, Solver.INT_VAR_SIMPLE, Solver.INT_VALUE_SIMPLE); solver.NewSearch(db); //Mise à jour du sudoku //int n = cell_size * cell_size; //Or on sait que cell_size = 3 -> voir ligne 13 //Inspiré de l'exemple : taille des cellules identique while (solver.NextSolution()) { for (int i = 0; i < 9; i++) { for (int j = 0; j < 9; j++) { s.SetCell(i, j, (int)grid[i, j].Value()); } } } //Si 4 lignes dessus optionnelles, EndSearch est obligatoire solver.EndSearch(); }
public void Solve(GrilleSudoku s) { SolverContext problem = SolverContext.GetContext(); Model model = problem.CreateModel(); Decision[][] grid = new Decision[9][]; // 0-based indices, 1-based values for (int r = 0; r < 9; ++r) { grid[r] = new Decision[9]; } for (int r = 0; r < 9; ++r) { for (int c = 0; c < 9; ++c) { grid[r][c] = new Decision(Domain.IntegerRange(1, 9), "grid" + r + c); } } for (int r = 0; r < 9; ++r) { model.AddDecisions(grid[r]); } //for (int r = 0; r < 9; ++r) // alternative to above // for (int c = 0; c < 9; ++c) // model.AddDecisions(grid[r][c]); Console.WriteLine("\nCreating generic row constraints"); for (int r = 0; r < 9; ++r) { model.AddConstraint("rowConstraint" + r, Model.AllDifferent(grid[r])); } Console.WriteLine("Creating generic column constraints"); for (int c = 0; c < 9; ++c) { for (int first = 0; first < 8; ++first) { for (int second = first + 1; second < 9; ++second) { model.AddConstraint("colConstraint" + c + first + second, grid[first][c] != grid[second][c]); } } } Console.WriteLine("Creating generic sub-cube constraints"); // cube constraints for grid[a][b] and grid[x][y] for (int r = 0; r < 9; r += 3) { for (int c = 0; c < 9; c += 3) { for (int a = r; a < r + 3; ++a) { for (int b = c; b < c + 3; ++b) { for (int x = r; x < r + 3; ++x) { for (int y = c; y < c + 3; ++y) { if ((x == a && y > b) || (x > a)) { // xy > ab model.AddConstraint("cubeConstraint" + a + b + x + y, grid[a][b] != grid[x][y]); } } // y } // x } // b } // a } // c } // r Console.WriteLine("Creating problem specific data constraints"); // brute force approach: //model.AddConstraint("v02", grid[0][2] == 6); //model.AddConstraint("v03", grid[0][3] == 2); //model.AddConstraint("v07", grid[0][7] == 8); //model.AddConstraint("v12", grid[1][2] == 8); //model.AddConstraint("v13", grid[1][3] == 9); //model.AddConstraint("v14", grid[1][4] == 7); //model.AddConstraint("v22", grid[2][2] == 4); //model.AddConstraint("v23", grid[2][3] == 8); //model.AddConstraint("v24", grid[2][4] == 1); //model.AddConstraint("v26", grid[2][6] == 5); //model.AddConstraint("v34", grid[3][4] == 6); //model.AddConstraint("v38", grid[3][8] == 2); //model.AddConstraint("v41", grid[4][1] == 7); //model.AddConstraint("v47", grid[4][7] == 3); //model.AddConstraint("v50", grid[5][0] == 6); //model.AddConstraint("v54", grid[5][4] == 5); //model.AddConstraint("v62", grid[6][2] == 2); //model.AddConstraint("v64", grid[6][4] == 4); //model.AddConstraint("v65", grid[6][5] == 7); //model.AddConstraint("v66", grid[6][6] == 1); //model.AddConstraint("v72", grid[7][2] == 3); //model.AddConstraint("v74", grid[7][4] == 2); //model.AddConstraint("v75", grid[7][5] == 8); //model.AddConstraint("v76", grid[7][6] == 4); //model.AddConstraint("v81", grid[8][1] == 5); //model.AddConstraint("v85", grid[8][5] == 1); //model.AddConstraint("v86", grid[8][6] == 2); ////model.AddConstraint("v86", grid[8][6] == 4); // creates unsolvable problem AddDataConstraints(s, model, grid); // more elegant approach Console.WriteLine("\nSolving. . . "); int numSolutions = NumberSolutions(problem); Console.WriteLine("\nThere is/are " + numSolutions + " Solution(s)\n"); Solution solution = problem.Solve(); //ShowAnswer(grid); // alternative to below for (int r = 0; r < 9; ++r) { for (int c = 0; c < 9; ++c) { double v = grid[r][c].GetDouble(); //Console.Write(" " + v); s.SetCell(r, c, (int)v); } } }