%%%
% Arbre de calculs
%%%
\def\filedateArbreC{2025/12/21}%
\def\fileversionArbreC{0.1a}%
\message{-- \filedateArbreC\space v\fileversionArbreC}%
\newtoks\toklistearbre%
\newtoks\toklistearbrefractions%
\newtoks\toklistearbreexpressions%

\def\UpdatetoksArbreCalcul#1\nil{\IfDecimal{#1}{\addtotok\toklistearbre{#1,}}{\addtotok\toklistearbre{"#1",}}}%
\def\UpdatetoksArbreFractions#1\nil{\addtotok\toklistearbrefractions{"#1",}}%
\def\UpdatetoksArbreExpressions#1\nil{\addtotok\toklistearbreexpressions{"#1",}}%

\setKVdefault[ArbreCalcul]{Correction=false,Couleur=LightSteelBlue,Substitue=7,Litteral=false,Largeur=8mm,LargeurC=8mm,Ecart=1.5cm,Hauteur=10mm,Lettre="x",CouleurDepart=LightGreen,Nombres={},Expressions={},Etape=infinity,Fraction={}}%

\makeatletter
\NewDocumentCommand\ArbreCalcul{om}{%
  \useKVdefault[ArbreCalcul]%
  \setKV[ArbreCalcul]{#1}%
  \toklistearbre{}%
  \toklistearbrefractions{}%
  \toklistearbreexpressions{}%
  \infixtoRPN{#2}%
  \setsepchar{ }\ignoreemptyitems%
  \readlist*\PfC@ListeNombres{\RPN}%
  \reademptyitems%
  \foreachitem\compteur\in\PfC@ListeNombres{\expandafter\UpdatetoksArbreCalcul\compteur\nil}%
  \ifemptyKV[ArbreCalcul]{Fraction}{%
    \ifboolKV[ArbreCalcul]{Litteral}{
      \edef\Foo{\useKV[ArbreCalcul]{Nombres}}%
      \setsepchar{,}\ignoreemptyitems%
      \readlist*\PfC@ListeFractions{\Foo}%
      \reademptyitems%
      \foreachitem\compteur\in\PfC@ListeFractions{\expandafter\UpdatetoksArbreFractions\compteur\nil}%
      \edef\Foo{\useKV[ArbreCalcul]{Expressions}}%
      \setsepchar{,}\ignoreemptyitems%
      \readlist*\PfC@ListeExpressions{\Foo}%
      \reademptyitems%
      \foreachitem\compteur\in\PfC@ListeExpressions{\expandafter\UpdatetoksArbreExpressions\compteur\nil}%
      \PfC@BuildArbreCalculLitteral{\the\toklistearbre}{\the\toklistearbrefractions}{\the\toklistearbreexpressions}%
    }{%
      \PfC@BuildArbreCalcul{\the\toklistearbre}%
    }%
  }{%
    \edef\Foo{\useKV[ArbreCalcul]{Nombres}}%
    \setsepchar{,}\ignoreemptyitems%
    \readlist*\PfC@ListeFractions{\Foo}%
    \reademptyitems%
    \foreachitem\compteur\in\PfC@ListeFractions{\expandafter\UpdatetoksArbreFractions\compteur\nil}%
    \PfC@BuildArbreCalculFraction{\the\toklistearbre}{\the\toklistearbrefractions}%
  }%
}%

\NewDocumentCommand\PfC@BuildArbreCalcul{m}{%
  \mplibforcehmode%
  \begin{mplibcode}
    boolean Correction,Litteral,Allume[];
    Correction=\useKV[ArbreCalcul]{Correction};
    Litteral=\useKV[ArbreCalcul]{Litteral};
    
    NombreSubstitue=\useKV[ArbreCalcul]{Substitue};

    etape=0;
    Etape=\useKV[ArbreCalcul]{Etape};
      
    color Evidence,CoulDepart;
    Evidence=\useKV[ArbreCalcul]{Couleur};
    CoulDepart=\useKV[ArbreCalcul]{CouleurDepart};
      
    pair pointprec;
    
    path base[];
    base1=unitsquare xscaled \useKV[ArbreCalcul]{Largeur} yscaled 5mm;
    base2=fullcircle scaled 5mm;
    base3=unitsquare xscaled \useKV[ArbreCalcul]{LargeurC} yscaled 5mm;
    
    vardef BlocCalcul(expr Ba,Bb,op,cha,chb)=%
      % Ba point gauche
      % Bb point droite
      % op opération à afficher
      etape:=etape+1;
      save $;
      picture $;
      path cc[];
      pair Bc;
      Bc=(0.5*(xpart(Ba)+xpart(Bb)),if ypart(Bb)<ypart(Ba):ypart(Bb) else:ypart(Ba) fi -0.75u);
      pointprec:=Bc+u*(0,-0.75);
      $=image(
        if Allume[numeropoint-1]=true:
          cc1=base3 shifted (Ba-center base3);
        else:
          cc1=base1 shifted (Ba-center base1);
        fi;
        if Allume[numeropoint]=true:
          cc2=base3 shifted (Bb-center base3);
        else:
          cc2=base1 shifted (Bb-center base1);
        fi;
        %
        cc3=(fullcircle scaled 5mm) shifted Bc;
        cc4=base3 shifted (pointprec-center base3);
        if op="mul":
          label(TEX("$\times$"),Bc);
          ValeurPile[numeropoint-1]:=cha*chb;
        elseif op="add":
          label(TEX("$+$"),Bc);
          ValeurPile[numeropoint-1]:=cha+chb;
        elseif op="sub":
          label(TEX("$\_$"),Bc);
          ValeurPile[numeropoint-1]:=cha-chb;
        elseif op="div":
          label(TEX("$\div$"),Bc);
          ValeurPile[numeropoint-1]:=cha/chb;
        fi;
        if Correction:
          if etape<Etape+1:
            fill cc4 withcolor Evidence;
            label(TEX("\num{"&decimal(ValeurPile[numeropoint-1])&"}"),pointprec);
          fi;
        fi;
        for l=1 upto 4:
          trace cc[l];
        endfor;
        draw (Ba--Bc) cutbefore cc1 cutafter cc3;
        draw (Bb--Bc) cutbefore cc2 cutafter cc3;
        draw (Bc--pointprec) cutbefore cc3 cutafter cc4;
        );
      $
    enddef;

    numeric Valeurs[],Valeursa[],ValeurPile[];
      
    string Operations[];

    numeric numeropoint;
    numeropoint=0;
      
    vardef RecupDonnees(text t)=
      n:=0;
      for p_=t:
        n:=n+1;
        if numeric p_:
          Valeurs[n]=p_;
          Operations[n]="";
        else:
          Valeurs[n]=infinity;
          Operations[n]=p_;
        fi;
      endfor;
      n:=n+1;
      Operations[n]="stop";
      nbtotal=n;
      for k=1 upto nbtotal:
        ValeurPile[k]=0;
      endfor;
    enddef;

    pair A[];
    ecart=\useKV[ArbreCalcul]{Ecart};

    RecupDonnees(#1);
    
    A[0]=(0,0);
    k=0;
    nbetape:=0;
    
    for p_=#1:
      k:=k+1;
      if numeric p_:
        numeropoint:=numeropoint+1;
        if unknown A[numeropoint]:
          A[numeropoint]-A[numeropoint-1]=ecart*(1,0);Allume[numeropoint]=false;
        else:
          A[numeropoint]:=A[numeropoint-1]+ecart*(1,0); Allume[numeropoint]:=false;
        fi;
        if Valeurs[k]=0:Valeursa[k]:=NombreSubstitue else: Valeursa[k]=Valeurs[k] fi;
        if Operations[k+1]="neg":
          if Valeurs[k]=0:
            fill (base1 shifted (A[numeropoint]-center base1)) withcolor CoulDepart;
            if Litteral:
              label(TEX("$\useKV[ArbreCalcul]{Lettre}$"),A[numeropoint]);
            else:
              label(TEX("\num{"&decimal(-Valeursa[k])&"}"),A[numeropoint]);
            fi;
          else:
            label(TEX("\num{"&decimal(-Valeursa[k])&"}"),A[numeropoint]);
          fi;      
          ValeurPile[numeropoint]:=-Valeursa[k];
        else:
          if Valeurs[k]=0:
            fill (base1 shifted (A[numeropoint]-center base1)) withcolor CoulDepart;
            if Litteral:
              label(TEX("$\useKV[ArbreCalcul]{Lettre}$"),A[numeropoint]);
            else:
              label(TEX("\num{"&decimal(Valeursa[k])&"}"),A[numeropoint]);
            fi;
          else:
            label(TEX("\num{"&decimal(Valeursa[k])&"}"),A[numeropoint]);
          fi;
          ValeurPile[numeropoint]:=Valeursa[k];
        fi;      
      elseif string p_:
        if p_<>"neg":
          trace BlocCalcul(A[numeropoint-1],A[numeropoint],Operations[k],ValeurPile[numeropoint-1],ValeurPile[numeropoint]);
          A[numeropoint-1]:=pointprec;
          Allume[numeropoint-1]:=true;
          numeropoint:=numeropoint-1;
        fi;
      fi;
    endfor;
  \end{mplibcode}
}%

\NewDocumentCommand\PfC@BuildArbreCalculFraction{mm}{%
  \mplibforcehmode%
  \begin{mplibcode}
    boolean Correction,Allume[];
    Correction=\useKV[ArbreCalcul]{Correction};
      
    string Fraction;
    Fraction=\useKV[ArbreCalcul]{Fraction};
      
    color Evidence,CoulDepart;
    Evidence=\useKV[ArbreCalcul]{Couleur};
    CoulDepart=\useKV[ArbreCalcul]{CouleurDepart};
    
    pair pointprec;

    path base[];
    base1=unitsquare xscaled \useKV[ArbreCalcul]{Largeur} yscaled \useKV[ArbreCalcul]{Hauteur};
    base2=fullcircle scaled 5mm;
    base3=unitsquare xscaled \useKV[ArbreCalcul]{LargeurC} yscaled \useKV[ArbreCalcul]{Hauteur};
      
    vardef BlocCalcul(expr Ba,Bb,op,cha,chb)=%
      % Ba point gauche
      % Bb point droite
      % op opération à afficher
      etape:=etape+1;
      save $;
      picture $;
      path cc[];
      pair Bc;
      Bc=(0.5*(xpart(Ba)+xpart(Bb)),if ypart(Bb)<ypart(Ba):ypart(Bb) else:ypart(Ba) fi -0.75u);
      pointprec:=Bc+u*(0,-1.25);
      $=image(
        if Allume[numeropoint-1]=true:
          cc1=base3 shifted (Ba-center base3);
        else:
          cc1=base1 shifted (Ba-center base1);
        fi;
        if Allume[numeropoint]=true:
          cc2=base3 shifted (Bb-center base3);
        else:
          cc2=base1 shifted (Bb-center base1);
        fi;
        cc3=(fullcircle scaled 5mm) shifted Bc;
        cc4=base3 shifted (pointprec-center base3);
      if op="mul":
      label(TEX("$\times$\MulFraction[Seul][3]{"&cha&"}{"&chb&"}[\ResultatMul]"),Bc);
      ValeurPile[numeropoint-1]:="\ResultatMul";
      elseif op="add":
      label(TEX("$+$\AddFraction[Seul][3]{"&cha&"}{"&chb&"}[\ResultatAdd]"),Bc);
      ValeurPile[numeropoint-1]:="\ResultatAdd";
      elseif op="sub":
      label(TEX("$\_$\SousFraction[Seul][3]{"&cha&"}{"&chb&"}[\ResultatSous]"),Bc);
      ValeurPile[numeropoint-1]:="\ResultatSous";
      elseif op="div":
      label(TEX("$\div$\DivFraction[Seul][3]{"&cha&"}{"&chb&"}[\ResultatDiv]"),Bc);
      ValeurPile[numeropoint-1]:="\ResultatDiv";
      fi;
      if Correction:
      if etape<Etape+1:
      fill cc4 withcolor Evidence;
      label(TEX("$\displaystyle\tofrac{"&ValeurPile[numeropoint-1]&"}$"),pointprec);
      fi;
      fi;
      for l=1 upto 4:
      trace cc[l];
      endfor;
      draw (Ba--Bc) cutbefore cc1 cutafter cc3;
      draw (Bb--Bc) cutbefore cc2 cutafter cc3;
      draw (Bc--pointprec) cutbefore cc3 cutafter cc4;
      );
      $
      enddef;

      numeric Valeurs[];
      string Valeursa[],Operations[],ValeurPile[];

      numeric numeropoint;
      numeropoint=0;

      vardef RecupDonnees(text t)=
        n:=0;
        for p_=t:
          n:=n+1;
          if numeric p_:
            Valeurs[n]=p_;
            Operations[n]="";
          else:
            Valeurs[n]=infinity;
            Operations[n]=p_;
          fi;
        endfor;
        n:=n+1;
        Operations[n]="stop";
        nbtotal=n;
        for k=1 upto nbtotal:
          ValeurPile[k]="0";
        endfor;
      enddef;

      vardef RecupFractions(text t)=
        n:=0;
        for p_=t:
          n:=n+1;
          Valeursa[n]=p_;
        endfor;
      enddef;

      pair A[];
      ecart=\useKV[ArbreCalcul]{Ecart};

      RecupDonnees(#1);
      RecupFractions(#2);

      etape=0;
      Etape=\useKV[ArbreCalcul]{Etape};
      
      A[0]=(0,0);
      k=0;
      nbetape:=0;
      
      for p_=#1:
      k:=k+1;
      if numeric p_:
      numeropoint:=numeropoint+1;
      if unknown A[numeropoint]:A[numeropoint]-A[numeropoint-1]=ecart*(1,0);Allume[numeropoint]=false; else:
      A[numeropoint]:=A[numeropoint-1]+ecart*(1,0); Allume[numeropoint]:=false;
      fi;
      if Valeurs[k]=0:Valeursa[Valeurs[k]]:=\useKV[ArbreCalcul]{Fraction} fi;
      if Operations[k+1]="neg":
      if Valeurs[k]=0:fill (base1 shifted (A[numeropoint]-center base1)) withcolor CoulDepart;
      label(TEX("$\displaystyle\tofrac{"&-Valeursa[Valeurs[k]]&"}$"),A[numeropoint]);
      else:
      label(TEX("$\displaystyle\tofrac{"&-Valeursa[Valeurs[k]]&"}$"),A[numeropoint]);
      fi;      
      ValeurPile[numeropoint]:=decimal(-Valeursa[Valeurs[k]]);
      else:
      if Valeurs[k]=0:fill (base1 shifted (A[numeropoint]-center base1)) withcolor CoulDepart;
      label(TEX("$\displaystyle\tofrac{"&Valeursa[Valeurs[k]]&"}$"),A[numeropoint]);
        else:
      label(TEX("$\displaystyle\tofrac{"&Valeursa[Valeurs[k]]&"}$"),A[numeropoint]);
      fi;
      ValeurPile[numeropoint]:=Valeursa[Valeurs[k]];
      fi;      
      elseif string p_:
      if p_<>"neg":
      trace BlocCalcul(A[numeropoint-1],A[numeropoint],Operations[k],ValeurPile[numeropoint-1],ValeurPile[numeropoint]);
      A[numeropoint-1]:=pointprec;
      Allume[numeropoint-1]:=true;
      numeropoint:=numeropoint-1;
      fi;
      fi;
    endfor;
  \end{mplibcode}
}%

\NewDocumentCommand\PfC@BuildArbreCalculLitteral{mmm}{%
  \mplibforcehmode%
  \begin{mplibcode}
    boolean Correction,Allume[];
    Correction=\useKV[ArbreCalcul]{Correction};
      
    color Evidence,CoulDepart;
    Evidence=\useKV[ArbreCalcul]{Couleur};
    CoulDepart=\useKV[ArbreCalcul]{CouleurDepart};
    
    pair pointprec;
    
    path base[];
    base1=unitsquare xscaled \useKV[ArbreCalcul]{Largeur} yscaled \useKV[ArbreCalcul]{Hauteur};
    base2=fullcircle scaled 5mm;
    base3=unitsquare xscaled \useKV[ArbreCalcul]{LargeurC} yscaled \useKV[ArbreCalcul]{Hauteur};
      
    vardef BlocCalcul(expr Ba,Bb,op,cha,chb)=%
      % Ba point gauche
      % Bb point droite
      % op opération à afficher
      etape:=etape+1;
      save $;
      picture $;
      path cc[];
      pair Bc;
      Bc=(0.5*(xpart(Ba)+xpart(Bb)),if ypart(Bb)<ypart(Ba):ypart(Bb) else:ypart(Ba) fi -0.75u);
      pointprec:=Bc+u*(0,-1.25);
      $=image(
      if Allume[numeropoint-1]=true:
      cc1=base3 shifted (Ba-center base3);
      else:
      cc1=base1 shifted (Ba-center base1);
      fi;
      if Allume[numeropoint]=true:
      cc2=base3 shifted (Bb-center base3);
      else:
      cc2=base1 shifted (Bb-center base1);
      fi;
      cc3=(fullcircle scaled 5mm) shifted Bc;
      cc4=base3 shifted (pointprec-center base3);
      if op="mul":
      label(TEX("$\times$"),Bc);
      ValeurPile[numeropoint-1]:="";
      elseif op="add":
      label(TEX("$+$"),Bc);
      ValeurPile[numeropoint-1]:="";
      elseif op="sub":
      label(TEX("$\_$"),Bc);
      ValeurPile[numeropoint-1]:="";
      elseif op="div":
      label(TEX("$\div$"),Bc);
      ValeurPile[numeropoint-1]:="";
      fi;
      if Correction:
      if etape<Etape+1:
      fill cc4 withcolor Evidence;
      label(TEX("$"&Valeursc[etape]&"$"),pointprec);
      fi;
      fi;
      for l=1 upto 4:
      trace cc[l];
      endfor;
      draw (Ba--Bc) cutbefore cc1 cutafter cc3;
      draw (Bb--Bc) cutbefore cc2 cutafter cc3;
      draw (Bc--pointprec) cutbefore cc3 cutafter cc4;
      );
      $
      enddef;

      numeric Valeurs[];
      string Valeursa[],Valeursc[],Operations[],ValeurPile[];

      numeric numeropoint;
      numeropoint=0;

      vardef RecupDonnees(text t)=
        n:=0;
        for p_=t:
          n:=n+1;
          if numeric p_:
            Valeurs[n]=p_;
            Operations[n]="";
          else:
            Valeurs[n]=infinity;
            Operations[n]=p_;
          fi;
        endfor;
        n:=n+1;
        Operations[n]="stop";
        nbtotal=n;
        for k=1 upto nbtotal:
          ValeurPile[k]="0";
        endfor;
      enddef;

      vardef RecupFractions(text t)=
        n:=0;
        for p_=t:
          n:=n+1;
          Valeursa[n]=p_;
        endfor;
      enddef;

      vardef RecupCorrections(text t)=
        n:=0;
        for p_=t:
          n:=n+1;
          Valeursc[n]=p_;
        endfor;
      enddef;

      pair A[];
      ecart=\useKV[ArbreCalcul]{Ecart};

      RecupDonnees(#1);
      RecupFractions(#2);
      RecupCorrections(#3);

      etape=0;
      Etape=\useKV[ArbreCalcul]{Etape};
      
      A[0]=(0,0);
      k=0;
      nbetape:=0;
      
      for p_=#1:
      k:=k+1;
      if numeric p_:
      numeropoint:=numeropoint+1;
      if unknown A[numeropoint]:A[numeropoint]-A[numeropoint-1]=ecart*(1,0);Allume[numeropoint]=false; else:
      A[numeropoint]:=A[numeropoint-1]+ecart*(1,0); Allume[numeropoint]:=false;
      fi;
      if Valeurs[k]=0:Valeursa[Valeurs[k]]:=\useKV[ArbreCalcul]{Lettre} fi;
      if Operations[k+1]="neg":
      if Valeurs[k]=0:fill (base1 shifted (A[numeropoint]-center base1)) withcolor CoulDepart;
      label(TEX("$"&-Valeursa[Valeurs[k]]&"$"),A[numeropoint]);
      else:
      label(TEX("$"&-Valeursa[Valeurs[k]]&"$"),A[numeropoint]);
      fi;      
      ValeurPile[numeropoint]:=decimal(-Valeursa[Valeurs[k]]);
      else:
      if Valeurs[k]=0:fill (base1 shifted (A[numeropoint]-center base1)) withcolor CoulDepart;
      label(TEX("$"&Valeursa[Valeurs[k]]&"$"),A[numeropoint]);
        else:
      label(TEX("$"&Valeursa[Valeurs[k]]&"$"),A[numeropoint]);
      fi;
      ValeurPile[numeropoint]:=Valeursa[Valeurs[k]];
      fi;      
      elseif string p_:
      if p_<>"neg":
      trace BlocCalcul(A[numeropoint-1],A[numeropoint],Operations[k],ValeurPile[numeropoint-1],ValeurPile[numeropoint]);
      A[numeropoint-1]:=pointprec;
      Allume[numeropoint-1]:=true;
      numeropoint:=numeropoint-1;
      fi;
      fi;
    endfor;
  \end{mplibcode}
}%
\makeatother