%%%
% GratteCiel
%%%
\def\filedateGratteCiel{2026/03/22}%
\def\fileversionGratteCiel{0.1b}%
\message{-- \filedateGratteCiel\space v\fileversionGratteCiel}%
%
\setKVdefault[GratteCiel]{CouleurSolution={},ListeIndices={},Creation=false,Taille=5,Graine={}}

\NewDocumentCommand\GratteCiel{om}{%
  \useKVdefault[GratteCiel]%
  \setKV[GratteCiel]{#1}%
  \ifboolKV[GratteCiel]{Creation}{%
    \ifemptyKV[GratteCiel]{Graine}{}{\PfCGraineAlea{\useKV[GratteCiel]{Graine}}}%
    \edef\PfCGCTaille{\useKV[GratteCiel]{Taille}}%
    \edef\PfCListeGCAMelanger{1}%
    \xintFor* ##1 in{\xintSeq{2}{\PfCGCTaille}}\do{%
      \edef\PfCListeGCAMelanger{\PfCListeGCAMelanger,##1}%
    }%
    \MelangeListe{\PfCListeGCAMelanger}{\PfCGCTaille}%
    \edef\PfCListeGCMel{\faa}%
%    Liste initiale : \PfCListeGCMel\par
%    \MelangeListe{1,2,3,4,5}{5}%
    \MelangeListe{\PfCListeGCAMelanger}{\PfCGCTaille}%
    \edef\PfCListeGCRotCol{\faa}%
%    Liste de rotation des colonnes pour la création des lignes : \PfCListeGCRotCol\par
%    \MelangeListe{1,2,3,4,5}{5}%
    \MelangeListe{\PfCListeGCAMelanger}{\PfCGCTaille}%
    \edef\PfCListeGCRotLig{\faa}%
%    Liste de rotation des lignes : \PfCListeGCRotLig\par
    \edef\PfCGraineRetenue{\PfCGraineAAfficher}%
    \BuildGratteCielCreation{\PfCListeGCMel}{\PfCListeGCRotCol}{\PfCListeGCRotLig}%
    \ifemptyKV[GratteCiel]{Graine}{}{\PfCGraineAlea{\PfCGraineRetenue}}%
  }{%
    \BuildGratteCiel{#2}%
  }%
}%

\NewDocumentCommand\BuildGratteCielCreation{mmm}{%
  \mplibforcehmode%
  \begin{mplibcode}
    boolean Solution;
    color CoulSol;
    \ifemptyKV[GratteCiel]{CouleurSolution}{Solution=false;}{Solution=true;CoulSol=\useKV[GratteCiel]{CouleurSolution};}
    pair A[][],Pind[];
    numeric M[][],Mrotcol[][],Mrotlig[][],Mfinal[][];
    path Case;
    Case=unitsquare scaled u;
    largeur=0;
    for p_=#1:
      M[0][largeur]=p_;
      largeur:=largeur+1;
    endfor;
    largeura:=largeur-1;
    % Tracé du terrain de jeu
    for k=0 upto largeura:
      for l=0 upto largeura:
        A[k][l]=u*(l,-k);
        trace Case shifted (A[k][l]-center Case);
%        label.lft(TEX("\tiny"&decimal(M[0][l])),A[k][l]);
      endfor;
    endfor;
%    dotlabel("",(0,0));  
    % On crée les lignes par rotations circulaires des colonnes
    klig:=0;  
    for p_=#2:
      for k=0 upto largeura:
        Mrotlig[klig][k]=M[0][(k+p_-1) mod largeur];
%        label.top(TEX("\tiny"&decimal(Mrotlig[klig][k])),A[klig][k]);
      endfor;
      klig:=klig+1;  
    endfor;
    % On permute les lignes :)
    kcol:=0;  
    for p_=#3:
      for k=0 upto largeura:
        Mfinal[kcol][k]=Mrotlig[p_-1][k];
        Num[kcol][k]=Mfinal[kcol][k];
        % label.rt(TEX("\tiny"&decimal(Mfinal[kcol][k])),A[kcol][k]);
        if Solution:
          drawoptions(withcolor CoulSol);
          label(TEX(decimal(Mfinal[kcol][k])),A[kcol][k]);
        fi;
      endfor;
      kcol:=kcol+1;
    endfor;
    string RetiensLAssemblage;
    RetiensLAssemblage="";
    for k=0 upto largeura:
      for l=0 upto largeura:
        RetiensLAssemblage:=RetiensLAssemblage&decimal(Num[k][l])&",";
      endfor;
    endfor;
    write RetiensLAssemblage to "PfCSolutionGratteCiel.tex";
    write EOF to "PfCSolutionGratteCiel.tex";
    k:=0;
%    for p_=#1:
%      Num[(k div largeur)][(k mod largeur)]=p_;
%      if Solution:drawoptions(withcolor CoulSol);label(TEX(decimal(p_)),A[(k div largeur)][(k mod largeur)]);fi;
%      k:=k+1;
%    endfor;
    drawoptions();
    nbmin:=0;
    %AffichageHaut 
    for l=0 upto largeura:
    nb:=1;
    mink:=Num[0][l];
    for k=1 upto largeura:
    if Num[k][l]>mink:
    nb:=nb+1;
    mink:=Num[k][l];
    fi;
    endfor;
    %label(TEX(decimal(nb)),A[0][l]+u*(0,1));
    drawarrow (A[0][l]+u*(0,0.85))--(A[0][l]+u*(0,0.55));
    nbmin:=nbmin+1;
    Min[nbmin]:=nb;
    Pind[nbmin]:=A[0][l]+u*(0,1);
    endfor;
%    % AffichageDroite
    for k=0 upto largeura:
    nb:=1;
    mink:=Num[k][largeura];
    for l=largeura-1 downto 0:
    if Num[k][l]>mink:
    nb:=nb+1;
    mink:=Num[k][l];
    fi;
    endfor;
    %label(TEX(decimal(nb)),A[k][largeura]+u*(1,0));
    drawarrow (A[k][largeura]+u*(0.85,0))--(A[k][largeura]+u*(0.55,0));
    nbmin:=nbmin+1;
    Min[nbmin]:=nb;
    Pind[nbmin]:=A[k][largeura]+u*(1,0);
    endfor;
%    % AffichageBas
    for l=largeura downto 0:
    nb:=1;
    mink:=Num[largeura][l];
    for k=largeura-1 downto 0:
    if Num[k][l]>mink:
    nb:=nb+1;
    mink:=Num[k][l];
    fi;
    endfor;
    % label(TEX(decimal(nb)),A[largeura][l]+u*(0,-1));
    drawarrow (A[largeura][l]+u*(0,-0.85))--(A[largeura][l]+u*(0,-0.55));
    nbmin:=nbmin+1;
    Min[nbmin]:=nb;
    Pind[nbmin]:=A[largeura][l]+u*(0,-1);
    endfor;
%    %AffichageGauche  
    for k=largeura downto 0:
    nb:=1;
    mink:=Num[k][0];
    for l=1 upto largeura:
    if Num[k][l]>mink:
    nb:=nb+1;
    mink:=Num[k][l];
    fi;
    endfor;
    %label(TEX(decimal(nb)),A[k][0]+u*(-1,0));
    drawarrow (A[k][0]+u*(-0.85,0))--(A[k][0]+u*(-0.55,0));
    nbmin:=nbmin+1;
    Min[nbmin]:=nb;
    Pind[nbmin]:=A[k][0]+u*(-1,0);
    endfor;
    % Pour le test d'apparition
    boolean Retour;
    vardef Test(expr nbt)=
      Retour:=false;
      op:=0;
      for l_=\useKV[GratteCiel]{ListeIndices}:
        if l_=nbt:
          op:=op+1;
        fi;
      endfor;
      if op>0:
        Retour:=true;
      fi;
    enddef;
%    %
    \ifemptyKV[GratteCiel]{ListeIndices}{%
      for k=1 upto nbmin:
        label(decimal(Min[k]),Pind[k]);
      endfor;
    }{
      for k=1 upto nbmin:
      Test(k);
      if Retour=false:
      label(decimal(Min[k]),Pind[k]);
      fi;
      endfor;
    }
  \end{mplibcode}%
}%

\NewDocumentCommand\BuildGratteCiel{m}{%
  \mplibforcehmode
  \begin{mplibcode}
    boolean Solution;
    color CoulSol;
    \ifemptyKV[GratteCiel]{CouleurSolution}{Solution=false;}{Solution=true;CoulSol=\useKV[GratteCiel]{CouleurSolution};}
    pair A[][],Pind[];
    path Case;
    Case=unitsquare scaled u;
    largeur=0;
    for p_=#1:
    largeur:=largeur+1;
    endfor;
    largeur:=sqrt(largeur);
    largeura:=largeur-1;
    for k=0 upto largeura:
      for l=0 upto largeura:
        A[k][l]=u*(l,-k);
        trace Case shifted (A[k][l]-center Case);
      endfor;
    endfor;
    k:=0;  
    for p_=#1:
      Num[(k div largeur)][(k mod largeur)]=p_;
      if Solution:drawoptions(withcolor CoulSol);label(TEX(decimal(p_)),A[(k div largeur)][(k mod largeur)]);fi;
      k:=k+1;
    endfor;
    drawoptions();
    nbmin:=0;
    %AffichageHaut 
    for l=0 upto largeura:
    nb:=1;
    mink:=Num[0][l];
    for k=1 upto largeura:
    if Num[k][l]>mink:
    nb:=nb+1;
    mink:=Num[k][l];
    fi;
    endfor;
    % label(TEX(decimal(nb)),A[0][l]+u*(0,1));
    drawarrow (A[0][l]+u*(0,0.85))--(A[0][l]+u*(0,0.55));
    nbmin:=nbmin+1;
    Min[nbmin]:=nb;
    Pind[nbmin]:=A[0][l]+u*(0,1);
    endfor;
    % AffichageDroite
    for k=0 upto largeura:
    nb:=1;
    mink:=Num[k][largeura];
    for l=largeura-1 downto 0:
    if Num[k][l]>mink:
    nb:=nb+1;
    mink:=Num[k][l];
    fi;
    endfor;
    % label(TEX(decimal(nb)),A[k][largeura]+u*(1,0));
    drawarrow (A[k][largeura]+u*(0.85,0))--(A[k][largeura]+u*(0.55,0));
    nbmin:=nbmin+1;
    Min[nbmin]:=nb;
    Pind[nbmin]:=A[k][largeura]+u*(1,0);
    endfor;
    % AffichageBas
    for l=largeura downto 0:
    nb:=1;
    mink:=Num[largeura][l];
    for k=largeura-1 downto 0:
    if Num[k][l]>mink:
    nb:=nb+1;
    mink:=Num[k][l];
    fi;
    endfor;
    % label(TEX(decimal(nb)),A[largeura][l]+u*(0,-1));
    drawarrow (A[largeura][l]+u*(0,-0.85))--(A[largeura][l]+u*(0,-0.55));
    nbmin:=nbmin+1;
    Min[nbmin]:=nb;
    Pind[nbmin]:=A[largeura][l]+u*(0,-1);
    endfor;
    %AffichageGauche  
    for k=largeura downto 0:
    nb:=1;
    mink:=Num[k][0];
    for l=1 upto largeura:
    if Num[k][l]>mink:
    nb:=nb+1;
    mink:=Num[k][l];
    fi;
    endfor;
    % label(TEX(decimal(nb)),A[k][0]+u*(-1,0));
    drawarrow (A[k][0]+u*(-0.85,0))--(A[k][0]+u*(-0.55,0));
    nbmin:=nbmin+1;
    Min[nbmin]:=nb;
    Pind[nbmin]:=A[k][0]+u*(-1,0);
    endfor;
    % Pour le test d'apparition
    boolean Retour;
    vardef Test(expr nbt)=
      Retour:=false;
      op:=0;
      for l_=\useKV[GratteCiel]{ListeIndices}:
        if l_=nbt:
          op:=op+1;
        fi;
      endfor;
      if op>0:
        Retour:=true;
      fi;
    enddef;
    %
    \ifemptyKV[GratteCiel]{ListeIndices}{%
      for k=1 upto nbmin:
        label(decimal(Min[k]),Pind[k]);
      endfor;
    }{
      for k=1 upto nbmin:
      Test(k);
      if Retour=false:
      label(decimal(Min[k]),Pind[k]);
      fi;
      endfor;
    }
  \end{mplibcode}
}%