After getting these two answers I'd like to publish my solution also. After seeing jfbu's answer I was a bit intimidated and I went the luatex way.
The code is probably not efficient, but it can produce an animated PDF – unfortunately this feature only works in Adobe Reader – or pages with the different evolution phases. Also this code only works with n×n matrices.
\documentclass{article}
\usepackage[a0paper]{geometry}
\usepackage{luacode}
\usepackage{animate}
\usepackage{tikz}
\usepackage{xcolor}
\usepackage[active, tightpage]{preview}
\PreviewEnvironment{animateinline}
%\PreviewEnvironment{tikzpicture}
\tikzset{%
cellframe/.style={%
minimum size=5mm,%
draw,%
fill=white,%
fill opacity=0%
}%
}
\tikzset{%
alivecell/.style={%
circle,%
inner sep=0pt,%
minimum size=4mm,%
fill=black%
}%
}
\setlength{\PreviewBorder}{5mm}
\begin{document}
\begin{luacode*}
iterations = 36
grid = {{0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 1, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 1, 0, 0, 0},
{0, 0, 0, 1, 1, 1, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0}}
\end{luacode*}
\begin{luacode*}
function evolve(grid)
local temp = {}
local gridsize = #grid
for i = 1, gridsize do
temp[i] = {}
for j = 1, gridsize do
temp[i][j] = 0
end
end
for i = 1, gridsize do
for j = 1, gridsize do
iminus = i - 1
iplus = i + 1
jminus = j - 1
jplus = j + 1
if iminus == 0 then
iminus = gridsize
end
if iplus == gridsize + 1 then
iplus = 1
end
if jminus == 0 then
jminus = gridsize
end
if jplus == gridsize + 1 then
jplus = 1
end
neighbourcount = grid[iminus][jminus] +
grid[iminus][j] +
grid[iminus][jplus] +
grid[i][jminus] +
grid[i][jplus] +
grid[iplus][jminus] +
grid[iplus][j] +
grid[iplus][jplus]
if (grid[i][j] == 1 and (neighbourcount == 2 or neighbourcount == 3)) or (grid[i][j] == 0 and neighbourcount == 3) then
temp[i][j] = 1
else
temp[i][j] = 0
end
end
end
return temp
end
function display(grid)
local gridsize = #grid
for i = 1, gridsize do
for j = 1, gridsize do
tex.sprint([[\node[cellframe] at (]])
tex.sprint((i - 1) * 5)
tex.sprint([[mm,]])
tex.sprint(-((j - 1) * 5))
tex.sprint([[mm){0};]])
if grid[j][i] == 1 then
tex.sprint([[\node[alivecell] at (]])
tex.sprint((i - 1) * 5)
tex.sprint([[mm,]])
tex.sprint(-((j - 1) * 5))
tex.sprint([[mm){1};]])
end
end
end
end
function animate(grid, iterations)
for i = 1, iterations - 1 do
display(grid)
tex.sprint([[\newframe]])
grid = evolve(grid)
end
display(grid)
end
function frames(grid, iterations)
for i = 1, iterations - 1 do
tex.sprint([[\begin{tikzpicture}]])
display(grid)
grid = evolve(grid)
tex.sprint([[\end{tikzpicture}]])
tex.sprint([[\clearpage]])
end
tex.sprint([[\begin{tikzpicture}]])
display(grid)
tex.sprint([[\end{tikzpicture}]])
end
\end{luacode*}
\noindent\begin{animateinline}[autoplay,loop,
begin={\begin{tikzpicture}[scale=1]},
end={\end{tikzpicture}}]{5}
\luadirect{animate(grid, iterations)}
\end{animateinline}
%\noindent\luadirect{frames(grid, iterations)}
\end{document}
The code above produces the following animation of a glider:

If you want to generate each frames as a new page, then you have to modify the code only a little bit:
Comment line 9:
\PreviewEnvironment{animateinline}
→ %\PreviewEnvironment{animateinline}
Uncomment line 10:
%\PreviewEnvironment{tikzpicture}
→ \PreviewEnvironment{tikzpicture}
Comment lines 153–157 to look like this:
%\noindent\begin{animateinline}[autoplay,loop,
%begin={\begin{tikzpicture}[scale=1]},
%end={\end{tikzpicture}}]{5}
% \luadirect{animate(grid, iterations)}
%\end{animateinline}
Uncomment line 158 to look like this:
\noindent\luadirect{frames(grid, iterations)}
You can specify an initial seed by assigning another array to the grid
lua variable (line 41), and set the number of iterations (number of frames or pages) by assigning the iterations
lua variable (line 39).
Here is an animation of the Gosper glider gun with the following seed with 300 generations:
\begin{luacode*}
iterations = 300
grid = {{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0},
{0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0},
{0,1,1,0,0,0,0,0,0,0,0,1,0,0,0,1,0,1,1,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0},
{0,1,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}}
\end{luacode*}
TikZ
arrays but ad hoc structures thus removing most of the calls to\pgfmathtruncatemacro
from your code. Simple\loop
fromLaTeX
and count registers will be amply enough to go through the rectangular grid. To compute the next generation a simple\numexpr
and either direct code of perhaps use ofetoolbox
if the conditional is a bit complicated for the next generation (don't think so). Thus\foreach+TikZ
used only for drawing. [LaTeX
loop can't be easily nested but one can fix that easily too]\foreach
rather thanLaTeX
loops after all. But no array. Direct control sequences suitably defined via\csname..\endcsname
. [\foreach
creates groups forcing to use global definitions, I don't recall if there is option to\foreach
not to create a group]