%!PS-Adobe-2.0
%%Creator: Peter Salvi
%%Title: Langton's Ant
%%BoundingBox: 0 0 595 842
%%EndComments

% Parameters
/pixelSize 5 def
/iterations 11000 def
/seeds [ ] def          % array of arrays, e.g. [ [ 0 0 ] [ 1 0 ] [ 1 1 ] ]

% Main code follows

% Initial setup (A4 size: 595x842 points)
/width 595 pixelSize idiv def
/height 842 pixelSize idiv def
/antX width 2 idiv def
/antY height 2 idiv def
/antDir 0 def                   % 0 = Left, 1 = Down, 2 = Right, 3 = Up
/board width height mul array def

% Call as `<x> <y> boardSet' where (0,0) is the center
/boardSet {
    height 2 idiv add width mul add
    width 2 idiv add
    board exch 0 put
} def

/setupBoard {
    % Clear the array initially
    0 1 board length 1 sub { board exch 1 put } for
    seeds { aload pop boardSet } forall
} def

% Inverts the color at (antX, antY) and leaves the original on the stack.
/invertColor {
    antX antY width mul add     % index
    dup board exch get          % index original
    dup 1 exch sub board        % index original inverted board
    4 1 roll exch 4 1 roll      % original board index inverted
    put                         % original
} def

/leftTurn [ 1 2 3 0 ] def
/rightTurn [ 3 0 1 2 ] def
/turn {
    1 eq { rightTurn } { leftTurn } ifelse
    antDir get /antDir exch def
} def

/deltaX [ -1 0 1 0 ] def
/deltaY [ 0 -1 0 1 ] def
/moveForward {
    % Toroidal arrangement
    /antX antX deltaX antDir get add width add width mod def
    /antY antY deltaY antDir get add height add height mod def
} def

% Writes the pixel at (antX,antY) with the color defined in board
/writePixel {
    newpath
    antX pixelSize mul antY pixelSize mul moveto
    0 pixelSize 2 div sub dup rmoveto
    pixelSize 0 rlineto
    0 pixelSize rlineto
    0 pixelSize sub 0 rlineto
    closepath
    board antX antY width mul add get setgray fill
} def

/drawBoard {
    height 1 sub -1 0 {
        /antY exch def
        0 1 width 1 sub {
            /antX exch def
            writePixel
        } for
    } for
} def

% Main loop
setupBoard
iterations { invertColor turn moveForward } repeat
drawBoard