%%%
% Ronde infernale
%%%
\newcommand\TestNombrePremier[1]{%
  % #1 le nombre \`a tester
  \newcount\anp\newcount\bnp\newcount\cnp%
  \anp=#1\relax
  \bnp=2\relax
  \premier=-1\relax
  \whiledo{\anp > 1}{%
    \modulo{\the\anp}{\the\bnp}
    \ifnum\remainder=0\relax%
      \global\premier=\numexpr\premier+1\relax%
      \cnp=\numexpr\anp/\bnp\relax%
      \anp=\cnp\relax%
    \else%
      \bnp=\numexpr\bnp+1\relax%
    \fi%
  }%
}%

\newcommand\PfCRIListeDiviseur[1]{%#1 : nombre entier
  \newcount\anp\newcount\bnp%
  \anp=\fpeval{abs(#1)}%
  \bnp=2\relax%
  \xdef\PfCRIRetiensListeDiviseurs{}%
  \ifnum#1=0%
  \xdef\PfCRIRetiensListeDiviseurs{\fpeval{randint(2,5)},\fpeval{randint(6,9)}}%
  \else
  \whiledo{\bnp<\anp}{%
    \modulo{\the\anp}{\the\bnp}{}%
    \ifnum\remainder=0%
    \ifnum#1>0
    \xdef\PfCRIRetiensListeDiviseurs{\PfCRIRetiensListeDiviseurs \the\bnp,}%
    \else
    \xdef\PfCRIRetiensListeDiviseurs{\PfCRIRetiensListeDiviseurs \the\bnp,-\the\bnp,}%
    \fi
    \fi%
    \bnp=\numexpr\bnp+1%
  }%
  \ifnum#1>0
  \xdef\PfCRIRetiensListeDiviseurs{\PfCRIRetiensListeDiviseurs \the\anp,1}
  \else
  \xdef\PfCRIRetiensListeDiviseurs{\PfCRIRetiensListeDiviseurs \the\anp,-\the\anp}
  \fi
  \fi
}

\setKVdefault[RondeInfernale]{Solution=false,Relatifs=false,Etapes=4,Perso=false,Cles=false,Vide,Rayon=2.5cm,Rectangle=false}%
\defKV[RondeInfernale]{Graine=\PfCGraineAlea{#1}}
\defKV[RondeInfernale]{Cle=\setKV[RondeInfernale]{Cles}\setKV[RondeInfernale]{Vide=false}}%
\defKV[RondeInfernale]{ListeOperations=\setKV[RondeInfernale]{Perso}}%
\defKV[RondeInfernale]{ListeNombres=\setKV[RondeInfernale]{Perso}}%
%

\NewDocumentCommand\RondeInfernale{ }{%Mise en place pour les germanistes : le " est actif :(
  \begingroup
  \catcode`\"12
  \RondeInfernaleaux
}%

\NewDocumentCommand\RondeInfernaleaux{o}{%
  \endgroup
  \useKVdefault[RondeInfernale]%
  \setKV[RondeInfernale]{#1}%
  % Graine
%  \ifboolKV[RondeInfernale]{Graines}{\PfCGraineAlea{\useKV[RondeInfernale]{Graine}}}{}%
  % Nombre clé
  \ifboolKV[RondeInfernale]{Cles}{%
    \xdef\PfCRINombreCle{\useKV[RondeInfernale]{Cle}}%
  }{%
    \ifboolKV[RondeInfernale]{Relatifs}{%
      \xdef\PfCRIListeNegatifs{-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,1,2,3,4,5,6,7,8,9,10}
      \MelangeListe{\PfCRIListeNegatifs}{1}
      \readlist*\PfCRIListeCle{\faa}
      \xdef\PfCRINombreCle{\PfCRIListeCle[1]}%
    }{%
      \xdef\PfCRINombreCle{\fpeval{randint(2,9)}}%
    }%
  }%
  \ifboolKV[RondeInfernale]{Perso}{%
    \xdef\PfCRIRecupOperations{\useKV[RondeInfernale]{ListeOperations}}%
    \xdef\PfCRIRecupNombres{\useKV[RondeInfernale]{ListeNombres}}%
  }{%
    % On définit les éléments nécessaires
    \xdef\PfCRIListeToutesOperations{+,-,*,/}%
    \xdef\PfCRIListeOperationsSansDiv{+,-,*}%
    \xdef\PfCRIListeOperationsSansMul{+,-,/}%
    \xdef\PfCRIListeOperationsSimple{+,-}%
    \xdef\PfCRIRecupOperations{}%
    \xdef\PfCRIRecupNombres{}%
    \xdef\PfCRIRecupResultats{}%
    \xdef\PfCRINombreATester{\PfCRINombreCle}%
    \xdef\PfCRIRetiensNbEtapes{\useKV[RondeInfernale]{Etapes}}%
    \setsepchar{,}\ignoreemptyitems%
    % Liste des opérations jusqu'à l'étape n-1
    \xintFor* ##1 in{\xintSeq{1}{\fpeval{\useKV[RondeInfernale]{Etapes}-1}}}\do{%
      \TestNombrePremier{\PfCRINombreATester}\relax%
      \xintifboolexpr{\premier==0}{%
        % Définition des opérations
        \MelangeListe{\PfCRIListeOperationsSansDiv}{1}%
        \readlist*\PfCRIRetiensLoperation{\faa}%
        \xdef\PfCRIRecupOperations{\PfCRIRecupOperations \faa}%
        \xdef\PfCRIOperateur{\fpeval{randint(2,9)}}%
        \xdef\PfCRIRecupNombres{\PfCRIRecupNombres \PfCRIOperateur,}%
        \xdef\PfCRIResultat{\fpeval{\PfCRINombreATester\PfCRIRetiensLoperation[1]\PfCRIOperateur}}%
        \xdef\PfCRIRecupResultats{\PfCRIRecupResultats \PfCRIResultat,}%
        \xdef\PfCRINombreATester{\PfCRIResultat}%
      }{%
        \MelangeListe{\PfCRIListeToutesOperations}{1}%
        \readlist*\PfCRIRetiensLoperation{\faa}%
        \xdef\PfCRIRecupOperations{\PfCRIRecupOperations \faa}%
        \IfStrEq{\PfCRIRetiensLoperation[1]}{/}{%
          \PfCRIListeDiviseur{\PfCRINombreATester}%
          \MelangeListe{\PfCRIRetiensListeDiviseurs}{1}%
          \readlist*\PfCRIRetiensLeDiviseur{\faa}%
          \xdef\PfCRIOperateur{\PfCRIRetiensLeDiviseur[1]}%
        }{%
          \xdef\PfCRIOperateur{\fpeval{randint(2,9)}}%
        }%
        \xdef\PfCRIRecupNombres{\PfCRIRecupNombres \PfCRIOperateur,}%
        \xdef\PfCRIResultat{\fpeval{\PfCRINombreATester\PfCRIRetiensLoperation[1]\PfCRIOperateur}}%
        \xdef\PfCRIRecupResultats{\PfCRIRecupResultats \PfCRIResultat,}%
        \xdef\PfCRINombreATester{\PfCRIResultat}%
      }%
    }%
    % Dernière opération
    \xintifboolexpr{\fpeval{abs(\PfCRINombreATester)-abs(\PfCRINombreCle)}>0}{%
      \modulo{\PfCRINombreATester}{\PfCRINombreCle}{}%
      \xintifboolexpr{\remainder==0}{%
        \MelangeListe{\PfCRIListeOperationsSansMul}{1}%
        \xdef\PfCRIRecupOperations{\PfCRIRecupOperations \faa}%
        \ignoreemptyitems%
        \readlist*\PfCRIRetiensLoperation{\faa}%
        \IfStrEq{\PfCRIRetiensLoperation[1]}{/}{%
          \xdef\PfCRINombreATester{\fpeval{\PfCRINombreATester/\PfCRINombreCle}}%
        }{%
          \IfStrEq{\PfCRIRetiensLoperation[1]}{-}{%
            \xdef\PfCRINombreATester{\fpeval{\PfCRINombreATester-\PfCRINombreCle}}%
          }{%
            \xdef\PfCRINombreATester{\fpeval{\PfCRINombreCle-\PfCRINombreATester}}%
          }%
        }%
        \xdef\PfCRIRecupNombres{\PfCRIRecupNombres \PfCRINombreATester}%
      }{%
        \MelangeListe{\PfCRIListeOperationsSimple}{1}%
        \xdef\PfCRIRecupOperations{\PfCRIRecupOperations \faa}%
        \ignoreemptyitems%
        \readlist*\PfCRIRetiensLoperation{\faa}%
        \IfStrEq{\PfCRIRetiensLoperation[1]}{-}{%
          \xdef\PfCRINombreATester{\fpeval{\PfCRINombreATester-\PfCRINombreCle}}%
        }{%
          \xdef\PfCRINombreATester{\fpeval{\PfCRINombreCle-\PfCRINombreATester}}%
        }%
        \xdef\PfCRIRecupNombres{\PfCRIRecupNombres \PfCRINombreATester}%
      }%
    }{%
      \xintifboolexpr{\fpeval{abs(\PfCRINombreATester)-abs(\PfCRINombreCle)}==0}{%
        \xdef\PfCRIRecupOperations{\PfCRIRecupOperations *}%
        \ignoreemptyitems%
        \readlist*\PfCRIRIListeOperations{\PfCRIRecupOperations}%
        \xdef\PfCRIRecupNombres{\PfCRIRecupNombres 1}%
      }{%
        \xintifboolexpr{\PfCRINombreATester==0}{%
          \MelangeListe{\PfCRIListeOperationsSimple}{1}%
          \xdef\PfCRIRecupOperations{\PfCRIRecupOperations \faa}%
          \ignoreemptyitems%
          \readlist*\PfCRIRetiensLoperation{\faa}%
          \IfStrEq{\PfCRIRetiensLoperation[1]}{-}{%
            \xdef\PfCRINombreATester{\fpeval{\PfCRINombreATester-\PfCRINombreCle}}%
          }{%
            \xdef\PfCRINombreATester{\fpeval{\PfCRINombreCle-\PfCRINombreATester}}%
          }%
          \xdef\PfCRIRecupNombres{\PfCRIRecupNombres \PfCRINombreATester}%
        }{%
          \modulo{\PfCRINombreCle}{\PfCRINombreATester}{}%
          \xintifboolexpr{\remainder==0}{%-1
            \MelangeListe{\PfCRIListeToutesOperations}{1}%
            \xdef\PfCRIRecupOperations{\PfCRIRecupOperations \faa}%
            \readlist*\PfCRIRetiensLoperation{\faa}%
            \ignoreemptyitems%
            \readlist*\PfCRIRIListeOperations{\PfCRIRecupOperations}%
            \IfStrEq{\PfCRIRetiensLoperation[1]}{*}{%
              \xdef\PfCRINombreATester{\fpeval{\PfCRINombreCle/\PfCRINombreATester}}%
              \xdef\PfCRIRecupNombres{\PfCRIRecupNombres \PfCRINombreATester}%
            }{
              \IfStrEq{\PfCRIRetiensLoperation[1]}{-}{%
                \xdef\PfCRINombreATester{\fpeval{\PfCRINombreATester-\PfCRINombreCle}}%
              }{%
                \xdef\PfCRINombreATester{\fpeval{\PfCRINombreCle-\PfCRINombreATester}}%
              }%
              \xdef\PfCRIRecupNombres{\PfCRIRecupNombres \PfCRINombreATester}%
            }%
          }{%
            \MelangeListe{\PfCRIListeOperationsSimple}{1}%
            \xdef\PfCRIRecupOperations{\PfCRIRecupOperations \faa}%
            \ignoreemptyitems%
            \readlist*\PfCRIRIListeOperations{\PfCRIRecupOperations}%
            \IfStrEq{\PfCRIRIListeOperations[\PfCRIRetiensNbEtapes]}{-}{%
              \xdef\PfCRINombreATester{\fpeval{\PfCRINombreATester-\PfCRINombreCle}}%
            }{%
              \xdef\PfCRINombreATester{\fpeval{\PfCRINombreCle-\PfCRINombreATester}}%
            }%
            \xdef\PfCRIRecupNombres{\PfCRIRecupNombres \PfCRINombreATester}%
          }%
        }%
      }%
    }%
  }%
  \ignoreemptyitems%
  \readlist*\PfCRIRIOperations{\PfCRIRecupOperations}%
  \readlist*\PfCRIRINombres{\PfCRIRecupNombres}%
  \reademptyitems%
  % On prépare le dessin
  \xdef\PfCRINombresDessin{}%
  \xdef\PfCRIOperationsDessin{}%
  \foreachitem\compteur\in\PfCRIRINombres{%
    \xintifboolexpr{\PfCRIRINombres[\compteurcnt]<0}{%
      \xdef\PfCRINombresDessin{\PfCRINombresDessin "(\num{\PfCRIRINombres[\compteurcnt]})",}%
    }{%
      \xdef\PfCRINombresDessin{\PfCRINombresDessin "\num{\PfCRIRINombres[\compteurcnt]}",}%
    }%
  }%
  \foreachitem\compteur\in\PfCRIRIOperations{%
    \xdef\PfCRIOperationsDessin{\PfCRIOperationsDessin "\PfCRIRIOperations[\compteurcnt]",}%
  }%
  % On dessine
  \BuildRondeInfernale{\PfCRINombresDessin}{\PfCRIOperationsDessin}%
}%

\NewDocumentCommand\BuildRondeInfernale{m m}{%
  \ifluatex
  \mplibforcehmode
  \begin{mplibcode}
    boolean Vide,Rectangle,Perso;
    Vide=\useKV[RondeInfernale]{Vide};
    Rectangle=\useKV[RondeInfernale]{Rectangle};
    Perso=\useKV[RondeInfernale]{Perso};
    if Perso:
    string Depart;
    Depart=\useKV[RondeInfernale]{Cle};
    else:
    numeric Depart;
    Depart=\PfCRINombreCle;
    fi;

    numeric Rayon;
    Rayon=\useKV[RondeInfernale]{Rayon};

    string Nombre[];
    
    vardef Compte(text t)=%On compte le nb d'étapes et on retient les nombres
    nbcase:=0;
    for p_=t:
    nbcase:=nbcase+1;
    Nombre[nbcase]=p_;
    endfor;
    enddef;

    vardef AfficheRonde(text t)=%On fait l'affichage des opérations
    n:=0;
    for k=1 upto nbcase:
    fill cercles(rotation(A[k],O,0.5*(360/nbcase)),5mm) withcolor white;
    endfor;
    for p_=t:
    n:=n+1;
    if p_="*":
    label(TEX("$\times"&Nombre[n]&"$"),rotation(A[nbcase-n],O,0.5*(360/nbcase)));
    elseif p_="/":
    label(TEX("$\div"&Nombre[n]&"$"),rotation(A[nbcase-n],O,0.5*(360/nbcase)));
    else:
    label(TEX("$"&p_&Nombre[n]&"$"),rotation(A[nbcase-n],O,0.5*(360/nbcase)));
        fi;
    endfor;
    enddef;

    vardef AfficheRectangle(text t)=%On fait l'affichage des opérations
    n:=0;
    for p_=t:
    n:=n+1;
    if n=nbcase:
    if p_="*":
    label.bot(TEX("$\times"&Nombre[n]&"$"),1/2[A[n-1],A[0]]+u*(0,-1));
    elseif p_="/":
    label.bot(TEX("$\div"&Nombre[n]&"$"),1/2[A[n-1],A[0]]+u*(0,-1));
    else:
    label.bot(TEX("$"&p_&Nombre[n]&"$"),1/2[A[n-1],A[0]]+u*(0,-1));
    fi;
    else:
    if p_="*":
    label.top(TEX("$\times"&Nombre[n]&"$"),1/2[A[n-1],A[n]]);
    elseif p_="/":
    label.top(TEX("$\div"&Nombre[n]&"$"),1/2[A[n-1],A[n]]);
    else:
    label.top(TEX("$"&p_&Nombre[n]&"$"),1/2[A[n-1],A[n]]);
    fi;
    fi;
    endfor;
    enddef;

    vardef BaseRonde=
    pair O,A[];
    O=(0,0);
    path cc;
    cc=cercles(O,Rayon);
    A[0]=pointarc(cc,0);
    A[nbcase+1]=A[0];
    for k=1 upto nbcase:
    A[k]=rotation(A[0],O,k*(360/nbcase));
    endfor;
    for k=0 upto nbcase:
    drawarrow reverse(arccercle(A[k],A[k+1],O) cutbefore cercles(A[k],5mm) cutafter cercles(A[k+1],5mm)) withpen pencircle scaled 1.5;
    endfor;
    for k=0 upto nbcase:
    fill cercles(A[k],5mm) withcolor white;
    trace cercles(A[k],5mm) withpen pencircle scaled 1.5;
    endfor;
    enddef;

    vardef BoiteRectangle=
    save $;
    path $;
    $=u*(0.9,-0.5){dir 0}..{dir 90}(u*(1,-0.4))--(u*(1,0.4)){dir 90}..{dir180}(u*(0.9,0.5))--u*(-0.9,0.5){dir 180}..{dir-90}(u*(-1,0.4))--(u*(-1,-0.4)){dir-90}..{dir0}(u*(-0.9,-0.5))--cycle;
    $
    enddef;
    
    vardef BaseRectangle=
    pair O,A[];
    O=(0,0);
    A[0]=O;
    for k=1 upto nbcase:
    A[k]-A[k-1]=(Rayon+2cm,0);
    endfor;
    for k=0 upto nbcase-2:
    drawarrow (A[k]--A[k+1]) cutbefore (BoiteRectangle shifted A[k]) cutafter (BoiteRectangle shifted A[k+1]) withpen pencircle scaled 1.5;
    endfor;
    drawarrow (A[nbcase-1]--(A[nbcase-1]+u*(0,-1))--(A[0]+u*(0,-1))--A[0]) cutbefore (BoiteRectangle shifted A[nbcase-1]) cutafter (BoiteRectangle shifted A[0]) withpen pencircle scaled 1.5;
    for k=0 upto nbcase-1:
    trace (BoiteRectangle shifted A[k]) withpen pencircle scaled 1.5;
    endfor;
    enddef;
    
    Compte(#1);
    
    if Rectangle:
    BaseRectangle;
    AfficheRectangle(#2);
    else:
    BaseRonde;
    AfficheRonde(#2);
    fi;
    if Vide=false:
    if Perso:
    label(TEX("$"&Depart&"$"),A[0]);
    else:
    label(TEX("$"&decimal(Depart)&"$"),A[0]);
    fi;
    fi;
  \end{mplibcode}
  \else
  \begin{mpost}[mpsettings={%
      boolean Vide,Rectangle,Perso;Vide=\useKV[RondeInfernale]{Vide};Rectangle=\useKV[RondeInfernale]{Rectangle};Perso=\useKV[RondeInfernale]{Perso};if Perso:string Depart;Depart=\useKV[RondeInfernale]{Cle};else:numeric Depart;Depart=\PfCRINombreCle;fi;numeric Rayon;Rayon=\useKV[RondeInfernale]{Rayon};}]
    string Nombre[];
    
    vardef Compte(text t)=%On compte le nb d'étapes et on retient les nombres
    nbcase:=0;
    for p_=t:
    nbcase:=nbcase+1;
    Nombre[nbcase]=p_;
    endfor;
    enddef;

    vardef AfficheRonde(text t)=%On fait l'affichage des opérations
    n:=0;
    for k=1 upto nbcase:
    fill cercles(rotation(A[k],O,0.5*(360/nbcase)),5mm) withcolor white;
    endfor;
    for p_=t:
    n:=n+1;
    if p_="*":
    label(LATEX("$\times"&Nombre[n]&"$"),rotation(A[nbcase-n],O,0.5*(360/nbcase)));
    elseif p_="/":
    label(LATEX("$\div"&Nombre[n]&"$"),rotation(A[nbcase-n],O,0.5*(360/nbcase)));
    else:
    label(LATEX("$"&p_&Nombre[n]&"$"),rotation(A[nbcase-n],O,0.5*(360/nbcase)));
    fi;
    endfor;
    enddef;

    vardef AfficheRectangle(text t)=%On fait l'affichage des opérations
    n:=0;
    for p_=t:
    n:=n+1;
    if n=nbcase:
    if p_="*":
    label.bot(LATEX("$\times"&Nombre[n]&"$"),1/2[A[n-1],A[0]]+u*(0,-1));
    elseif p_="/":
    label.bot(LATEX("$\div"&Nombre[n]&"$"),1/2[A[n-1],A[0]]+u*(0,-1));
    else:
    label.bot(LATEX("$"&p_&Nombre[n]&"$"),1/2[A[n-1],A[0]]+u*(0,-1));
    fi;
    else:
    if p_="*":
    label.top(LATEX("$\times"&Nombre[n]&"$"),1/2[A[n-1],A[n]]);
    elseif p_="/":
    label.top(LATEX("$\div"&Nombre[n]&"$"),1/2[A[n-1],A[n]]);
    else:
    label.top(LATEX("$"&p_&Nombre[n]&"$"),1/2[A[n-1],A[n]]);
    fi;
    fi;
    endfor;
    enddef;

    vardef BaseRonde=
    pair O,A[];
    O=(0,0);
    path cc;
    cc=cercles(O,Rayon);
    A[0]=pointarc(cc,0);
    A[nbcase+1]=A[0];
    for k=1 upto nbcase:
    A[k]=rotation(A[0],O,k*(360/nbcase));
    endfor;
    for k=0 upto nbcase:
    drawarrow reverse(arccercle(A[k],A[k+1],O) cutbefore cercles(A[k],5mm) cutafter cercles(A[k+1],5mm)) withpen pencircle scaled 1.5;
    endfor;
    for k=0 upto nbcase:
    fill cercles(A[k],5mm) withcolor white;
    trace cercles(A[k],5mm) withpen pencircle scaled 1.5;
    endfor;
    enddef;

    vardef BoiteRectangle=
    save $;
    path $;
    $=u*(0.9,-0.5){dir 0}..{dir 90}(u*(1,-0.4))--(u*(1,0.4)){dir 90}..{dir180}(u*(0.9,0.5))--u*(-0.9,0.5){dir 180}..{dir-90}(u*(-1,0.4))--(u*(-1,-0.4)){dir-90}..{dir0}(u*(-0.9,-0.5))--cycle;
    $
    enddef;
    
    vardef BaseRectangle=
    pair O,A[];
    O=(0,0);
    A[0]=O;
    for k=1 upto nbcase:
    A[k]-A[k-1]=(Rayon+2cm,0);
    endfor;
    for k=0 upto nbcase-2:
    drawarrow (A[k]--A[k+1]) cutbefore (BoiteRectangle shifted A[k]) cutafter (BoiteRectangle shifted A[k+1]) withpen pencircle scaled 1.5;
    endfor;
    drawarrow (A[nbcase-1]--(A[nbcase-1]+u*(0,-1))--(A[0]+u*(0,-1))--A[0]) cutbefore (BoiteRectangle shifted A[nbcase-1]) cutafter (BoiteRectangle shifted A[0]) withpen pencircle scaled 1.5;
    for k=0 upto nbcase-1:
    trace (BoiteRectangle shifted A[k]) withpen pencircle scaled 1.5;
    endfor;
    enddef;
    
    Compte(#1);
    
    if Rectangle:
    BaseRectangle;
    AfficheRectangle(#2);
    else:
    BaseRonde;
    AfficheRonde(#2);
    fi;
    if Vide=false:
    if Perso:
    label(LATEX("$"&Depart&"$"),A[0]);
    else:
    label(LATEX("$"&decimal(Depart)&"$"),A[0]);
    fi;
    fi;
  \end{mpost}
  \fi
}%