# mission2.adb

    with Support ;
    with SudoGrille ;
    with Gada.Text_IO ;

    procedure Mission2 is

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

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

       type Un_Resultat_Double is record
          Combien : Integer ;
          Ligne   : Integer ;
          Colonne : Integer ;
       end record ;

       function Possibles_Lignes (Grille : G.Une_Grille ; Ligne : Integer ; Val : Integer) return Un_Resultat is
          NPossibles : Integer := 0 ;
          NoCol : Integer ;
       begin
          for Col in Grille'Range(2) loop
             if Grille(Ligne, Col)(Val) then
                NPossibles := NPossibles + 1 ;
                NoCol := Col ;
             end if ;
          end loop ;
          return (NPossibles, NoCol) ;
       end Possibles_Lignes ;

       procedure Tester_Possibles_Lignes is
          Res : Un_Resultat ;
       begin
          Res := Possibles_Lignes(G.Fabrique(G.Difficile), 1, 5) ;
          Txt.Put_Line("Possibles Ligne 1  Val 5 :  Combien = " & Integer'Image(Res.Combien) &
                       "  Valeur = " & Integer'Image(Res.Valeur)) ;
       end Tester_Possibles_Lignes ;

       function Possibles_Colonnes (Grille : G.Une_Grille ; Col : Integer ; Val : Integer) return Un_Resultat is
          NPossibles : Integer := 0 ;
          NoLigne : Integer ;
       begin
          for Ligne in Grille'Range(1) loop
             if Grille(Ligne, Col)(Val) then
                NPossibles := NPossibles + 1 ;
                NoLigne := Ligne ;
             end if ;
          end loop ;
          return (NPossibles, NoLigne) ;
       end Possibles_Colonnes ;

       function Possibles_Sous_Mat (Grille : G.Une_Grille ; Ligne, Col : Integer ; Val : Integer) return Un_Resultat_Double is
          NPossibles : Integer := 0 ;
          NoLigne, NoCol : Integer ;
          DepLigne : Integer := 3 * ((Ligne - 1) / 3) + 1 ;
          DepCol   : Integer := 3 * ((Col - 1) / 3) + 1 ;

       begin
          for NLigne in DepLigne..DepLigne+2 loop
             for NCol in DepCol..DepCol+2 loop
                if Grille(NLigne, NCol)(Val) then
                   NPossibles := NPossibles + 1 ;
                   NoLigne := NLigne ;
                   NoCol   := NCol ;
                end if ;
             end loop ;
          end loop ;
          return (NPossibles, NoLigne, NoCol) ;
       end Possibles_Sous_Mat ;

       procedure Examiner_Ligne(Grille : in out G.Une_Grille ; Ligne : Integer) is
          Res : Un_Resultat ;
       begin
          for Val in 1..G.Taille loop
             Res := Possibles_Lignes(Grille, Ligne, Val) ;
             if Res.Combien = 1 then
                Grille(Ligne, Res.Valeur) := G.Fixe(Val) ;
             end if ;
          end loop ;
       end Examiner_Ligne ;

       procedure Examiner_Col(Grille : in out G.Une_Grille ; Col : Integer) is
          Res : Un_Resultat ;
       begin
          for Val in 1..G.Taille loop
             Res := Possibles_Colonnes(Grille, Col, Val) ;
             if Res.Combien = 1 then
                Grille(Res.Valeur, Col) := G.Fixe(Val) ;
             end if ;
          end loop ;
       end Examiner_Col ;

       procedure Examiner_Sous_Mat(Grille : in out G.Une_Grille ; Ligne, Col : Integer) is
          Res : Un_Resultat_Double ;
       begin
          for Val in 1..G.Taille loop
             Res := Possibles_Sous_Mat(Grille, Ligne, Col, Val) ;
             if Res.Combien = 1 then
                Grille(Res.Ligne, Res.Colonne) := G.Fixe(Val) ;
             end if ;
          end loop ;
       end Examiner_Sous_Mat ;

       -- Cette procedure est equivalente a celle demandee en partie 1,
       -- mais l'algorithme est different ici et ne correspond pas a ce qu'on vous demandait en partie 1.
       procedure Resous (LaGrille : in out SudoGrille.Une_Grille) is
          Continue : Boolean := True ;
       begin

          while Continue loop
             -- Ne modifiez pas la ligne suivante. Elle propage les contraintes comme dans la partie 1.
             Support.Propage_Tout(LaGrille, Continue) ;

             --G.Attend_Entree ;
             --G.Affiche(LaGrille) ;

             -- Lignes
             for Lig in LaGrille'Range(1) loop
                Examiner_Ligne(LaGrille, Lig) ;
             end loop ;

             -- Colonnes
             for Col in LaGrille'Range(2) loop
                Examiner_Col(LaGrille, Col) ;
             end loop ;

             -- Sous matrices
             for Lig in 1..G.SousTaille loop
                for Col in 1..G.SousTaille loop
                   Examiner_Sous_Mat(LaGrille, Lig * G.SousTaille, Col * G.SousTaille) ;
                end loop ;
             end loop ;

          end loop ;

          SudoGrille.Affiche(LaGrille) ;

       end Resous ;

       -- Declarer ici la variable Sudok
       --Soduk : G.Une_Grille := G.Fabrique(G.Moyen) ;
       Soduk : G.Une_Grille := G.Fabrique(G.Difficile) ;
    begin

       G.Affiche(Soduk) ;

       Resous(Soduk) ;

       --Tester_Possibles_Lignes ;

    end Mission2 ;