All pastes #517813 Raw Edit

Jester

public text v1 · immutable
#517813 ·published 2007-05-29 04:05 UTC
rendered paste body
using System;
using System.Collections.Generic;
using System.Text;

namespace SudokuProc
{
	class Program
	{
		private static Random randomG = new Random();
		static int[,] Grille = new int[9, 9];
		static bool[,] Verrou = new bool[9, 9];
		static bool[,] verrouUtilisateur = new bool[9, 9];
		static bool GameStarted = false;
		static bool modeFacile;
		static bool[,] Suggested = new bool[9,9];
		static int[,] Suggestion = new int[9,9];
		static int[,] Historique = new int[500,3];	//Historique de toutes les actions durant la partie
													//[x,0]=ligne [x,1]=colonne [x,2]=chiffre
		static int nbActions;					//nombre d'actions totales de l'utilisateur durant la partie
		static bool[,] Change = new bool[9, 9];			//Cases qui ont changé après résolution de l'impasse

		static void Main(string[] args)
		{
			//Initialisation de la fenêtre
			Console.Clear();
			Console.Title = "TP1 - Sudoku!";
			Console.SetWindowSize(120, 50);

			//intro
			Console.WriteLine("*********************TP1 - Sudoku!*********************\n");
			while (true)
			{
				AfficherMenu();
				if (GameStarted)
				{
					switch (EntreeChoix(1, 7))
					{
						case 1: //Continuer la partie
							Jouer();
							break;
						case 2: //Ecrire une solution
							GenererGrille(0, verrouUtilisateur);
							AfficherGrille();
							NettoyerGrille(verrouUtilisateur);
							Console.WriteLine("Appuyez sur une touche pour continuer...");
							Console.ReadLine();
							Jouer();
							break;
						case 3:	//reset la grille
							ResetGrille();
							Jouer();
							break;
						case 4: //Voir l'historique des coups joués
							VoirHistorique();
							Jouer();
							break;
						case 5: //Nouvelle partie, Jeu normal
							InitialiserGrille();
							modeFacile = false;
							Jouer();
							break;
						case 6: //Nouvelle partie, Jeu facile
							InitialiserGrille();
							modeFacile = true;
							Jouer();
							break;
						case 7: //Quitter
							Console.WriteLine("Merci d'avoir jouer à TP1 - Sudoku!");
							return;
					}
				}
				else
				{
					switch (EntreeChoix(1, 3))
					{
						case 1: //Jeu normal
							InitialiserGrille();
							modeFacile = false;
							Jouer();
							break;
						case 2: //Jeu facile
							InitialiserGrille();
							modeFacile = true;
							Jouer();
							break;
						case 3: //Quitter
							Console.WriteLine("Merci d'avoir jouer à TP1 - Sudoku!");
							return;
					}
				}
				//### Ajouter une exception ici
			}

		}


