Life in PostScript

I participated in the IPSC last week, and was intrigued by one of the problems, figuring out what a Postscript program does. From this, I learned that Postscript is a real language, not just for graphics. So I spent a bit of time learning it, and wanted to do something interesting in it. So of course, the obvious choice was John Conway's game of life. So, oddly enough, you can, at least in theory, send this small file to a postscript printer, and it will run the game and print the output. I do not recomend this, since it will take a rather long time, since most printers have fairly slow processors, so you will tie it up for several minutes/hours/millenia. (But if you really want to, you at least want to scale it down a bit, changing the numgens variable in the beginning. Or, if you feel like wasing paper, you can change the call to "Disp" at the end into a call to DispPage, which will print out each generation on a new page.)

Of course, you can also view this in GSView, GhostView, or any other postscript viewer. This is the recommended method, since it doesn't waste much, except CPU time. Or you can be lazy and just look at the screenshots I've taken.

And if you feel driven to learn postscript yourself, you can view a handy postscript tutorial (PDF - how ironic!) and learn the secrets of Postscript yourself.


Code (download)

%!PS

% Copyright (C) 2003  Evan Danaher
% 
% This program is free software; you can redistribute it and/or
% modify it under the terms of the GNU General Public License
% as published by the Free Software Foundation; either version 2
% of the License, or (at your option) any later version.
% 
% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
% GNU General Public License for more details.
% 
% You should have received a copy of the GNU General Public License
% along with this program; if not, write to the Free Software
% Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.


/Times-Roman findfont 12 scalefont setfont

/size 70 def
/cellsize 5 def
/numgens 1000 def

/get2 {
   3 1 roll get exch get 
} def

/put2 {
   /val exch def /c exch def /r exch def /tmpar2 exch def
   /tmpar tmpar2 r get def 
   tmpar c val put
   tmpar2 r tmpar put
} def

/ar
size {
   0 size 1 sub { dup } repeat
   size array astore
} repeat
size array astore 
def

/ar2
size {
   0 size 1 sub { dup } repeat
   size array astore
} repeat
size array astore 
def

/diffs
size {
   0 size 1 sub { dup } repeat
   size array astore
} repeat
size array astore 
def

/arcpy {
   /dest exch def /src exch def
   0 1 size 1 sub {
      /i exch def
      0 1 size 1 sub {
         /j exch def
         dest i j src i j get2 put2
      } for
   } for
} def

/disp {
   0 1 size 1 sub { /i exch def
      0 1 size 1 sub { /j exch def
         diffs i j get2 dup 0 ne {
            1 eq { 1 } { 0 } ifelse
            setgray
            newpath
            100 cellsize j mul add 500 cellsize i mul sub moveto 
            0 cellsize rlineto
            cellsize 0 rlineto
            0 cellsize neg rlineto
            closepath
            fill
         } { pop } ifelse
      } for
   } for
} def

/dispPage {
   0 1 size 1 sub { /i exch def
      0 1 size 1 sub { /j exch def
         ar i j get2 dup 0 ne {
            0
            setgray
            newpath
            100 cellsize j mul add 500 cellsize i mul sub moveto 
            0 cellsize rlineto
            cellsize 0 rlineto
            0 cellsize neg rlineto
            closepath
            fill
         } { pop } ifelse
      } for
   } for
   showpage
} def

/Wrap {
   size add size mod
} def

/DoGen {
   /diffs
   size {
      0 size 1 sub { dup } repeat
      size array astore
   } repeat
   size array astore 
   def
   0 1 size 1 sub {
      /i exch def
      0 1 size 1 sub {
         /j exch def
         /neighbors 0 def
         -1 1 1  {
            /di exch def
            -1 1 1 {
               /dj exch def
               di 0 ne dj 0 ne or {
                  ar i di add Wrap j dj add Wrap get2 1 eq {
                     /neighbors neighbors 1 add def
                  } if
               } if
            } for
         } for
         ar i j get2 1 eq 
         { neighbors 2 eq neighbors 3 eq or not {ar2 i j 0 put2 diffs i j 1 put2} if }
         { neighbors 3 eq  {ar2 i j 1 put2 diffs i j -1 put2} if }
         ifelse
      } for
   } for
   ar2 ar arcpy
} def

/setcell {
   1 3 copy ar 4 1 roll put2 diffs 4 1 roll put2
} def

size size mul 4 div cvi {
   rand size mod rand size mod setcell
} repeat

ar ar2 arcpy

numgens { disp DoGen } repeat
disp
showpage