Triangle de Pascal

Le but de cet explication est de vous montrer comment réaliser une macro \trianglePascal qui permet d’afficher un triangle de Pascal dans un document LaTeX. Pour ceux qui ne s’en rappellent pas, le contenu d’une cellule est égal à la somme des deux cellules voisines de la rangée précédente, comme indiqué en couleur sur la figure ci-dessous [ en savoir plus…].

Ce code est tiré d’une discussion (début novembre 2004) sur  fctt. De façon simplifiée, voilà le but à atteindre :

\documentclass{article}
\begin{document}
\setBoxdim{8mm}{6mm}
\trianglePascal{10}
\end{document}

Créer le tableau

Nous souhaitons simplifier le problème en écrivant nous-même chaque ligne du tableau. Le triangle s’écrit donc

\Row1                    % En TeX, c'est équivalent à :
\Row11                   % \Row{1}{1}
\Row121                  % \Row{1}{2}{1}
\Row1331                 % \Row{1}{3}{3}{1}
\Row14641                % ...
\Row{1}{5}{10}{10}{5}{1} % Ici, les accolades sont obligatoires car
                         % certains arguments sont des nombres !

Commençons par créer la macro \Row qui permet d’afficher une rangée du tableau. Nous souhaitons que la macro prenne comme paramètre le contenu de chaque cellule de la rangée. Cette macro doit donc autoriser un nombre variable de paramètres. Comment TeX sait-il jusqu’où il doit lire les paramètres dans le fichier source ? Nous décidons qu’il s’arrêtera dès qu’une espace ou un retour ligne sont rencontrés.

\let\@nil\relax
\def\Row#1 {                 % Attention à l'espace avant l'accolade
                             % qui permet d'arrêter la lecture des
                             % arguments avec une espace/retour ligne
  \begingroup
    \par\centering           % Nouveau paragraphe centré
    \baselineskip=0pt        % sans espacement supplémentaire
    \nointerlineskip         %
    \printrow#1\@nil         % On imprime la ligne et on arrête la
                             % lecture d'arguments
    \par\vskip-\fboxrule     % Correction pour fusionner les lignes
                             % séparatrices horizontales
  \endgroup
}

La macro \Row a défini un environnement centré dans lequel se trouve le tableau et a ajusté les marges. La macro \printrow affiche donc les cellules du tableau proprement dit :

% N.B. : Ce code contient des explications qui entraînent un décalage
% dans le rendu. La version complète du code est correcte.
 
% Nous créons une macro prenant 2 arguments suivis de \@nil qui est en
% fait \relax (défini dans le premier bout de code, celui de
% \Row). Cette astuce permet de faire lire autant de paramètres que
% l'on souhaite à TeX, comme nous allons le voir.
 
\def\printrow#1#2\@nil{
  \fbox{                         % Crée la cellule
    \hbox to\Boxwd{              % et ajuste sa largeur
      \hss
      \vbox to\Boxht{            % et sa hauteur
        \vss#1\vss               % Le #1 utilise le token courant
      }                          % comme contenu de cellule
      \hss
    }
  }
  \hskip-\fboxrule               % Fusion des lignes séparatrices
                                 % verticales
  \def\@arg{#2}                  % \@arg contient le token suivant
  \ifx\empty\@arg
    \let\next\relax              % S'il est vide, la rangée est
                                 % terminée
  \else
    \let\next\printrow           % Sinon on définit \next comme étant
  \fi                            % la macro \printrow
  \expandafter\next\@arg\@nil    % et on change le cours du
                                 % développement de la macro en
                                 % demandant à TeX de développer
                                 % \printrow#2\@nil
}
 
% Nous avons donc le comportement suivant pour la 3e rangée (chaque
% ligne correspond à une étape du développement) :
 
% \Row121
% (code de \Row) \printrow1\@nil
% [1] \printrow2\@nil
% [2] \printrow1\relax\@nil
% [1]
 

La seule chose à faire pour l’utiliser est de définir la hauteur et la largeur de chaque cellule, par exemple en créant une macro \setBoxDim prenant leur hauteur et largeur :

\def\setBoxdim#1#2{%
  \def\Boxht{#2}%
  \def\Boxwd{#1}%
}

Automatiser la création complète du tableau

Nous souhaitons maintenant créer une nouvelle macro \trianglePascal prenant en argument le nombre de rangées du triangle de Pascal à afficher. Le code proposé utilise une bibliothèque comprenant une macro \FPPascal qui retourne les éléments d’une rangée donnée sous la forme [1,4,6,4,1] (ici : 5e ligne). Il faudra donc modifier le comportement de la macro \Row pour prendre en compte les crochets au début et à la fin et la macro \printrow pour prendre en compte la virgule séparant les éléments  :

\def\Row[#1]{%
  % début du code identique jusqu'à l'appel de \printrow :
  \printrow#1,\@nil
  % fin du code identique
}
 
\def\printrow#1,#2\@nil{%
  % code identique
}

Voici finalement le code de la macro \trianglePascal qui est limitée à 63 lignes (!) à cause de la bibliothèque de calcul utilisée :

\def\trianglePascal#1{%
  \ifnum#1>63%
    \typeout{ERROR: \string\trianglePascal{63} maximum}
  \else
    \multido{\i=0+1}{#1}{\FPpascal\foo{\i}\expandafter\Row\foo}
  \fi
}
Flattr