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={\\n\";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+=\"\\\",\\n\";}r+=\"};static\"+\" void Main(){string T=\\\"\";fore"+ "ach(var c in T){if(c=='\\\\'||c=='\"'){r+='\\\\';p++;} r+=c; if(++p>=77){r+="+ "\"\\\"+\\n\\\"\";p=1;}} foreach(var c in T){r+=c;if(++p%79==0)r+='\\n';}Cons"+ "ole.Write(r);}}",r="using System;class G /* GAME OF LIFE by Igor Ostrovsky "+ "*/ {static string[]S={\n";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+="\",\n";}r+="};static" +" void Main(){string T=\"";foreach(var c in T){if(c=='\\'||c=='"'){r+='\\';p++ ;} r+=c; if(++p>=77){r+="\"+\n\"";p=1;}} foreach(var c in T){r+=c;if(++p%79==0) r+='\n';}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={\\n\";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+=\"\\\",\\n\";}r+=\"};static\"+\" void Main(){string T=\\\"\";fore"+ "ach(var c in T){if(c=='\\\\'||c=='\"'){r+='\\\\';p++;} r+=c; if(++p>=77){r+="+ "\"\\\"+\\n\\\"\";p=1;}} foreach(var c in T){r+=c;if(++p%79==0)r+='\\n';}Cons"+ "ole.Write(r);}}",r="using System;class G /* GAME OF LIFE by Igor Ostrovsky "+ "*/ {static string[]S={\n";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+="\",\n";}r+="};static" +" void Main(){string T=\"";foreach(var c in T){if(c=='\\'||c=='"'){r+='\\';p++ ;} r+=c; if(++p>=77){r+="\"+\n\"";p=1;}} foreach(var c in T){r+=c;if(++p%79==0) r+='\n';}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
Tags: Cool
Wow that looks like something I did on my Commodore 64 back in the day.
Jiff
http://www.online-anonymity.kr.tc
You sir, are one evil motherfucker.
I look forward to your follow-up article that explains how to be an evil motherfucker just like you.
[…] Igor writes- 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. […]
wow …
Today, the Game of Life. Tomorrow, Skynet.
My head just exploded.
Hey Igor,
Didn’t know that you regularily blog programming/theory tidbits like this one. Cool.
Coolest quine ever!
it doesnt compile in Mono on Linux.
@rb: The code uses implicitly-typed variables (the ‘var’ keyword). Perhaps Mono does not support that feature yet?
[…] [upmod] [downmod] Self-printing Game of Life in C# | Igor Ostrovsky Blogging (igoro.com) 1 points posted 6 months, 2 weeks ago by jeethu tags game programming quine life […]
[…] the RSS feed to receive my future posts.Powered by WP Greet BoxAs promised at the end of my recent post, I am going to explain how to implement a program that prints itself, in addition to doing other […]
[…] Self-printing Game of Life in C# […]
You could also feed it to the build-in C# compiler.
http://support.microsoft.com/kb/304655
Now THAT’S what I call hardcore metaprogramming…
Von Neumann would be proud. XD
[…] a quine to print out the source code of the program together with a comment containing the next frame in Conway’s Game of Life. So we have programs that can age themselves, as well as programs that double as pictures. The […]
Works for Mono quite all right:
while [ 1 ];do gmcs GameOfLife.cs && mono GameOfLife.exe > GameOfLife.cs && clear && cat GameOfLife.cs|grep "\"#";done
Note the gmcs part. The mcs executable packaged in Mono implements only a subset of the language, or equally, an old version of the language. The Mono compiler for C# 2 and C#1 is mcs, and the Mono compiler for C# 3 and later is gmcs.