Easier way to make permutation diagrams?

I was tempted to use a matrix of nodes but my solution borrows from Jake's awesome code in Chinese checkers board using TikZ which effectively sets up a matrix of nodes manually.

This solution needs the tikz and the xstring packages.

The syntax

You use the code below as, for example

\drawpermutate{blue/{1/1,3/2}/left,red/{3/4,2/3}/right}

screenshot

\drawpermutate{green/{1/1,3/5,4/2}/left,orange/{3/4,2/3}/right}

enter image description here

You'll notice that each part of the argument has three parts to it:

  • colour: this should be self explanatory
  • {list of coordinates}: note that this needs to be grouped in its own {}, and each ordered pair (x,y) needs to be written as x/y
  • left or right: this can either be left or right depending on how you want the legend to be displayed. Actually, it can either be left or anything else- if it is not left, it'll go on the right (and underneath).

The code

Here's a complete MWE that you can play with; the code is fairly detailed in its comments- it basically uses a few loops to set up the nodes, and then do the appropriate thing at each node (circle, arrow, or *).

% arara: pdflatex
% !arara: indent: {overwrite: true}
\documentclass{standalone}

\usepackage{tikz}
\usepackage{xstring}

\newcommand{\drawpermutate}[1]{%
    \begin{tikzpicture}
        % setup the nodes
        \foreach [evaluate=\i as \x using int(\i-1)]\i in {0,1,...,8}
        {
            \foreach [evaluate=\j as \y using int(\j-1)] \j in {0,1,...,8}
            {
                %      \node at (\i,\j)[name=perm-\x-\y,label=\x-\y]{};
                \node at (\i,\j)[name=perm-\x-\y,]{};
            }
        }

        % draw numbers 1 to 6 in both x and y direction
        \foreach \i in {1,...,6}
        {
            \node at (perm-\i-0.center){\i};
            \node at (perm-0-\i.center){\i};
        }
        \node at (perm-7-7.center){$S$};

        % vertical lines
        \draw ([xshift=-5mm]perm-1--1.south west)--([xshift=-5mm]perm-1-7.north west);
        \draw ([xshift=-5mm]perm-7--1.south west)--([xshift=-5mm]perm-7-7.north west);
        % horizontal lines
        \draw ([yshift=5mm]perm--1-0.south west)--([yshift=5mm]perm-7-0.south east);
        \draw ([yshift=5mm]perm--1-6.south west)--([yshift=5mm]perm-7-6.south east);

        % draw user input
        \foreach \mystyle/\coords/\leftorright in {#1}
        {
            \foreach \x/\y in \coords
            {
                \node[circle,fill=\mystyle,draw=\mystyle] at (perm-\x-\y){};
                \IfStrEq{\leftorright}{left}{%
                    \node[\mystyle] at (perm--1-\y){*};
                    \node[\mystyle] at (perm-\x-7){$\downarrow$};
                }
                {% otherwise put it on the right
                    \node[\mystyle] at (perm-7-\y){$\leftarrow$};
                    \node[\mystyle] at (perm-\x--1){*};
                }
            }

        }

    \end{tikzpicture}
}

\begin{document}

%\drawpermutate{blue/{1/1,3/5,4/2}/left,red/{3/4,2/3}/right}

\drawpermutate{green/{1/1,3/5,4/2}/left,orange/{3/4,2/3}/right}

\end{document}

TikZ is not mandatory:-)

enter image description here

\documentclass{article}
\usepackage{color}
\makeatletter

\def\pdiag#1{{%
\setlength\unitlength{15pt}%
\begin{picture}(10,10)(-2,-2)%
\put(0,-2){\line(0,1){10}}%
\put(7,-2){\line(0,1){10}}%
\put(-2,-0){\line(1,0){10}}%
\put(-2,7){\line(1,0){10}}%
\put(7.2,7){S}%
\count@\z@
\@for\yc:=#1\do{%
\expandafter\ycdef\yc
\advance\count@\@ne
\put(-1,\count@){\the\count@}%
\put(\count@,-1){\the\count@}%
\put(\count@,\y){\if r\c\color{red}\else\if b\c\color{blue}\fi\fi
                  \circle*{.3}}%
\if r\c
\put(\count@,-2){\color{red}$\ast$}%
\put(7,\y){\color{red}$\leftarrow$}%
\fi
\if b\c
\put(-2,\y){\color{blue}$\ast$}%
\put(\count@,7.1){\color{blue}$\downarrow$}%
\fi
}%
\end{picture}}}

\def\ycdef#1#2{\def\y{#1}\def\c{#2}}
\begin{document}

\pdiag{6r,3r,2x,4r,1b,5b}


\end{document}

enter image description here

With the Asymptote module permdiag.asy typesetting of this nice little permutation game can be completely automated. Processing of the following file permdiag-test.asy

import permdiag;
permDiag pd=permDiag(new int[]{6,3,2,4,1,5});

