/// <summary> /// Recherche si ligne Vertical dupliqué /// </summary> /// <param name="sudoku"></param> /// <returns></returns> public static bool NoDuplicateRowVerti(Sudoku sudoku) { HashSet <int[]> hashSet = new HashSet <int[]>(); // premier élément hashSet.Add(sudoku.GetRowVertical(0)); for (int i = 1; i < Sudoku.SIZE - 1; i++) { var r = sudoku.GetRowVertical(i); foreach (var hash in hashSet) { // regarde si cette ligne existe déjà if (RowUtil.RowEqual(r, hash)) { // existe return(false); } } } hashSet = null; return(true); }
public static bool IsRowVerticalIsPermutation(Sudoku sudoku) { for (int i = 0; i < Sudoku.SIZE; i++) { if (RowUtil.IsPermutation(sudoku.GetRowVertical(i)) == false) { return(false); } } return(true); }
public static bool IsRowMatrixIsPermutation(Sudoku sudoku) { for (int i = 0; i < Sudoku.SIZE; i++) { if (RowUtil.IsPermutation(RowUtil.GetRowsbMatrixFlate(i, sudoku.Matrix)) == false) { return(false); } } return(true); }
public ExpertSudoku(List <Fact> facts) { //------------------------------------- // apply chaining forward //------------------------------------- Console.WriteLine("-----------------"); Console.WriteLine("Chainage avant"); Console.WriteLine("-----------------"); List <Exclure> exclures = null; // recherche les cases exclues. var flagValeurTrouve = true; while (flagValeurTrouve) { flagValeurTrouve = false; //--------------------- // exclusions //--------------------- exclures = new List <Exclure>(); // exclu a cause de la permetutaion facts.ForEach(f => f.Exclure(exclures)); // exclu les existantes differentes facts.ForEach(f => { for (int i = 0; i < f.Row.Count(); i++) { if (f.Row[i].HasValue) { foreach (var ee in exclures.Where(ex => ex.Valeur != f.Row[i].Value)) { ee.AExclure[f.Id, i] = 1; } } } }); //--------------------- // regle 1 // si une valeur est autorisée que sur une case alors on a une solution //--------------------- foreach (var exclure in exclures) { var valeurTrouvee = exclure.SearchValues(); // retirer if (valeurTrouvee.Count() > 0) { foreach (var vt in valeurTrouvee) { if (!facts[vt.Item1].Row[vt.Item2].HasValue) { flagValeurTrouve = true; // met à jour la matrice facts[vt.Item1].Row[vt.Item2] = exclure.Valeur; Console.WriteLine($"Ligne : {vt.Item1 + 1}, colonne {vt.Item2 + 1}, valeur : {exclure.Valeur}"); } } } } //--------------------- // regle 2 // test les exclusions si interdit a tous les chiffres sauf un chiffre alors // on a trouvé une solution ( cellule ne convient pas 1,3,4,5,6,7,8,9 => reponse =2) // en meme temps prepare la liste des permutations possbiles. //--------------------- foreach (var f in facts) { f.Tirage = new List <List <int> >(); for (int i = 0; i < Sudoku.SIZE; i++) { if (!f.Row[i].HasValue) { List <int> choixInterdit = new List <int>(); //= Fact.POSSIBLE; foreach (var ex in exclures) { if (ex.AExclure[f.Id, i] > 0) { // exclure choixInterdit.Add(ex.Valeur); } } var possible = Fact.POSSIBLE.Except(choixInterdit); if (possible.Count() == 1) { // on a trouvé une solution f.Row[i] = possible.First(); flagValeurTrouve = true; f.Tirage.Add(new List <int>() { possible.First() }); Console.WriteLine($"Ligne : {f.Id + 1}, colonne {i + 1}, valeur : {possible.First()}"); } else { //pas trouvé on mets les choix possible f.Tirage.Add(possible.ToList()); } } else { f.Tirage.Add(new List <int>() { f.Row[i].Value }); } } } } if (facts.All(f => f.Resolu)) { // Si chainage avant gagné List <int[]> tmp = new List <int[]>(); GetRowNonNullable(facts, tmp); RowUtil.PrintConsole(tmp); Solution = new Sudoku(tmp); return; } //------------------------------------- // apply chaining backward //------------------------------------- Console.WriteLine("-----------------"); Console.WriteLine("Chainage arriere"); Console.WriteLine("-----------------"); facts.ForEach(f => f.PermuteRow2()); // si apres permutation il y a une permutations ==1 une ligne a été résolu . on peut recommencer // les calculs avec les nouveaux fait inférés // iteration foreach (var t0 in facts[0].Permutaions) { foreach (var t1 in facts[1].Permutaions) { foreach (var t2 in facts[2].Permutaions) { foreach (var t3 in facts[3].Permutaions) { foreach (var t4 in facts[4].Permutaions) { foreach (var t5 in facts[5].Permutaions) { foreach (var t6 in facts[6].Permutaions) { foreach (var t7 in facts[7].Permutaions) { foreach (var t8 in facts[8].Permutaions) { List <int[]> rows = new List <int[]>(); rows.Add(t0); rows.Add(t1); rows.Add(t2); rows.Add(t3); rows.Add(t4); rows.Add(t5); rows.Add(t6); rows.Add(t7); rows.Add(t8); var sudoku = new Sudoku(rows); if (ApplyRule(sudoku)) { Solution = sudoku; RowUtil.PrintConsole(rows); return; } } } } } } } } } } Console.WriteLine("Aucunesolution !"); }
/// <summary> /// il ne reste q'une seule case possible /// </summary> /// <returns></returns> internal List <Tuple <int, int> > SearchValues() { var findCells = new List <Tuple <int, int> >(); // tester si c'est la seule possible sur une ligne for (int i = 0; i < Sudoku.SIZE; i++) { int nbPossible = 0, line = -1, column = -1; for (int c = 0; c < Sudoku.SIZE; c++) { if (AExclure[i, c] == 0) { line = i; column = c; nbPossible++; } } if (nbPossible == 1) { findCells.Add(new Tuple <int, int>(line, column)); } } // tester si c'est la seule possible sur une Colonne for (int c = 0; c < Sudoku.SIZE; c++) { int nbPossible = 0, line = -1, column = -1; for (int i = 0; i < Sudoku.SIZE; i++) { if (AExclure[i, c] == 0) { line = i; column = c; nbPossible++; } } if (nbPossible == 1) { findCells.Add(new Tuple <int, int>(line, column)); } } // seule valeur possible dans une sous matrice for (int i = 0; i < Sudoku.SIZE; i++) { var underMatrix = RowUtil.GetRowsbMatrixFlate(i, AExclure); // parcours cette sous matrice 3 X 3 int nbPossible = 0, line = -1; for (int l = 0; l < underMatrix.Length; l++) { if (underMatrix[l] == 0) { line = l; nbPossible++; } } if (nbPossible == 1) { // recherche des coordonnées dans la matrice principale int mainL = -1; int MainC = -1; RowUtil.getCoordMainMatrix(i, line, out mainL, out MainC); findCells.Add(new Tuple <int, int>(mainL, MainC)); } } return(findCells); }