		/// <summary>
		/// Affiche un menu
		/// </summary>
		static void AfficherMenu()
		{
			if (GameStarted)
			{
				Console.WriteLine("1) Continuer la partie");
				Console.WriteLine("2) Écrire une solution à la partie en cours");
				Console.WriteLine("3) Reset la grille");
				Console.WriteLine("4) Voir l'historique des coups joués");
				Console.WriteLine("5) Démarrer une nouvelle partie");
				Console.WriteLine("6) Démarrer une nouvelle partie en mode facile");
				Console.WriteLine("7) Quitter");
			}
			else
			{
				Console.WriteLine("1) Démarrer une nouvelle partie");
				Console.WriteLine("2) Démarrer une nouvelle partie en mode facile");
				Console.WriteLine("3) Quitter");
			}
			Console.Write("Votre choix : ");
		}
		/// <summary>
		/// Lis un chiffre entré par l'utilisateur
		/// </summary>
		/// <param name="p_Min">Borne inférieur, inclusive, 1+</param>
		/// <param name="p_Max">Borne supérieure, inclusive</param>
		/// <returns>La valeur entrée</returns>
		static int EntreeChoix(int p_Min, int p_Max)
		{
			int chiffre;
			
			while (true)
			{
				chiffre = Convert.ToInt32(Console.ReadLine(),10);

				if (chiffre == 0)
				{
					//Entrée invalide
					Console.WriteLine("Vous devez entrer un chiffre entre {0} et {1}.", p_Min, p_Max);
				}
				else 
				{
					if ((chiffre >= p_Min) && (chiffre <= p_Max))
					{
						return chiffre;
					}
					else
					{
						//Chiffre hors limites
						Console.WriteLine("La valeur entrée doit être entre {0} et {1}.", p_Min, p_Max);
					}
					
				}

			}
		}
		/// <summary>
		/// Génère un grille de départ puis cacher des cases. 
		/// </summary>
		static void InitialiserGrille()
		{
			//Initialisation des tables
			for (int i = 0; i < 9; i++)
			{
				for (int j = 0; j < 9; j++)
				{
					Grille[i, j] = 0;
					Verrou[i, j] = false; //Dévérouiller toutes les cases. Nécessaire pour la génération de grille.
					verrouUtilisateur[i, j] = false;
				}
			}
			GenererGrille(0,Verrou);
			CacherCases();
			
			//verrouUtilisateur doit correspondre au Verrou en debut de partie
			for (int i = 0; i < 9; i++)
			{
				for (int j = 0; j < 9; j++)
				{
					verrouUtilisateur[i, j] = Verrou[i, j];
				}
			}

			//Remettre l'historique a 0
			for (int i = 0; i < 500; i++)
			{
				Historique[i, 0] = 0;
				Historique[i, 1] = 0;
				Historique[i, 2] = 0;
			}
			nbActions = 0;

		}
		/// <summary>
		/// Fonction récursive. Place des numeros dans la grille 
		/// pour obtenir une grille de sudoku valide.
		/// </summary>
		/// <param name="p_compteur">Itérateur pour indiquer la case où l'on est rendu. Mettre 
		/// a 0 pour commencer du début.</param>
		/// <param name="p_verrou">Tableau indiquant les cases à ne pas modifier</param>
		/// <returns>TRUE une valeur à été placée avec succès. FALSE si les posibilités sont épuisées sans succès.</returns>
		static bool GenererGrille(int p_compteur, bool[,] p_verrou)
		{
			//Condition de sortie
			if (p_compteur == 81)
			{
				return true;
			}

			int rangee = p_compteur / 9;
			int col = p_compteur % 9;
			int numChoisi;
			bool[] utilise = new bool[9];
			int essais = 0;

			do
			{
				while (true)
				{
					if (essais == 9) //Tout les nombre ont été essayé
					{
						if (!p_verrou[rangee, col])
						{
							Grille[rangee, col] = 0;
						}
						return false;
					}
					if (p_verrou[rangee, col])
					{
						//Si la case est vérouillée, on enregistre le nombre d'essai à 9. 
						//Tout les nombres ont été essayé. Le programme considère alors 
						//qu'il n'y a pas de modification possible.
					    essais = 9;
					    break;
					}
					else
					{
						do
						{
							numChoisi = randomG.Next(1, 10);
						} while (utilise[numChoisi - 1]);
						utilise[numChoisi - 1] = true; //vérouille le nombre selectionner pour qu'il ne soit pas réutilisé.
						essais++;
						if (Check(rangee, col, numChoisi) == 0)
						{
							Grille[rangee, col] = numChoisi;
							break;
						}
					}
				}
			} while (!GenererGrille(p_compteur + 1, p_verrou));
			return true;
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="position"></param>
		/// <returns></returns>
		static bool GenGrid(int position)
		{
			Random NumRand = new Random();

			int num;
			int line = position / 9;
			int col = position % 9;

			num = NumRand.Next(1, 10);
			for (int i = 0; i < 9; ++i)
			{
				/* Si le nombre est valide pour la grille, l'inscrire dans la
				 * grille et appeler GenGrille de nouveau en incrementant la 
				 * position. Sinon, essayer un autre chiffre. */
				if (Check(line, col, num) == 0)
				{
					if (position == 80)
					{
						Grille[line, col] = num;
						return true;
					}
					else
					{
						Grille[line, col] = num;
						if (GenGrid(position + 1) == true)
						{
							return true;
						}
						else
						{
							Grille[line, col] = 0;
						}
					}
				}
				/* Si le numero est 9, le mettre a 1, sinon l'incrementer pour le prochain essai */
				if (num == 9)
				{
					num = 1;
				}
				else
				{
					++num;
				}
			}
			return false;	//Tous les chiffres de 1 a 9 ont ete essayes sans succes.
		}

		/// <summary>
		/// Cache des cases au hasard dans la grille et vérouille le reste.
		/// </summary>
		static void CacherCases()
		{
			int casesCache = 0;
			int casesACacher;
			int line;
			int col;

			//On vérouille toutes les case, on va ensuite dévérouiller les cases où on cache des chiffres.
			for (int i = 0; i < 9; i++)
			{
				for (int j = 0; j < 9; j++)
				{
					Verrou[i, j] = true;
				}
			}

			for (int regionH = 0; regionH < 9; regionH = regionH + 3) //Bloc de 3 ligne
			{
				for (int regionV = 0; regionV < 9; regionV = regionV + 3) //Bloc de 3 colonnes
				{
					casesCache = 0;
					casesACacher = randomG.Next(4, 8);
					while (casesCache != casesACacher)
					{
						line = randomG.Next(0, 3) + regionH;
						col = randomG.Next(0, 3) + regionV;
						if (Verrou[line, col]) //Ignorer si la case est dévérouillée, donc déja cachée
						{
							Grille[line, col] = 0;
							casesCache++;
							Verrou[line, col] = false;
						}
					}
				}
			}
		}	
		/// <summary>
		/// Vérifie si un chiffre peut être placer dans une certaine case selon les règles du Sudoku
		/// </summary>
		/// <param name="p_Ligne">Ligne de la case</param>
		/// <param name="p_Col">Colonne de la case</param>
		/// <param name="p_Nombre">Valeur à vérifier</param>
		/// <returns>0 si possible, 1 si erreur dans la région, 2 si erreur dans la ligne, 3 si erreur dans la colonne</returns>
		static int Check(int p_Ligne, int p_Col, int p_Nombre)
		{
			//check la region 3x3
			int regionV = (p_Ligne - (p_Ligne % 3));
			int regionH = (p_Col - (p_Col % 3));
			for (int i = regionV; i < regionV + 3; i++)
			{
				for (int j = regionH; j < regionH + 3; j++)
				{
					if (Grille[i, j] == p_Nombre)
						return 1;
				}
			}

			//check ligne
			for (int i = 0; i < 9; i++)
			{
				if (Grille[p_Ligne, i] == p_Nombre)
					return 2;
			}

			//check colonne
			for (int i = 0; i < 9; i++)
			{
				if (Grille[i, p_Col] == p_Nombre)
					return 3;
			}

			//Réussi
			return 0;
		}
		/// <summary>
		/// Lit et enregistre les modification à la grille de jeu.
		/// </summary>
		/// <param name="facile">TRUE pour le mode facile</param>
		static void Jouer()
		{
			int line;
			int col;
			int valeurEntre;			
			char[] delimiterChars = { ' ', ',', '.', ':', '\t', ';' };
			string[] Valeurs;
			bool gridFull = false;	//flag qui indique que toutes les cases sont occupees, partie terminee

			GameStarted = true;	//partie en cours
			Console.WriteLine("\nVoici votre grille : \n");

			//Boucler jusqu'a ce que toutes les cases soient occupees
			while (!gridFull)
			{
				AfficherGrille();
				Console.WriteLine("Que voulez-vous modifier? (ligne, colonne, valeur) \"Enter\" pour retourner au menu, \"s\" pour suggerer une action, \"d\" pour défaire la dernière action");
				Valeurs = Console.ReadLine().Split(delimiterChars);

				//L'utilisateur a appuye sur "Enter", retourner au menu
				if (Valeurs[0] == "")
				{
					return;
				}
				////L'utilisateur desire retourner au menu
				//if((Valeurs[0] == "m")||(Valeurs[0] == "M"))
				//{
				//    return;
				//}

				//L'utilisateur veut defaire la derniere action
				else if((Valeurs[0] == "d") || (Valeurs[0] == "D"))
				{
					undo();
					continue;
				}
				//L'utilisateur desire une suggestion pour sa prochaine action
				else if ((Valeurs[0] == "s") || (Valeurs[0] == "S"))
				{
				    SuggestMove();
					continue;
				}

				line = Convert.ToInt32(Valeurs[0])-1;
				col = Convert.ToInt32(Valeurs[1])-1;
				valeurEntre = Convert.ToInt32(Valeurs[2]);

				//verifier si les chiffres entres sont corrects
				if ((line < 0) || (line > 8) || (col < 0) || (col > 8) || (valeurEntre < 0) || (valeurEntre > 9))
				{
					Console.ForegroundColor = ConsoleColor.Red;
					Console.WriteLine("\n-- Une des valeurs entrees est incorrecte\n");
					Console.ResetColor();
					continue;
				}

				EnregistrerNombre(line, col, valeurEntre);

				//Verifier si toutes les cases sont remplies
				gridFull = true;
				for (int i = 0; i < 9; ++i)
				{
					for (int j = 0; j < 9; ++j)
					{
						if (Grille[i, j] == 0)
						{
							gridFull = false;
						}
					}
				}
			}
			//Cases toutes occupees, fin de la partie
			AfficherGrille();
			Console.WriteLine("Bravo! Vous avez completé la grille!");
		}

		/// <summary>
		/// Vérifie si une case est disponible et y enregistre la valeur spécifiée.
		/// </summary>
		/// <param name="line">Ligne de la case</param>
		/// <param name="col">Colonne de la case</param>
		/// <param name="valeurEntre">Valeur à entrer</param>
		static void EnregistrerNombre(int line, int col, int valeurEntre)
		{
			int resultatCheck;
			int temp;

			//Si la case ne contient pas une variable de départ (verrouillée)
			if (!Verrou[line, col])
			{
				resultatCheck = Check(line, col, valeurEntre); //Verifier si la valeur est valide pour cette case

				//Retirer la valeur dans la case si l'utilisateur a entré comme valeur '0'
				if (valeurEntre == 0)
				{
					//enregistrer l'etat de la case dans l'historique avant de la modifier
					Historique[nbActions, 0] = line;
					Historique[nbActions, 1] = col;
					Historique[nbActions, 2] = Grille[line, col];
					++nbActions;

					Grille[line, col] = valeurEntre;
					verrouUtilisateur[line, col] = false;
				}
				//Si la valeur est valide pour cette case
				else if (resultatCheck == 0)
				{
					temp = Grille[line, col];

					//enregistrer l'etat de la case dans l'historique avant de la modifier
					Historique[nbActions, 0] = line;
					Historique[nbActions, 1] = col;
					Historique[nbActions, 2] = Grille[line, col];
					++nbActions;

					Grille[line, col] = valeurEntre;
					verrouUtilisateur[line, col] = true;

					if (modeFacile)
					{
						//Verifier s'il est possible de completer la grille avec la valeur entree
						//Si non, remettre l'ancienne valeur (temp), deverouiller la case, decrementer
						// le nombre de cases occupees et afficher une erreur
						if (!GenererGrille(0, verrouUtilisateur))
						{
							Grille[line, col] = temp;
							verrouUtilisateur[line, col] = false;
							AfficherErreur(5);

							//decrementer le nombre d'actions
							--nbActions;
						}

						//Enlever les valeurs ajoutees a Grille[,] par la fonction GenererGrille()
						//Toutes les cases non verrouillees sont remises a 0
						NettoyerGrille(verrouUtilisateur);
					}
				}
				//Valeur invalide pour la case (meme valeur sur la ligne, colonne ou region
				else
				{
					AfficherErreur(resultatCheck);
				}
			}
			else
			{
				AfficherErreur(4);	//Erreur, case verrouillée (case de départ)
			}
		}
		/// <summary>
		/// Affiche la grille de jeu
		/// </summary>
		static void AfficherGrille()
		{
			//En-tête
			Console.WriteLine("      1     2     3     4     5     6     7     8     9   ");
			Console.WriteLine("   -------------------------------------------------------");

			//Lignes
			for (int i = 0; i < 9; i++)
			{
				Console.Write("   |");
				for (int j = 0; j < 9; j++)
				{
					EcrireCaseLigneVide(i,j);					
				}
				Console.WriteLine();
				
				Console.Write(" {0} |", i + 1);
				for (int j = 0; j < 9; j++)
				{					
					if ((j == 2) || (j == 5)) //Case adjacente à un séparateur vertical
					{
						EcrireCaseAdj(i, j);
					}
					else //Autre case
					{
						EcrireCaseAutre(i, j);
					}
				}
				Console.WriteLine();

				Console.Write("   |");
				for (int j = 0; j < 9; j++)
				{
					EcrireCaseLigneVide(i, j);
				}
				Console.WriteLine();

				//Séparateur de bloc horizontal
				if ((i == 2) || (i == 5))
				{
					Console.WriteLine("   *******************************************************");
				}
				else
				{
					if (i == 8) //Dernière ligne
					{
						Console.WriteLine("   -------------------------------------------------------");
					}
					else
					{
						Console.WriteLine("   ------------------#-----------------#------------------");
					}
				}
			}
		}

		/// <summary>
		/// Afficher une partie de case sur une ligne sans chiffres
		/// </summary>
		/// <param name="i">le numéro de la ligne</param>
		/// <param name="j">le numéro de la colonne</param>
		private static void EcrireCaseLigneVide(int i, int j)
		{
			if (Change[i, j])
			{
				Console.ForegroundColor = ConsoleColor.Yellow;
				Console.Write("-----");
				Console.ResetColor();
				if ((j == 2) || (j == 5))
				{
					Console.Write("#");
				}
				else
				{
					Console.Write("|");
				}

			}
			else
			{
				if ((j == 2) || (j == 5))
				{
					Console.Write("     #");
				}
				else
				{
					Console.Write("     |");
				}
			}
		}
		/// <summary>
		/// Écrit une case adjacente à un séparateur vertical
		/// </summary>
		/// <param name="i">le numéro de la ligne</param>
		/// <param name="j">le numéro de la colonne</param>
		static void EcrireCaseAdj(int i, int j)
		{
			if (Grille[i, j] == 0) //Case non modifiée
			{
				if (Change[i, j]) //Case a changer pour resoudre une impasse
				{
					Console.ForegroundColor = ConsoleColor.Yellow;
					Console.Write("|   |");
					Console.ResetColor();
					Console.Write("#");
				}
				else  //Laisser la case blanche
				{
					Console.Write("     #", Grille[i, j]);
				}
			}
			else //Une valeur y est entrée
			{
				if (Verrou[i, j]) //Valeur de départ vérouillée
				{
					Console.ForegroundColor = ConsoleColor.Green;
					Console.Write(" [{0}] ", Grille[i, j]);
					Console.ResetColor();
					Console.Write("#");
				}
				else if (Suggested[i, j]) //Valeur suggérée (Rouge)
				{
					Console.ForegroundColor = ConsoleColor.Red;
					Console.Write(" ({0}) ", Suggestion[i, j]);
					//Console.Write(" ({0}) ", Grille[i, j]);
					Console.ResetColor();
					Console.Write("#");
				} 
				else if (Change[i, j])
				{
					Console.ForegroundColor = ConsoleColor.Yellow;
					Console.Write("| {0} |", Grille[i, j]);
					Console.ResetColor();
					Console.Write("#");
				}
				else //Valeur entrée par l'utilisateur
				{
					Console.ForegroundColor = ConsoleColor.Cyan;
					Console.Write("  {0}  ", Grille[i, j]);
					Console.ResetColor();
					Console.Write("#");
				}
			}
		}
		/// <summary>
		/// Écrit une case qui n'est pas adjacente à un séparateur
		/// </summary>
		/// <param name="i">le numéro de la ligne</param>
		/// <param name="j">le numéro de la colonne</param>
		static void EcrireCaseAutre(int i, int j)
		{
			if (Grille[i, j] == 0) //Case non modifiée
			{				
				if (Change[i, j]) //Case a changer pour resoudre une impasse
				{
					Console.ForegroundColor = ConsoleColor.Yellow;
					Console.Write("|   |");
					Console.ResetColor();
					Console.Write("|");
				}
				else //Laisser la case blanche
				{
					Console.Write("     |", Grille[i, j]);
				}
			}
			else //Une valeur y est entrée
			{
				if (Verrou[i, j]) //Valeur de départ vérouillée
				{
					Console.ForegroundColor = ConsoleColor.Green;
					Console.Write(" [{0}] ", Grille[i, j]);
					Console.ResetColor();
					Console.Write("|");
				}
				else if (Suggested[i, j]) //Valeur suggérée (Rouge)
				{
					Console.ForegroundColor = ConsoleColor.Red;
					Console.Write(" ({0}) ", Suggestion[i, j]);
					//Console.Write(" ({0}) ", Grille[i, j]);
					Console.ResetColor();
					Console.Write("|");
				}
				else if (Change[i, j]) //Case a changer pour resoudre une impasse
				{
					Console.ForegroundColor = ConsoleColor.Yellow;
					Console.Write("| {0} |", Grille[i, j]);
					Console.ResetColor();
					Console.Write("|");
				}
				else //Valeur entrée par l'utilisateur
				{
					Console.ForegroundColor = ConsoleColor.Cyan;
					Console.Write("  {0}  ", Grille[i, j]);
					Console.ResetColor();
					Console.Write("|");
				}
			}
		}
		/// <summary>
		/// Affiche des message d'erreurs au hasard
		/// </summary>
		/// <param name="type">Type d'erreur: 1. Région 2.Ligne 3.Colonne 4.Case vérouill 5.Impossible de completer</param>
		static void AfficherErreur(int type)
		{
			//Message en rouge
			Console.ForegroundColor = ConsoleColor.Red;

			if (type == 1) //Valeur déja dans la région
			{
				switch (randomG.Next(1, 5))
				{
					case 1:
						Console.WriteLine("\n-- Cette valeur est déja dans la région!\n");
						break;
					case 2:
						Console.WriteLine("\n-- Attention! Vous ne pouvez pas placer cette valeur ici! Vérifiez la région.\n");
						break;
					case 3:
						Console.WriteLine("\n-- Ce chiffre ne peut pas être placé ici! Il est déja dans la région.\n");
						break;
					case 4:
						Console.WriteLine("\n-- Ce chiffre est déja placé dans la région.\n");
						break;
				}
			}
			if (type == 2) //Valeur déja dans la ligne
			{
				switch (randomG.Next(1, 5))
				{
					case 1:
						Console.WriteLine("\n-- Vérifier la ligne, cette valeur y est déja.\n");
						break;
					case 2:
						Console.WriteLine("\n-- Ce chiffre est déja sur cette ligne.\n");
						break;
					case 3:
						Console.WriteLine("\n-- Attention, vous ne pouvez pas placer deux fois le même chiffre sur la même ligne.\n");
						break;
					case 4:
						Console.WriteLine("\n-- Vous ne pouvez pas écrire ce chiffre ici, il est déja dans la ligne.\n");
						break;
				}
			}
			if (type == 3) //Valeur déja dans la colonne
			{
				switch (randomG.Next(1, 5))
				{
					case 1:
						Console.WriteLine("\n-- Cette valeur est déja dans la colonne.\n");
						break;
					case 2:
						Console.WriteLine("\n-- Vous ne pouvez pas placer deux fois le même chiffre dans la même colonne.\n");
						break;
					case 3:
						Console.WriteLine("\n-- Ce chiffre ne peut pas être écrit ici, il est déja dans la colonne.\n");
						break;
					case 4:
						Console.WriteLine("\n-- Ce chiffre est déja placé dans la colonne.\n");
						break;
				}
			}
			if (type == 4) //Case vérouillée
			{
				switch (randomG.Next(1, 6))
				{
					case 1:
						Console.WriteLine("\n-- Vous ne pouvez pas modifier cette case!\n");
						break;
					case 2:
						Console.Write("\n-- Vous ne pouvez pas modifier les cases avec des ");
						Console.ForegroundColor = ConsoleColor.Green;
						Console.Write("[ ]");
						Console.ForegroundColor = ConsoleColor.Red;
						Console.WriteLine(".\n");
						break;
					case 3:
						Console.WriteLine("\n-- Cette case à été verouillée pour votre sécurité.\n");
						break;
					case 4:
						Console.WriteLine("\n-- Cette case est vérouillée!\n");
						break;
					case 5:
						Console.WriteLine("\n-- Vous ne pouvez pas modifier les cases de départ.\n");
						break;
					default:
						break;
				}
			} 
			if (type == 5) //Pas de solution possible (Mode facile)
			{
				switch (randomG.Next(1, 4))
				{
					case 1:
						Console.WriteLine("\n-- Aucune solution possible avec cette valeur!\n");
						break;
					case 2:
						Console.WriteLine("\n-- Cette valeur vous empecherais de completer la grille.\n");
						break;
					case 3:
						Console.WriteLine("\n-- Vous ne pouvez pas placer ce chiffre ici, il n'y a aucune solution possible.\n");
						break;
				}
			}

			Console.ResetColor();
		}

		static void undo()
		{
			if (nbActions == 0)
			{
				Console.ForegroundColor = ConsoleColor.Red;
				Console.WriteLine("\n-- Aucune action n'as encore été prise !\n");
				Console.ResetColor();
				return;
			}
			--nbActions;
			int line = Historique[nbActions,0];
			int col = Historique[nbActions,1];

			Grille[line, col] = Historique[nbActions, 2];
			if (Grille[line, col] == 0)
			{
				verrouUtilisateur[line, col] = false;
			}
			else
			{
				verrouUtilisateur[line, col] = true;
			}
		}

		/// <summary>
		/// Suggere une action a l'utilisateur
		/// </summary>
		static void SuggestMove()
		{
			int[] positions= new int[81];	//Positions dans la Grille qui sont vides
			int count=0;					//nombre de positions trouvees
			int randPosition;				//Position au hasard dans une des positions vides trouvees
			int caseVideChoisie;
			bool[,] verrouSugg = new bool[9, 9];
			
			//Obtenir les positions
			for (int i = 0; i < 9; ++i)
			{
				for (int j = 0; j < 9; ++j)
				{
					if (Grille[i, j] == 0)
					{
						positions[count] = i * 9 + j;
						++count;
					}
					//initialiser le verrou de suggestions
					verrouSugg[i, j] = verrouUtilisateur[i, j];
				}
			}

			while (true)
			{
				if(!GenererGrille(0, verrouSugg))
				{
					Console.ForegroundColor = ConsoleColor.Red;
					Console.WriteLine("\n-- Il est impossible de completer la grille avec les valeurs entrees presentement\n");
					Console.ResetColor();
					NettoyerGrille(verrouUtilisateur);
					ResoudreImpasse();
					return;
				}
				else
				{
					//AfficherGrille();
					//GenererGrille(0, verrouUtilisateur);
					randPosition = randomG.Next(0, count);		//position random dans positions[]
					caseVideChoisie = positions[randPosition];	//Case vide choisie
					Suggestion[caseVideChoisie / 9, caseVideChoisie % 9] = Grille[caseVideChoisie / 9, caseVideChoisie % 9];
					Suggested[caseVideChoisie / 9, caseVideChoisie % 9] = true;
					verrouSugg[caseVideChoisie / 9, caseVideChoisie % 9] = true;

					//On retire la valeur utilisée
					positions[randPosition] = positions[count-1];
					--count;

					NettoyerGrille(verrouSugg);
					AfficherGrille();

					if (count == 0) //Toute la grille est suggérée
					{
						Console.WriteLine("La grille est pleine!");
						Console.WriteLine("Appuyer sur une touche pour continuer...");
						Console.ReadLine();
						EnregistrerSug();
						return;
					}

					while (true)
					{
						Console.WriteLine("Suggerer une autre action ? (y/n)");
						string reponse = Console.ReadLine();
						if (reponse == "y")
						{
							break;
						}
						else if (reponse == "n")
						{
							EnregistrerSug();						
							return;
						}
						else
						{
							Console.WriteLine("Reponse incorrecte");
						}
					}
				}
			}
		}

		/// <summary>
		/// Enregistre les suggestion et initialise le tableau de suggestion
		/// </summary>
		static void EnregistrerSug()
		{
			while (true)
			{
				Console.WriteLine("Voulez-vous conserver les suggestions? (y/n)");
				string reponse = Console.ReadLine();
				if (reponse == "y")
				{
					for (int i = 0; i < 9; ++i)
					{
						for (int j = 0; j < 9; ++j)
						{
							if (Suggested[i, j])
							{
								//enregistrer l'etat de la case dans l'historique avant de la modifier
								Historique[nbActions, 0] = i;
								Historique[nbActions, 1] = j;
								Historique[nbActions, 2] = 0;
								++nbActions;

								verrouUtilisateur[i, j] = true;
								Grille[i, j] = Suggestion[i, j];
							}
						}
					}
					break;
				}
				else if (reponse == "n")
				{
					break;
				}
				else
				{
					Console.WriteLine("Reponse incorrecte");
				}
			}

			//Remettre toutes les cases de Suggested[] a false
			for (int i = 0; i < 9; ++i)
			{
				for (int j = 0; j < 9; ++j)
				{
					Suggested[i, j] = false;
				}
			}
		}
		
		static void ResoudreImpasse()
		{
			int[,] backupGrille = new int[9, 9];			//Backup de la grille
			bool[,] backupVerrou = new bool[9, 9];		//Backup de verrouUtilisateur
			//int[,] bufferResolution = new int[9, 9];	//Grille resolue
			string reponse;								//reponse aux questions
			int nbActionsDefaites = 0;					//Nombre de fois qu'on retourne en arriere
														//pour corriger l'impasse
			while (true)
			{
				Console.WriteLine("Voulez-vous retourner en arrière pour voir ce qui a causé l'impasse? (y/n)");
				reponse = Console.ReadLine();
				if (reponse == "n")
				{
					return;
				}
				else if(reponse == "y")
				{
					/* Faire un backup de la grille et du verrou utilisateur */
					for (int i = 0; i < 9; ++i)
					{
						for (int j = 0; j < 9; ++j)
						{
							backupGrille[i, j] = Grille[i, j];
							backupVerrou[i, j] = verrouUtilisateur[i, j];
						}
					}
					/* Aussi longtemps que la grille ne peut etre resolue avec les valeurs
					 * entrees, retourner une action en arriere et essayer encore */
					for (int i = 0; !GenererGrille(0, verrouUtilisateur); ++i)
					{
						int line = Historique[(nbActions-1) - i, 0];
						int col = Historique[(nbActions-1) - i, 1];

						if (Historique[(nbActions-1) - i, 2] == 0)
						{
							Grille[line, col] = Historique[(nbActions-1) - i, 2];
							verrouUtilisateur[line, col] = false;
						}
						else
						{
							Grille[line, col] = Historique[(nbActions-1) - i, 2];
							verrouUtilisateur[line, col] = true;
						}
						++nbActionsDefaites;
					}
					NettoyerGrille(verrouUtilisateur);
					//la Grille[,] peut etre resolue a partir d'ici


					//Determiner quelles cases doivent etre modifiees
					for (int i = 0; i < 9; ++i)
					{
						for (int j = 0; j < 9; ++j)
						{
							if (Grille[i, j] != backupGrille[i, j])
							{
								Change[i, j] = true;
							}
						}
					}

					//Afficher la grille avec les cases qui doivent etre modifiees
					AfficherGrille();

					while (true)
					{
						Console.WriteLine("Voici l'etat du tableau tel qu'il etait la derniere fois qu'il etait resolvable");
						Console.WriteLine("Voulez-vous revenir en appliquant ces modifications? (y/n)");
						Console.WriteLine("Les cases qui seront modifiées apparaissent en jaune");
						reponse = Console.ReadLine();
						if (reponse == "y")
						{
							//Decrementer le nombre d'actions du nombre de fois qu'on retourne en arriere
							nbActions -= nbActionsDefaites;
							for (int i = 0; i < 9; ++i)
							{
								for (int j = 0; j < 9; ++j)
								{
									Change[i, j] = false;
								}
							}
							return;
						}
						else if (reponse == "n")
						{
							for (int i = 0; i < 9; ++i)
							{
								for (int j = 0; j < 9; ++j)
								{
									Grille[i, j] = backupGrille[i, j];
									verrouUtilisateur[i, j] = backupVerrou[i, j];
									Change[i, j] = false;
								}
							}
							return;
						}
						else
						{
							Console.WriteLine("Reponse incorrecte");
						}
					}
				}
				else
				{
					Console.WriteLine("Reponse incorrecte");
				}
			}
		}

		/// <summary>
		/// Remet la grille telle qu'elle etait au debut de la partie
		/// </summary>
		static void ResetGrille()
		{
			nbActions = 0;
			for (int i = 0; i < 9; i++)
			{
				for (int j = 0; j < 9; j++)
				{
					if (!Verrou[i, j])
					{
						Grille[i, j] = 0;
						verrouUtilisateur[i, j] = false;
					}
				}
			}
		}

		/// <summary>
		/// Cache les case qui ne sont pas vérouillées.
		/// (Nettoyage après avoir vérifier une solution possible)
		/// </summary>
		/// <param name="VerrouUtilisateur">Tableau de verrouillage à utiliser</param>
		static void NettoyerGrille(bool[,] Verrou)
		{
			for (int i = 0; i < 9; i++)
			{
				for (int j = 0; j < 9; j++)
				{
					if (!(Verrou[i,j]))
					{
						//Si la case n'est pas vérouillée, effacer la case.
						Grille[i,j] = 0;
					}
				}
			}
		}

		static void VoirHistorique()
		{
			int[,] copyGrille = new int[9, 9];
			int ligneCase;	// ligne de la case apres modification
			int colonneCase; // colonne de la case apres modification

			/* Faire une copie de la grille */
			for (int i = 0; i < 9; ++i)
			{
				for (int j = 0; j < 9; ++j)
				{
					copyGrille[i, j] = Grille[i, j];
				}
			}

			for (int i = 0; i < nbActions; ++i)
			{
				ligneCase = Historique[(nbActions-1)-i,0];
				colonneCase = Historique[(nbActions-1)-i,1];
				Console.WriteLine("{0}) Ligne: {1} Colonne: {2} Valeur: {3}", i+1, Historique[(nbActions-1)-i,0]+1, Historique[(nbActions-1)-i,1]+1, copyGrille[ligneCase,colonneCase]);
				copyGrille[ligneCase, colonneCase] = Historique[(nbActions - 1) - i, 2];
			}
			Console.WriteLine("Appuyez sur une touche pour continuer");
			Console.ReadLine();
		}
	}
}