# 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 ;