Conway’s Game of Life has fascinated computer scientists for decades. Even though its rules are ridiculously simple, Conway’s universe gives rise to a variety of gliders, spaceships, oscillators, glider guns, and other forms of “life”. Self-printing programs are similarly curious, and – rather surprisingly – have an important place in the theory of computation.

What happens when you combine the two? You are about to find out, but one thing is for sure: the geekiness factor should be pretty high.

I wrote a little C# program that contains a Game-of-Life grid. The program advances the game grid to the next generation and prints out a copy of itself, with the grid updated. You can take the output, compile it with a C# compiler, run it, and you’ll get the next generation of the game. You can iterate the process, or change the initial grid state manually.

Here is the source code:

using System; class G /* GAME OF LIFE by Igor Ostrovsky */ { static string []S={ "############################################################################" , "# * * #" , "# *** * #" , "# * * #" , "# * * * * #" , "# ** ** ** *** #" , "# * * ** ** #" , "# ** * * ** #" , "# ** * * ** * * #" , "# * * * #" , "# * * #" , "# ** #" , "# ** ** #" , "# ** ** * * #" , "# * * * * * * * #" , "# *** ** ** *** * * #" , "# * * * * * * **** #" , "# *** *** #" , "# #" , "# *** *** #" , "# * * * * * * * #" , "# *** ** ** *** * * * *** #" , "# * * * * * * * * * #" , "# ** ** *** * * ** * #" , "# ** ** **** * #" , "# * * #" , "############################################################################" , }; static void Main(){ string T= "\",r=\"using System;class G /* GAME OF LIFE b" + "y Igor Ostrovsky \"+\"*/ {static string[]S={\

\";int p=31,i,j,b,d;for(i=0;" + "i<27;i++){r+='\"'; for(j=0;j<76;j++){if(S[i][j]!='#'){b=0;for(d=0;d<9;d++)if" + "(S[i-1+d/3][j-1+d%3]=='*')b++;r+=b==3 ||(S[i][j]=='*'&&b==4)?'*':' ';} else " + "r+='#';}r+=\"\\\",\

\";}r+=\"};static\"+\" void Main(){string T=\\\"\";fore" + "ach(var c in T){if(c=='\\\\'||c=='\"'){r+='\\\\';p++;} r+=c; if(++p>=77){r+=" + "\"\\\"+\

\\\"\";p=1;}} foreach(var c in T){r+=c;if(++p%79==0)r+='\

';}Cons" + "ole.Write(r);}}" ,r= "using System;class G /* GAME OF LIFE by Igor Ostrovsky " + "*/ {static string[]S={

" ; int p=31,i,j,b,d; for (i=0;i<27;i++){r+= '"' ; for (j=0; j<76;j++){ if (S[i][j]!= '#' ){b=0; for (d=0;d<9;d++) if (S[i-1+d/3][j-1+d%3]== '*' )b++; r+=b==3 ||(S[i][j]== '*' &&b==4)? '*' : ' ' ;} else r+= '#' ;}r+= "\",

" ;}r+= "};static" + " void Main(){string T=\"" ; foreach ( var c in T){ if (c== '\\' ||c== '"' ){r+= '\\' ;p++ ;} r+=c; if (++p>=77){r+= "\"+

\"" ;p=1;}} foreach ( var c in T){r+=c; if (++p%79==0) r+= '

' ;} Console .Write(r);}}

And is here the output the program prints. The output is the same as the source code, except that the game has advanced to the next generation:

using System;class G /* GAME OF LIFE by Igor Ostrovsky */ {static string[]S={ "############################################################################", "# * #", "# * ** #", "# * * *** #", "# * * ** * #", "# * * * ** *** #", "# ** * * ** * #", "# ** ** ** * * #", "# ** *** ** * * #", "# ** ** * #", "# ** #", "# * #", "# *** *** #", "# #", "# * * * * ** #", "# * * * * ** ** #", "# * * * * **** #", "# *** *** ** #", "# #", "# *** *** #", "# * * * * * #", "# * * * * *** #", "# * * * * * * ** * **#", "# * ** ** ***#", "# *** *** * **** ** #", "# ** #", "############################################################################", };static void Main(){string T="\",r=\"using System;class G /* GAME OF LIFE b"+ "y Igor Ostrovsky \"+\"*/ {static string[]S={\

\";int p=31,i,j,b,d;for(i=0;"+ "i<27;i++){r+='\"'; for(j=0;j<76;j++){if(S[i][j]!='#'){b=0;for(d=0;d<9;d++)if"+ "(S[i-1+d/3][j-1+d%3]=='*')b++;r+=b==3 ||(S[i][j]=='*'&&b==4)?'*':' ';} else "+ "r+='#';}r+=\"\\\",\

\";}r+=\"};static\"+\" void Main(){string T=\\\"\";fore"+ "ach(var c in T){if(c=='\\\\'||c=='\"'){r+='\\\\';p++;} r+=c; if(++p>=77){r+="+ "\"\\\"+\

\\\"\";p=1;}} foreach(var c in T){r+=c;if(++p%79==0)r+='\

';}Cons"+ "ole.Write(r);}}",r="using System;class G /* GAME OF LIFE by Igor Ostrovsky "+ "*/ {static string[]S={

";int p=31,i,j,b,d;for(i=0;i<27;i++){r+='"'; for(j=0; j<76;j++){if(S[i][j]!='#'){b=0;for(d=0;d<9;d++)if(S[i-1+d/3][j-1+d%3]=='*')b++; r+=b==3 ||(S[i][j]=='*'&&b==4)?'*':' ';} else r+='#';}r+="\",

";}r+="};static" +" void Main(){string T=\"";foreach(var c in T){if(c=='\\'||c=='"'){r+='\\';p++ ;} r+=c; if(++p>=77){r+="\"+

\"";p=1;}} foreach(var c in T){r+=c;if(++p%79==0) r+='

';}Console.Write(r);}}

If you want to see the program iterate, save the source code into a file named life.cs, and run this command repeatedly from a Visual Studio console:

csc.exe life.cs && (life > life.cs) && life

Cool, isn’t it? I have a follow-up article nearly ready that explains how to write programs like this one… just in case you ever wanted to.

[Update] The follow-up How to write a self-printing program is up.

More articles:

Numbers that cannot be computed

Skip list are fascinating!

Quicksort killer

Tags: Cool