//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--; } }
//Retourne le nombre de grilles possibles avec les valeurs actuelles protected int Solve() { //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()) { return(1); } //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()) { return(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(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)); SetChiffreVisible(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(); int res = 0; //On teste toutes les valeurs for (int k = 0; (k < 9) && (res < 2); k++) { if (dispo[k]) { //On regarde combien de grilles sont possibles avec cette valeur Jeu temp = new Jeu(this); temp.SetChiffreVisible(i, j, k + 1); res += temp.Solve(); } } //res contient le nombre de grilles possibles avec les chiffres de départ (2 s'il y en a 2 ou plus) return(res); }