mission1.adb

with Gada.Text_IO ;
with SudoGrille ;

procedure Mission1 is

   package G renames SudoGrille ;
   package Txt renames GAda.Text_IO ;

   type Un_Resultat is record
      Combien : Integer ;
      Valeur  : Integer ;
   end record ;

   -- Compte le nombre de valeurs possibles dans une case et renvoie l'une des valeurs possibles.
   function Compte_Possibles (Possibles : G.Les_Chiffres_Possibles) return Un_Resultat is
      Compteur : Integer := 0 ;
      Valeur : Integer ;
   begin
      -- Combien de possibles
      for NoVal in Possibles'Range loop
         if Possibles(NoVal) then
            Compteur := Compteur + 1 ;
            Valeur := NoVal ;
         end if ;
      end loop ;

      G.Failif(Compteur = 0, "Aucune possibilité dans cette case.") ;

      return (Compteur, Valeur) ;
   end Compte_Possibles ;

   procedure Tester_Compte is
      Result : Un_Resultat ;
   begin
      -- On doit voir Combien = 1  Valeur = 2
      Result := Compte_Possibles(G.Fabrique(G.Piece_Of_Cake)(2,1)) ;
      Txt.Put_Line("Compte PoC(2,1) :  Combien = " & Integer'Image(Result.Combien) & "  Valeur = " & Integer'Image(Result.Valeur)) ;

      -- On doit voir Combien = 9  Valeur = 9
      Result := Compte_Possibles(G.Fabrique(G.Piece_Of_Cake)(2,2)) ;
      Txt.Put_Line("Compte PoC(2,2) :  Combien = " & Integer'Image(Result.Combien) & "  Valeur = " & Integer'Image(Result.Valeur)) ;
   end Tester_Compte ;


   -- Calcule la somme du nombre de valeurs possibles de la grille.
   function Total_Possibles (Grille : G.Une_Grille) return Integer is
      Total : Integer := 0 ;
   begin
      for Ligne in Grille'Range(1) loop
         for Colonne in Grille'Range(2) loop
            Total := Total + Compte_Possibles(Grille(Ligne, Colonne)).Combien ;
         end loop ;
      end loop ;

      return Total ;
   end Total_Possibles ;

   -- Doit donner : 44 * 9 + 37 = 433
   procedure Tester_Total is
   begin
      Txt.Put_Line("Total (PoC) = " & Integer'Image(Total_Possibles(G.Fabrique(G.Piece_Of_Cake)))) ;
   end Tester_Total ;

   --
   -- Propage une case déterminée dans les trois maisons.
   --
   procedure Propage(Grille : in out G.Une_Grille ; Ligne, Colonne : Integer ; Valeur : Integer) is
      DepLigne : Integer ;
      DepCol : Integer ;
   begin
      -- Propage sur toute la ligne. Attention à ne pas interdire la valeur dans la case d'où l'on vient.
      for NCol in Grille'Range(2) loop
         if NCol /= Colonne then
               Grille(Ligne, NCol)(Valeur) := False ;
            end if ;
      end loop ;

      -- Propage sur toute la colonne. Attention à ne pas interdire la valeur dans la case d'où l'on vient.
      for NLig in Grille'Range(1) loop
         if NLig /= Ligne then
            Grille(NLig, Colonne)(Valeur) := False ;
         end if ;
      end loop ;

      DepLigne := 3 * ((Ligne - 1) / 3) + 1 ;
      DepCol   := 3 * ((Colonne - 1) / 3) + 1 ;

      -- Propage sur tout la sous-grille. Attention à ne pas interdire la valeur dans la case d'où l'on vient.
      for NLig in DepLigne..DepLigne+2 loop
         for NCol in DepCol..DepCol+2 loop
            if NLig /= Ligne or NCol /= Colonne then
               Grille(NLig, NCol)(Valeur) := False ;
            end if ;
         end loop ;
      end loop ;

   end Propage ;


   -- Résous une grille de Sudoku
   procedure Resous(Grille : in out G.Une_Grille) is
      Ancien_Compte, Nouveau_Compte : Integer ;
      Seul : Un_Resultat ;
   begin
      Ancien_Compte := Integer'Last ;
      Nouveau_Compte := Total_Possibles(Grille) ;

      while Nouveau_Compte > G.Taille * G.Taille and Nouveau_Compte < Ancien_Compte loop
         G.Affiche(Grille) ;
         G.Attend_Entree ;

         -- Propage les contraintes liées aux cases déterminées.
         for Ligne in Grille'Range(1) loop
            for Colonne in Grille'Range(2) loop
               Seul := Compte_Possibles(Grille(Ligne, Colonne)) ;
               if Seul.Combien = 1 then
                  Propage(Grille, Ligne, Colonne, Seul.Valeur) ;
               end if ;
            end loop ;
         end loop ;

         Ancien_Compte := Nouveau_Compte ;
         Nouveau_Compte := Total_Possibles(Grille) ;

      end loop ;

      G.Affiche(Grille) ;
   end Resous ;

   Sudok : G.Une_Grille := G.Fabrique(G.Piece_Of_Cake) ;
--   Sudok : G.Une_Grille := G.Fabrique(G.Difficile) ;
begin

   G.Affiche(Sudok) ;
   Tester_Compte ;
   Tester_Total ;

   --Propage(Sudok,1,1,9) ;
   --G.Affiche(Sudok) ;

   Resous(Sudok) ;

end Mission1 ;