for(int i=1;i<=pd.n;++i){
  shipout("diag"+format("%02d",i),pd.board(i));
}

with asy -f pdf permdiag-test.asy results in 6 files diag01.pdf..diag06.pdf, which were combined together with

\documentclass[a4paper]{article}
\usepackage{graphicx}
\begin{document}
\noindent%
\includegraphics[scale=1]{diag00.pdf}\quad 
\includegraphics[scale=1]{diag01.pdf}\quad 
\includegraphics[scale=1]{diag02.pdf}\\[10mm]
\noindent%
\includegraphics[scale=1]{diag03.pdf}\quad 
\includegraphics[scale=1]{diag04.pdf}\quad 
\includegraphics[scale=1]{diag05.pdf} 
\end{document}

And this is the main permdiag.asy, which handles the permDiag class:

struct permDiag{
  int n;
  int[] perm;
  int[] dotState;
  int[][] tperm;

  picture boardPic;
  guide dotShape;
  pen[] dotFill;

  void drawNumbers(){
    for(int i=0;i<n;++i){
      label(boardPic,string(i+1),(i,-1));
      label(boardPic,string(n-i),(-1,n-1-i));
    }
  }

  void drawArrows(){
    for(int i=0;i<n;++i){
      if(dotState[i]>0){
        if(dotState[i]==1){
          label(boardPic,"$\leftarrow$",(n+0.5,tperm[i][0]-1));
        }else{
          label(boardPic,"$\downarrow$",(tperm[i][2]-1,n+0.5));
        }  
      }  
    }
  } 

  void drawStars(){
    for(int i=0;i<n;++i){
      if(dotState[i]>0){
        if(dotState[i]==2){
          label(boardPic,"*",(-2,tperm[i][0]-1));
        }else{
          label(boardPic,"*",(tperm[i][3]-1,-2));
        }  
      }  
    }
  } 

  void drawLines(){
    draw(boardPic,(-2.5,-0.5)--(n+1.5,-0.5));
    draw(boardPic,(-2.5,n-0.5)--(n+1.5,n-0.5));
    draw(boardPic,(-0.5,-2.5)--(-0.5,n+1.5));
    draw(boardPic,(n-0.5,-2.5)--(n-0.5,n+1.5));
  }


  void play(int hstep){
    erase(boardPic);
    int tmp;
    int redblu=0;
    for(int i=0;i<n;++i){
      tperm[i][0]=perm[i];
      tperm[i][4]=i+1;      
    }
    dotState=array(n,0); 
    for(int i=0;i<hstep;++i){
      for(int j=n-1;j>i;--j){
        if(tperm[j][redblu]>tperm[j-1][redblu]){
          tmp=tperm[j][redblu];
          tperm[j][redblu]=tperm[j-1][redblu];
          tperm[j-1][redblu]=tmp;
          tmp=tperm[j][1-redblu];
          tperm[j][1-redblu]=tperm[j-1][1-redblu];
          tperm[j-1][1-redblu]=tmp;          
        }
      }
      dotState[i]=1+redblu;
      redblu=1-redblu;
    }
  }

  picture board(int move){
    assert(move>=0 && move<=n);
                      //  move number, 0 = initial state, 
                      //   odd - after red move
                      //  even - after blu move
    play(move);
    for(int i=0;i<n;++i){       
      filldraw(boardPic,shift(tperm[i][5]-1,tperm[i][0]-1)*dotShape,dotFill[dotState[i]]);
    }
    drawNumbers();
    drawArrows();
    drawStars();
    drawLines();
    label(boardPic,"$\mathcal{S}$",(n+0.5,n+0.5));
    return boardPic;
  }

  void operator init(int[] perm){
    assert(perm.length>0);
    this.n=perm.length;
    this.perm=copy(perm);
    this.dotState=array(n,0);
    this.dotShape=scale(0.382)*unitcircle;
    this.dotFill=new pen[]{lightyellow,red,blue};
    this.tperm=new int[n][6];
    boardPic.size(20*n);
  }
} 

//// Example:
//
//  import permdiag;
//  permDiag pd=permDiag(new int[]{6,3,2,4,1,5});
//
//  for(int i=0;i<=pd.n;++i){
//    shipout("diag"+format("%02d",i),pd.board(i));
//  }
//

Edit: Fixed picture scaling for different values of n. Example permdiag-test2.asy:

import permdiag;
permDiag pda=permDiag(new int[]{3,1,2,4});
permDiag pdb=permDiag(new int[]{9,19,17,1,8,13,18,11,10,4,5,7,2,3,15,16,12,6,20,14});
int i;
i=3;
shipout("diag-"+format("n%d-",pda.n)+format("%02d",i),pda.board(i));
i=12;
shipout("diag-"+format("n%d-",pdb.n)+format("%02d",i),pdb.board(i));

processed with asy -f pdf permdiag-test2.asy results in two pictures, diag-n4-03.pdf and diag-n20-12.pdf:

enter image description here

enter image description here