//Masque les cases de la grille en fonction du niveau de difficulté protected void Masquer(int difficulte, Random rand) { bool[] tab = new bool[81]; for (int i = 0; i < 81; i++) { tab[i] = true; } int pos = 81; while (pos > 0) { //On choisit une case au hasard int c = rand.Next(pos); int x = -1, y = 0; for (int n = 0; x == -1; n++) { if (tab[n]) { if (c == 0) { x = n / 9; y = n % 9; } else { c--; } } } //On regarde si on peut retirer ce nombre bool[] dispo = new bool[9]; for (int n = 0; n < 9; n++) { dispo[n] = true; } //On regarde les valeurs sur la colonne ainsi que celles sur la ligne for (int n = 0; n < 9; n++) { int v = ValeurVisible(x, n); if ((v != 0) && (n != y)) { dispo[v - 1] = false; } v = ValeurVisible(n, y); if ((v != 0) && (n != x)) { dispo[v - 1] = false; } } //On regarde ensuite sur le carré int i = x / 3; int j = y / 3; for (int k = 0; (k < 3); k++) { for (int l = 0; (l < 3); l++) { if (ValeurVisible((3 * i) + k, (3 * j) + l) != 0) { dispo[ValeurVisible((3 * i) + k, (3 * j) + l) - 1] = false; } } } //On compte le nombre de possibilités int res = 0; for (int n = 0; n < 9; n++) { res += dispo[n] ? 1 : 0; } //Si on n'a pas plus de possibilités que le niveau de difficulté, on essaye d'enlever le chiffre if (res <= difficulte) { //On créé une copie pour tester Jeu temp = new Jeu(this); //On enlève la valeur temp.Set(x, y, 0); temp.CalcDispo(); if (1 == temp.Solve()) { //Si on a toujours une seule grille possible, on enlève la valeur SetChiffreCache(x, y, Valeur(x, y)); } else { //Sinon elle est necessaires : on la fixe SetChiffreVisible(x, y, Valeur(x, y)); } } else { //Sinon la valeur ne doit pas être modifiée : on la garde SetChiffreVisible(x, y, Valeur(x, y)); } tab[(9 * x) + y] = false; pos--; } }
//Remplie aléatoirement une grille protected Jeu[] RempAlea(Random rand) { //On charche pour quelle case on a le moins de possibilités //Pour optimiser l'algorithme on remplie toutes les cases avec une seule possibilité //Si on a rempli au moins une case, les possibilités sont diminuées donc on recommence la recherche //Enfin s'il n'y a plus que des cases avec plusieurs possibilités, on selectionne celle qui en a le moins //On créé une nouvelle grille pour chaque possibilité de la case choisie et on réappelle cette fonction pour essayer de resoudre la grille int i, j; bool valeursSimples; do { //On fait les vérifications à chaque itération car une valeur a pu être entrée alors qu'elle est erronnée //Si la grille est pleine et sans incohérance, on retourne 1 if (Possible() && Remplie()) { //Console.WriteLine("Fin normale"); return(new Jeu[] { this }); } //Si elle n'est pas cohérente, on retourne 0 //Une grille est incohérente si on a une case vide avec aucune possibilité ou plusieurs fois le même chiffre dans des carrés, colonnes ou lignes if (!Possible()) { //Console.WriteLine("Fin impossible"); return(new Jeu[0]); } //On regarde les possibilités i = 0; j = 0; //On réinitialise notre valeur de test de while() pour ne pas avoir de boucle infinie valeursSimples = false; for (int x = 0; (x < 9); x++) { for (int y = 0; (y < 9); y++) { //Si on a une case vide sans valeurs possible la grille est incohérente if (m_tab_jeu[x, y].NbDispo() == 0) { return(new Jeu[0]); } if (m_tab_jeu[x, y].NbDispo() == 1) { //Si on trouve une case avec une seule valeur possible, on rentre cette valeur bool[] temp = m_tab_jeu[x, y].Dispo(); //L'ajout d'une valeur a modifié les possibilités des cases sur ses ligne, colonne et carré //Il faut donc revérifier les cases au dessus de celle-ci, c'est pourquoi on recommence la boucle valeursSimples = true; for (int z = 0; z < 9; z++) { if (temp[z]) { Set(x, y, (z + 1)); } } } else if ((!valeursSimples) && (m_tab_jeu[x, y].NbDispo() < m_tab_jeu[i, j].NbDispo())) { //On ne continue de chercher la case avec le moins de possibilité que si aucune case ayant une seule possibilité n'a été trouvée //En effet, dans ce cas les probabilités ont changé donc la recherche est faussée pour cette boucle i = x; j = y; } } } } while (valeursSimples); //On fait en fonction des possibilités disponnibles bool[] dispo = m_tab_jeu[i, j].Dispo(); int taille = m_tab_jeu[i, j].NbDispo(); bool continuer; Jeu[] res; do { //On choisie une valeur aléatoire parmi celles disponnibles continuer = false; int valRand = rand.Next(taille); int valeur = 0; for (int k = 0; valeur == 0; k++) { if (dispo[k]) { if (valRand == 0) { valeur = k + 1; } else { valRand--; } } } //On regarde si on peut faire une grille avec cette valeur Jeu temp = new Jeu(this); temp.Set(i, j, valeur); res = temp.RempAlea(rand); if ((taille > 1) && (res.Length == 0)) { //Si aucune grille n'a pu être remplie avec cette valeur, on la supprime des possibilités et on recommence taille--; dispo[valeur - 1] = false; continuer = true; } } while (continuer); //Lorsqu'on arrive là, on a deux possibilités // > res est un tableau d'une case contenant la grille aléatoire terminée // > res est un tableau de 0 case et le problème sera traité par la fonction précédente dans la récursion return(res); }