Conway's Game of Life is the classic example of cellular automation. The cells form a square grid and each has two states: alive or dead. On each turn, each cell simultaneously updates according to its state and those of its eight neighbours:

  • A live cell remains alive if it has exactly two or three live neighbours
  • A dead cell becomes alive if it has exactly three live neighbours

Your mission, should you choose to accept it, is to code the shortest Game of Life implementation in your favourite language.

The rules:

  • The grid must be at least 20x20
  • The grid must wrap around (so the grid is like the surface of a Torus)
  • Your implementation must allow the user to input their own starting patterns
  • GoL is a bit pointless if you can't see what is happening, so there must be visual output of the automaton running, with each turn's result being shown for long enough to be seen!
  • 8
    Previously on Stack Overflow: Code Golf: Conway's Game of Life, and be sure to look at the APL implementation link in the comments. – dmckee Aug 14 '11 at 3:07
  • 1
    Ah, I did not see that. But this is slightly different no (save me deleting the work putting the challenge together? – Griffin Aug 14 '11 at 3:15
  • 6
    It's not a problem. Many puzzles already run on Stack Overflow have been done here too, but people will tell you that I am obsessive about linking to similar challenges. – dmckee Aug 14 '11 at 3:17
  • @Griffin: You can remove all those ; before }s. Also vars can be eliminated at times (if it doesn't break your code). And for one-line fors, ifs etc, you can eliminate the { } completely: for(...) for(...) dosomething(). – pimvdb Aug 14 '11 at 14:21
  • @pimvdb, cheers, I haven't fully golfed it yet, haven't had the time. just wanted to show that I had a go too, rather than idly setting a challenge. Will golf it to the max soon. – Griffin Aug 14 '11 at 17:53

30 Answers 30

up vote 27 down vote accepted

HTML5 Canvas with JavaScript, 940 639 586 519 characters

<html><body onload="k=40;g=10;b=[];setInterval(function(){c=[];for(y=k*k;y--;){n=0;for(f=9;f--;)n+=b[(~~(y/k)+k+f%3-1)%k*k+(y+k+~~(f/3)-1)%k];c[y]=n==3||n-b[y]==3;r.fillStyle=b[y]?'red':'tan';r.fillRect(y%k*g,~~(y/k)*g,g-1,g-1)}if(v.nextSibling.checked)b=c},1);v=document.body.firstChild;v.width=v.height=g*k;v.addEventListener('click',function(e){b[~~((e.pageY-v.offsetTop)/g)*k+~~((e.pageX-v.offsetLeft)/g)]^=1},0);r=v.getContext('2d');for(y=k*k;y--;)b[y]=0"><canvas></canvas><input type="checkbox"/>Run</body></html>

I always wanted to do something with canvas, so here is my attempt (original version online). You can toggle cells by clicking (also possible in running mode).

You can now also try the new version here.

Unfortunately there is an issue I couldn't work around yet. The online version is 11 characters longer because jsFiddle puts a text node just before the canvas (why?) and thus the canvas is no longer the first child.

Edit 1: Lots of optimisations and restructurings.

Edit 2: Several smaller changes.

Edit 3: Inlined the complete script block plus minor changes.

  • Nice, but change the interval delay to 1 makes it as fast as mine rather than that slow stepping. Also if you want to implement drawing (rather than clicking on each square) you can round the mouse position to the nearest blocksize and fill the rectangle at that point. More characters but more points. – Griffin Aug 15 '11 at 0:32
  • You can replace new Array('#FFF','#800') with ['#FFF','#800']. – Lowjacker Aug 15 '11 at 15:59
  • Though saying that about drawing, my super-golfed doesn't allow drawing and is ugly as sin. Haha. You can set your two colours in the s array to tan and red since they are the two colours with the shortest representations - saves you two chars. Also, if possible, put the literal version of j into the interval. I'm sure there's lots more to squeeze out too. – Griffin Aug 19 '11 at 14:46
  • @Griffin and Lowjacker: thank you very much. I am also pretty sure that you can golf this much more (and have already some ideas). Unfortunately I didn't find the time to do so. A better golfed version will follow tomorrow - I hope... – Howard Aug 19 '11 at 15:07
  • 1
    You can remove the html and body tags. It will function the same – arodebaugh Mar 8 '17 at 11:52

Python, 219 chars

I went for maximum golfage, with just enough interface to satisfy the question.

import time
P=input()
N=range(20)
while 1:
 for i in N:print''.join(' *'[i*20+j in P]for j in N)
 time.sleep(.1);Q=[(p+d)%400 for d in(-21,-20,-19,-1,1,19,20,21)for p in P];P=set(p for p in Q if 2-(p in P)<Q.count(p)<4)

You run it like this:

echo "[8,29,47,48,49]" | ./life.py

The numbers in the list represent the coordinates of the starting cells. The first row is 0-19, the second row is 20-39, etc.

Run it in a terminal with 21 rows and it looks pretty snazzy.

  • 1
    This totally should have won. I guess 'ease of input' was weighted fairly high. – primo Aug 3 '12 at 10:13
  • @primo I'd even go so far as to suggest mma should have a separate competition. – luser droog Jan 26 '13 at 4:35
  • 2
    So is this Life of Py then? – Christopher Wirt Mar 10 '17 at 15:59
  • You can always save one more char... 2-(p in P) == 2-({p}<P). But then you would have to change your input to {8,29,47,48,49} :) – JBernardo Aug 17 '17 at 18:26

TI-BASIC, 96 bytes (87 for non-competing entry)

For your TI-84 series graphing calculator (!). This was quite a challenge, because there is no easy way to write a buffered graphics routine (definitely nothing built in), and the graph screen has only four relevant graphics commands: Pxl-On(), Pxl-Off(), Pxl-Change(), and pxl-Test().

Uses every accessible pixel on the screen, and wraps correctly. Each cell is one pixel, and the program updates line by line horizontally to the right across the screen. Because the calculators have only a 15MHz z80 processor and BASIC is a slow interpreted language, the code only gets one frame about every five minutes.

User input is easy: before running the program, use the Pen tool to draw your shape on the graph screen.

Adapted from my entry to a code golf contest at the calculator forum Omnimaga.

0
While 1
For(X,0,94
Ans/7+49seq(pxl-Test(remainder(Y,63),remainder(X+1,95)),Y,62,123
For(Y,0,62
If 1=pxl-Test(Y,X)+int(3fPart(3cosh(fPart(6ֿ¹iPart(sum(Ans,Y+1,Y+3
Pxl-Change(Y,X
End
End
End

Omnimaga version (87 bytes)

This code has an additional feature: it detects if it is being run for the first time, and if randomizes the screen state. In subsequent runs it automatically continues the simulation if stopped after a frame is finished. However, it is not a competing entry because it does not wrap the screen; the cells on the outer border will always be considered dead if the graph screen is cleared beforehand.

0
While 1
For(X,0,93
Ans/7+49seq(pxl-Test(Y,X+1),Y,0,62
For(Y,1,61
If 2rand>isClockOn=pxl-Test(Y,X)+int(3fPart(3cosh(fPart(6ֿ¹iPart(sum(Ans,Y,Y+2
Pxl-Change(Y,X
End
End
ClockOff
End

This version is probably the most golfed code I have ever written, and contains some truly nasty obfuscatory optimizations:

  • I use the clock state as a flag. At the start of the program, the date/time clock is enabled, and I use the value of the global isClockOn flag to determine whether it is the first iteration. After the first frame is drawn, I turn the clock off. Saves one byte over the shortest other method and about four over the obvious method.

  • I store the states of the three columns next to the one being updated in a 63-element array of base-7 numbers. The 49's place holds the column to the right, the 7's place holds the middle column, and the units place holds the left column--1 for a live cell and 0 for a dead cell. Then I take the remainder mod 6 of the sum of the three numbers around the cell being modified to find the total number of live neighbor cells (it's just like the divisibility by 9 trick—in base 7, the remainder mod 6 equals the sum of the digits). Saves about 10 bytes by itself and gives the opportunity to use the next two optimizations. Example diagram (let's say there is a glider centered at a certain column at Y=45:

    Row # | Cell State       | Stored number | Mod 6 = cell count
    ...
    44      Live, Live, Live   49+7+1 = 57     3
    45      Dead, Dead, Live   49+0+0 = 49     1
    46      Dead, Live, Dead   0+7+0  = 7      1
    ...
    

    The center cell will stay dead, because it is surrounded by exactly five live cells.

  • After each row is completed, the numbers in the array are updated by dividing the existing numbers by 7, discarding the decimal part, and adding 49 times the values of the cells in the new column. Storing all three columns each time through would be much slower and less elegant, take at least 20 more bytes, and use three lists rather than one, because the values of cells in each row must be stored before cells are updated. This is by far the smallest way to store cell positions.

  • The snippet int(3fPart(3cosh( gives 1 when the input equals 3/6, 2 when it equals 4/6, and 0 when it equals 0, 1/6, 2/6, or 5/6. Saves about 6 bytes.

Mathematica - 333

Features:

  • Interactive interface: click cells to make your patterns

  • Nice grid

  • Buttons: RUN, PAUSE, CLEAR

The code is below.

Manipulate[x=Switch[run,1,x,2,CellularAutomaton[{224,{2,{{2,2,2},{2,1,2},{2,2,2}}},
{1,1}},x],3,Table[0,{k,40},{j,40}]];EventHandler[Dynamic[tds=Reverse[Transpose[x]];
ArrayPlot[tds,Mesh->True]],{"MouseClicked":>(pos=Ceiling[MousePosition["Graphics"]];
x=ReplacePart[x,pos->1-x[[Sequence@@pos]]];)}],{{run,3,""},{1->"||",2->">",3->"X"}}]

enter image description here

If you want to get a feel how this runs, 2nd example in this blog is just a more elaborate version (live Fourier analysis, better interface) of the code above. Example should run right in your browser after free plugin download.

  • 2
    +1, nice one for having a go. Yeah that's the problem with this site, there are tonnes of old questions which one tends to miss. – Griffin Jul 31 '12 at 13:10
  • @Griffin thanks for noticing it at all ;) – Vitaliy Kaurov Sep 13 '13 at 1:35

C 1063 characters

As a challenge, I did this in C using the golf-unfriendly Windows API for real time IO. If capslock is on, the simulation will run. It will stay still if capslock is off. Draw patterns with the mouse; left click revives cells and right click kills cells.

#include <windows.h>
#include<process.h>
#define K ][(x+80)%20+(y+80)%20*20]
#define H R.Event.MouseEvent.dwMousePosition
#define J R.Event.MouseEvent.dwButtonState
HANDLE Q,W;char*E[3],O;Y(x,y){return E[0 K;}U(x,y,l,v){E[l K=v;}I(){E[2]=E[1];E[1]=*E;*E=E[2];memset(E[1],0,400);}A(i,j,k,l,P){while(1){Sleep(16);for(i=0;i<20;++i)for(j=0;j<20;++j){COORD a={i,j};SetConsoleCursorPosition(Q,a);putchar(E[0][i+j*20]==1?'0':' ');}if(O){for(i=0;i<20;++i)for(j=0;j<20;++j){for(k=i-1,P=0;k<i+2;++k)for(l=j-1;l<j+2;++l){P+=Y(k,l);}U(i,j,1,P==3?1:Y(i,j)==1&&P==4?1:0);}I();}}}main(T,x,y,F,D){for(x=0;x<21;++x)puts("#####################");E[0]=malloc(800);E[1]=E[0]+400;I();I();W=GetStdHandle(-10);Q=GetStdHandle(-11);SetConsoleMode(W,24);INPUT_RECORD R;F=D=O=0;COORD size={80,25};SetConsoleScreenBufferSize(Q,size);_beginthread(A,99,0);while(1){ReadConsoleInput(W,&R,1,&T);switch(R.EventType){case 1:O=R.Event.KeyEvent.dwControlKeyState&128;break;case 2:switch(R.Event.MouseEvent.dwEventFlags){case 1:x=H.X;y=H.Y;case 0:F=J&1;D=J&2;}if(F)U(x,y,0,1);if(D)U(x,y,0,0);}}}

The compiled EXE can be found here

Edit: I've commented up the source. It's available Here

  • I'd love to see a commented version of this! – luser droog Dec 21 '12 at 2:50
  • 1
    Sure, if I can remember what I was thinking... =p – Kaslai Dec 22 '12 at 23:18
  • 1
    @luserdroog Here it is pastebin.com/BrX6wgUj – Kaslai Dec 22 '12 at 23:59
  • This is just awesome. – rayryeng Dec 12 '16 at 22:07

J (39 characters)

l=:[:+/(3 4=/[:+/(,/,"0/~i:1)|.])*.1,:]

Based on this APL version (same algorithm, toroidal convolution).

Example usage:

   r =: (i.3 3) e. 1 2 3 5 8
   r
0 1 1          NB. A glider!
1 0 1
0 0 1

   R =: _1 _2 |. 5 7 {. r
   R
0 0 0 0 0 0 0  NB. Test board
0 0 0 1 1 0 0
0 0 1 0 1 0 0
0 0 0 0 1 0 0
0 0 0 0 0 0 0

   l R
0 0 0 0 0 0 0  NB. Single step
0 0 0 1 1 0 0
0 0 0 0 1 1 0
0 0 0 1 0 0 0
0 0 0 0 0 0 0

Mathematica, 123 characters

A very rudimentary implementation that doesn't use Mathematica's built-in CellularAutomaton function.

ListAnimate@NestList[ImageFilter[If[3<=Total@Flatten@#<=3+#[[2]][[2]],1,0]&,#,1]&,Image[Round/@RandomReal[1,{200,200}]],99]

Ruby 1.9 + SDL (380 325 314)

EDIT: 314 characters, and fixed a bug with extra cells appearing alive on the first iteration. Upped the grid size to 56 since the color routine only looks at the lowest 8 bits.

EDIT: Golfed down to 325 characters. Grid width/height is now 28 since 28*9 is the largest you can have while still using the value as the background colour. It also processes only one SDL event per iteration now, which obviates the inner loop completely. Pretty tight I think!

The simulation starts paused, with all cells dead. You can press any key to toggle pause/unpause, and click any cell to toggle it between alive and dead. Runs an iteration every tenth of a second.

The wrapping is a bit wonky.

require'sdl'
SDL.init W=56
R=0..T=W*W
b=[]
s=SDL::Screen.open S=W*9,S,0,0
loop{r="#{e=SDL::Event.poll}"
r['yU']?$_^=1:r[?Q]?exit: r['nU']?b[e.y/9*W+e.x/9]^=1:0
b=R.map{|i|v=[~W,-W,-55,-1,1,55,W,57].select{|f|b[(i+f)%T]}.size;v==3||v==2&&b[i]}if$_
R.map{|i|s.fillRect i%W*9,i/W*9,9,9,[b[i]?0:S]*3}
s.flip
sleep 0.1}

Looks like this:

Screenshot of the app in action

Fun challenge! I welcome any improvements anybody can see.

  • Nice try but I can see straight away that you've gone wrong. You can't have a pattern like that in GoL. Have another read of the rules: en.wikipedia.org/wiki/Conway%27s_Game_of_Life#Rules – Griffin Aug 1 '12 at 8:01
  • @Griffin I think the screenshot was taken after pausing and toggling some cells manually - I'll check the rules again, though. Thanks! – Paul Prestidge Aug 2 '12 at 0:44
  • 6
    @Griffin cant the seed pattern be in any possible configuration? – ardnew Aug 8 '12 at 4:30

Scala, 1181 1158 1128 1063 1018 1003 999 992 987 characters

import swing._
import event._
object L extends SimpleSwingApplication{import java.awt.event._
import javax.swing._
var(w,h,c,d,r)=(20,20,20,0,false)
var x=Array.fill(w,h)(0)
def n(y:Int,z:Int)=for(b<-z-1 to z+1;a<-y-1 to y+1 if(!(a==y&&b==z)))d+=x((a+w)%w)((b+h)%h)
def top=new MainFrame with ActionListener{preferredSize=new Dimension(500,500)
menuBar=new MenuBar{contents+=new Menu("C"){contents+={new MenuItem("Go/Stop"){listenTo(this)
reactions+={case ButtonClicked(c)=>r= !r}}}}}
contents=new Component{listenTo(mouse.clicks)
reactions+={case e:MouseClicked=>var p=e.point
x(p.x/c)(p.y/c)^=1
repaint}
override def paint(g:Graphics2D){for(j<-0 to h-1;i<-0 to w-1){var r=new Rectangle(i*c,j*c,c,c)
x(i)(j)match{case 0=>g draw r
case 1=>g fill r}}}}
def actionPerformed(e:ActionEvent){if(r){var t=x.map(_.clone)
for(j<-0 to h-1;i<-0 to w-1){d=0
n(i,j)
x(i)(j)match{case 0=>if(d==3)t(i)(j)=1
case 1=>if(d<2||d>3)t(i)(j)=0}}
x=t.map(_.clone)
repaint}}
val t=new Timer(200,this)
t.start}}

Ungolfed:

import swing._
import event._

object Life extends SimpleSwingApplication
{
    import java.awt.event._
    import javax.swing._
    var(w,h,c,d,run)=(20,20,20,0,false)
    var x=Array.fill(w,h)(0)
    def n(y:Int,z:Int)=for(b<-z-1 to z+1;a<-y-1 to y+1 if(!(a==y&&b==z)))d+=x((a+w)%w)((b+h)%h)
    def top=new MainFrame with ActionListener
    {
        title="Life"
        preferredSize=new Dimension(500,500)
        menuBar=new MenuBar
        {
            contents+=new Menu("Control")
            {
                contents+={new MenuItem("Start/Stop")
                {
                    listenTo(this)
                    reactions+=
                    {
                        case ButtonClicked(c)=>run= !run
                    }
                }}
            }
        }
        contents=new Component
        {
            listenTo(mouse.clicks)
            reactions+=
            {
                case e:MouseClicked=>
                    var p=e.point
                    if(p.x<w*c)
                    {
                        x(p.x/c)(p.y/c)^=1
                        repaint
                    }
            }
            override def paint(g:Graphics2D)
            {
                for(j<-0 to h-1;i<-0 to w-1)
                {
                    var r=new Rectangle(i*c,j*c,c,c)
                    x(i)(j) match
                    {
                        case 0=>g draw r
                        case 1=>g fill r
                    }
                }
            }
        }
        def actionPerformed(e:ActionEvent)
        {
            if(run)
            {
                var t=x.map(_.clone)
                for(j<-0 to h-1;i<-0 to w-1)
                {
                    d=0
                    n(i,j)
                    x(i)(j) match
                    {
                        case 0=>if(d==3)t(i)(j)=1
                        case 1=>if(d<2||d>3)t(i)(j)=0
                    }
                }
                x=t.map(_.clone)
                repaint
            }
        }
        val timer=new Timer(200,this)
        timer.start
    }
}

The larger part of the code here is Swing GUI stuff. The game itself is in the actionPerformed method which is triggered by the Timer, and the helper function n which counts neighbours.

Usage:

Compile it with scalac filename and then run it with scala L.
Clicking a square flips it from live to dead, and the menu option starts and stops the game. If you want to change the size of the grid, change the first three values in the line: var(w,h,c,d,r)=(20,20,20,0,false) they are width, height and cell size (in pixels) respectively.

  • I found 2 golfing-improvements: import java.awt.event._ and contents+=m("Go",true)+=m("Stop",false)}}, leading to 1093 characters. – user unknown Aug 14 '11 at 19:20
  • @user unknown Thanks. I found a few improvements myself - down to 1063 now. – Gareth Aug 14 '11 at 19:47
  • Damn you've been busy. Keep it up! I will be testing answers when a few more people post them. – Griffin Aug 14 '11 at 23:56

Pure Bash, 244 bytes

Works on a toroidally-wrapped 36x24 universe:

mapfile a
for e in {0..863};{
for i in {0..8};{
[ "${a[(e/36+i/3-1)%24]:(e+i%3-1)%36:1}" == O ]&&((n++))
}
d=\ 
c=${a[e/36]:e%36:1}
[ "$c" == O ]&&((--n==2))&&d=O
((n-3))||d=O
b[e/36]+=$d
n=
}
printf -vo %s\\n "${b[@]}"
echo "$o"
exec $0<<<"$o"

Since this is a shell script, the method of input is congruent with other shell commands - i.e. from stdin:

$ ./conway.sh << EOF

   O 
    O 
  OOO 

EOF


  O O                                                       
   OO                                                       
   O                                                        

















    O                                                       
  O O                                                       
   OO                                                       

... etc

We can redirect input from any text source, piped through a tr filter to get interesting initial generations, e.g.

man tr | tr [:alnum:] O | ./conway.sh

JavaScript, 130

Not totally responding to the challenge, but for the record, here's a Game of Life engine in 130 bytes made by Subzey and I in 2013.

http://xem.github.io/miniGameOfLife/

/* Fill an array with 0's and 1's, and call g(array, width, height) to iterate */
g=function(f,c,g,d,e,b,h){g=[];e=[c+1,c,c-1,1];for(b=c*c;b--;g[b]=3==d||f[b]&&2==d,d=0)for(h in e)d+=f[b+e[h]]+f[b-e[h]];return g}
  • This seems to have some problems with the first row. For example setting @@\n@@ (2 by 2 square in top left corner) or .@\n.@\n.@. (1 by 3 column) – Annan Feb 5 at 21:03

C# - 675 chars

I've always wanted to write a version of this program. Never knew it would only take a lazy half hour for a quick and dirty version. (Golfing it takes much longer, of course.)

using System.Windows.Forms;class G:Form{static void Main(){new G(25).ShowDialog();}
public G(int z){var g=new Panel[z,z];var n=new int [z,z];int x,y,t;for(int i=0;i<z;
i++)for(int j=0;j<z;j++){var p=new Panel{Width=9,Height=9,Left=i*9,Top=j*9,BackColor
=System.Drawing.Color.Tan};p.Click+=(s,a)=>p.Visible=!p.Visible;Controls.Add(g[i,j]=
p);}KeyUp+=(s,_)=>{for(int i=0;i<99;i++){for(x=0;x<z;x++)for(y=0;y<z;y++){t=0;for(int 
c=-1;c<2;c++)for(int d=-1;d<2;d++)if(c!=0||d!=0){int a=x+c,b=y+d;a=a<0?24:a>24?0:a;b=
b<0?24:b>24?0:b;t+=g[a,b].Visible?0:1;}if(t==3||t>1&&!g[x,y].Visible)n[x,y]=1;if(t<2
||t>3)n[x,y]=0;}for(x=0;x<z;x++)for(y=0;y<z;y++)g[x,y].Visible=n[x,y]<1;Update();}};}}

Usage

  • Enter a starting pattern by clicking cells to turn them on (alive).
  • Start the game by pressing any keyboard key.
  • The game runs for 99 generations every time a key is pressed (I could have made it 9 to save a char, but that seemed too lame).

Golfing compromises

  • You can only turn cells on with the mouse, not off, so if you make a mistake you have to restart the program.
  • There are no grid lines, but that doesn't hurt playability too much.
  • Update speed is proportional to CPU speed, so on very fast computers it will probably be just a blur.
  • Living cells are red because "black" uses 2 more characters.
  • The smallness of the cells and the fact that they don't use up all the form space are also character-saving compromises.

GW-BASIC, 1086 1035 bytes (tokenised)

In tokenised form, this is 1035 bytes. (The ASCII form is, of course, a bit longer.) You get the tokenised form by using the SAVE"life command without appending ",a in the interpreter.

10 DEFINT A-Z:DEF SEG=&HB800:KEY OFF:COLOR 7,0:CLS:DEF FNP(X,Y)=PEEK((((Y+25)MOD 25)*80+((X+80)MOD 80))*2)
20 X=0:Y=0
30 LOCATE Y+1,X+1,1
40 S$=INKEY$:IF S$=""GOTO 40
50 IF S$=CHR$(13)GOTO 150
60 IF S$=" "GOTO 130
70 IF S$=CHR$(0)+CHR$(&H48)THEN Y=(Y-1+25)MOD 25:GOTO 30
80 IF S$=CHR$(0)+CHR$(&H50)THEN Y=(Y+1)MOD 25:GOTO 30
90 IF S$=CHR$(0)+CHR$(&H4B)THEN X=(X-1+80)MOD 80:GOTO 30
100 IF S$=CHR$(0)+CHR$(&H4D)THEN X=(X+1)MOD 80:GOTO 30
110 IF S$="c"THEN CLS:GOTO 20
120 GOTO 40
130 Z=PEEK((Y*80+X)*2):IF Z=42 THEN Z=32ELSE Z=42
140 POKE(Y*80+X)*2,Z:GOTO 40
150 LOCATE 1,1,0:ON KEY(1)GOSUB 320:KEY(1) ON
160 V!=TIMER+.5:FOR Y=0 TO 24:FOR X=0 TO 79:N=0
170 Z=FNP(X-1,Y-1):IF Z=42 OR Z=46 THEN N=N+1
180 Z=FNP(X,Y-1):IF Z=42 OR Z=46 THEN N=N+1
190 Z=FNP(X+1,Y-1):IF Z=42 OR Z=46 THEN N=N+1
200 Z=FNP(X-1,Y):IF Z=42 OR Z=46 THEN N=N+1
210 Z=FNP(X+1,Y):IF Z=42 OR Z=46 THEN N=N+1
220 Z=FNP(X-1,Y+1):IF Z=42 OR Z=46 THEN N=N+1
230 Z=FNP(X,Y+1):IF Z=42 OR Z=46 THEN N=N+1
240 Z=FNP(X+1,Y+1):IF Z=42 OR Z=46 THEN N=N+1
250 Z=PEEK((Y*80+X)*2):IF Z=32 THEN IF N=3 THEN Z=43
260 IF Z=42 THEN IF N<2 OR N>3 THEN Z=46
270 POKE(Y*80+X)*2,Z:NEXT:NEXT:FOR Y=0 TO 24:FOR X=0 TO 79:Z=PEEK((Y*80+X)*2):IF Z=46 THEN Z=32
280 IF Z=43 THEN Z=42
290 POKE(Y*80+X)*2,Z:NEXT:NEXT
300 IF TIMER<V!GOTO 300
310 IF INKEY$=""GOTO 160
320 SYSTEM

This is the maximum-golfed version, but still featureful: upon starting, you get an editor, in which you can move with the cursor keys; space toggles bacteria on/off on the current field, c clears the screen, Return starts game mode.

Here follows a less-obfuscated version, which also sets an initial game board with two structures (a circulary-rotating thing and a glider):

1000 REM Conway's Game of Life
1001 REM -
1002 REM Copyright (c) 2012 Thorsten "mirabilos" Glaser
1003 REM All rights reserved. Published under The MirOS Licence.
1004 REM -
1005 DEFINT A-Z:DEF SEG=&hB800
1006 KEY OFF:COLOR 7,0:CLS
1007 DEF FNP(X,Y)=PEEK((((Y+25) MOD 25)*80+((X+80) MOD 80))*2)
1010 PRINT "Initial setting mode, press SPACE to toggle, RETURN to continue"
1020 PRINT "Press C to clear the board, R to reset. OK? Press a key then."
1030 WHILE INKEY$="":WEND
1050 CLS
1065 DATA 3,3,4,3,5,3,6,3,7,3,8,3,3,4,4,4,5,4,6,4,7,4,8,4
1066 DATA 10,3,10,4,10,5,10,6,10,7,10,8,11,3,11,4,11,5,11,6,11,7,11,8
1067 DATA 11,10,10,10,9,10,8,10,7,10,6,10,11,11,10,11,9,11,8,11,7,11,6,11
1068 DATA 4,11,4,10,4,9,4,8,4,7,4,6,3,11,3,10,3,9,3,8,3,7,3,6
1069 DATA 21,0,22,1,22,2,21,2,20,2,-1,-1
1070 RESTORE 1065
1080 READ X,Y
1090 IF X=-1 GOTO 1120
1100 POKE (Y*80+X)*2,42
1110 GOTO 1080
1120 X=0:Y=0
1125 LOCATE Y+1,X+1,1
1130 S$=INKEY$
1140 IF S$="" GOTO 1130
1150 IF S$=CHR$(13) GOTO 1804
1160 IF S$=" " GOTO 1240
1170 IF S$=CHR$(0)+CHR$(&h48) THEN Y=(Y-1+25) MOD 25:GOTO 1125
1180 IF S$=CHR$(0)+CHR$(&h50) THEN Y=(Y+1) MOD 25:GOTO 1125
1190 IF S$=CHR$(0)+CHR$(&h4B) THEN X=(X-1+80) MOD 80:GOTO 1125
1200 IF S$=CHR$(0)+CHR$(&h4D) THEN X=(X+1) MOD 80:GOTO 1125
1210 IF S$="c" THEN CLS:GOTO 1120
1220 IF S$="r" GOTO 1050
1225 IF S$=CHR$(27) THEN END
1230 GOTO 1130
1240 Z=PEEK((Y*80+X)*2)
1250 IF Z=42 THEN Z=32 ELSE Z=42
1260 POKE (Y*80+X)*2,Z
1270 GOTO 1130
1804 LOCATE 1,1,0
1900 ON KEY(1) GOSUB 2300
1910 KEY(1) ON
2000 V!=TIMER+.5
2010 FOR Y=0 TO 24
2020  FOR X=0 TO 79
2030   N=0
2040   Z=FNP(X-1,Y-1):IF Z=42 OR Z=46 THEN N=N+1
2050   Z=FNP(X  ,Y-1):IF Z=42 OR Z=46 THEN N=N+1
2060   Z=FNP(X+1,Y-1):IF Z=42 OR Z=46 THEN N=N+1
2070   Z=FNP(X-1,Y  ):IF Z=42 OR Z=46 THEN N=N+1
2080   Z=FNP(X+1,Y  ):IF Z=42 OR Z=46 THEN N=N+1
2090   Z=FNP(X-1,Y+1):IF Z=42 OR Z=46 THEN N=N+1
2100   Z=FNP(X  ,Y+1):IF Z=42 OR Z=46 THEN N=N+1
2110   Z=FNP(X+1,Y+1):IF Z=42 OR Z=46 THEN N=N+1
2120   Z=PEEK((Y*80+X)*2)
2130   IF Z=32 THEN IF N=3 THEN Z=43
2140   IF Z=42 THEN IF N<2 OR N>3 THEN Z=46
2150   POKE (Y*80+X)*2,Z
2160  NEXT X
2170 NEXT Y
2200 FOR Y=0 TO 24
2210  FOR X=0 TO 79
2220   Z=PEEK((Y*80+X)*2)
2230   IF Z=46 THEN Z=32
2240   IF Z=43 THEN Z=42
2250   POKE (Y*80+X)*2,Z
2260  NEXT X
2270 NEXT Y
2280 IF TIMER<V! GOTO 2280
2290 IF INKEY$="" GOTO 2000
2300 SYSTEM

I wrote this in 15 minutes while bored and waiting for a friend, who was code-golfing with his “apprentice” for Conway’s Game of Life at the same time.

It functions like this: It immediately uses the 80x25 text mode screen buffer (change the initial DEF SEG to use &hB000 if you’re on a Hercules graphics card; these settings work with Qemu and (slower) dosbox). An asterisk * is a bacterium.

It works two-pass: first, birthplaces are marked with + and death marks its targets with .. In the second pass, + and . are replaced with * and , respectively.

The TIMER thing is to make it wait for half a second after each round, in case your Qemu host is very fast ☺

I’m not hoping for a shortest-wins price here but for a coolness one, especially considering the initial board setup. I’ve also got a version where the game engine was replaced by assembly code, in case you’re interested…

  • Considering you incremented your labels by 1 on the non-golfed version, is it possible to do the same on the golfed version? (i.e., 1, 2, 3, etc.) Or do the line numbers not count? – Zacharý Aug 17 '17 at 20:12
  • line numbers, when tokenised, count as word (16 bit), if I’m not totally mistaken – mirabilos Aug 18 '17 at 0:23
  • Okay then, guess I must've been thinking of some other BASIC dialect then. – Zacharý Aug 18 '17 at 10:51
  • @Zacharý Click on “GW-BASIC tokenised program format” then on “Program format” here to see that, indeed, line numbers are constantly two bytes, and for more in-depth details on the token format. – mirabilos Aug 22 '17 at 8:48

Mathematica, 115 bytes

Here's an easy cop-out to this:

ListAnimate[ArrayPlot/@CellularAutomaton[{224,{2,{{2,2,2},{2,1,2},
{2,2,2}}},{1,1}},{RandomInteger[1,{9,9}],0},90]]
  • 1
    Mathematica is fine, but as the rules state the program must allow the user to input their own patterns. This rule is intentional since a few languages allow short implementations like this but with no user interaction. Sure you can put your own array in there, but it's not gonna win. – Griffin Aug 14 '11 at 23:58
  • "input" in Mathematica is mostly through the notebook interface, so I don't think "user interaction" is really possible. You just replace the RandomInteger argument to the CellularAutomaton function with whatever you want, and re-evaluate the code. – JeremyKun Aug 15 '11 at 0:16
  • 3
    User interaction is possible. The most simplistic method I can think of right now is an array of buttons. Give it a go man. – Griffin Aug 15 '11 at 0:19

Java (OpenJDK 8) - 400 388 367 bytes

Second and (probably) Final Edit: Managed to golf an extra 21 bytes after finding these (imo) goldmines - definitely recommend new people to read these (especially if you're going to try some of these challenges using Java).

Resulting code (probably going to end up golfing even more if I find out how to shorten those double nested for loops...):

u->{int w=u.length,h=u[0].length,x,y,i,j,n;Stack<Point>r=new Stack<Point>();for(;;){for(Point c:r)u[c.x][c.y]=1;r.clear();for(x=0;x<w;++x)for(y=0;y<h;++y){boolean o=u[x][y]>0;n=o?-1:0;for(i=-2;++i<2;)for(j=-2;++j<2;)if(u[(w+x+i)%w][(h+y+j)%h]>0)++n;if(o&n>1&n<4|!o&n==3)r.add(new Point(x,y));System.out.print(u[x][y]+(y>h-2?"\n":""));}for(int[]t:u)Arrays.fill(t,0);}}

Try it online!

(Original post starts here.)

I actually thought for a moment that I would be able to at least challenge the best Python answer with my (arguably limited) knowledge of Java lol...It was a challenge I nevertheless enjoyed partaking in (despite having joined the party perhaps just a little bit late...)

There's not much to it really - basic explanation as follows (ungolfed):

/*
 * Explanation of each variable's usage:
 * w=height* of array
 * h=width* of array
 * x=y* coord of point in array
 * y=x* coord of point in array
 * i and j are counters for calculating the neighbours around a point in the array
 * n=neighbour counter
 * r=temporary array to store the cells from the current generation
 * u=the 2d array used for all the calculations (parameter from lambda expression)
 * c=temporary variable used to help populate the 2d array
 * o=boolean variable that stores the value of whether the cell is alive or not
 */
u-> // start of lambda statement with u as parameter (no need for brackets as it's only one parameter being passed)
{
    int w=u.length,h=u[0].length,x,y,i,j,n; // defines all the necessary integer variables;
    Stack<Point>r=new Stack<Point>(); // same with the only array list needed (note how I only use two data structures);
    for(;;) // notice how this is still an infinite loop but using a for loop;
    {
        for(Point c:r)u[c.x][c.y]=1; //for every point in the "previous" generation, add that to the 2D array as a live (evil?) cell;
        r.clear(); // clears the array list to be populated later on
        for(x=0;x<w;++x) // a pair of nested for loops to iterate over every cell of the 2D array;
        {
            for(y=0;y<h;++y)
            {
                // sets o to be the presence of a live cell at (x,y) then uses said value in initialising the neighbour counter;
                boolean o=u[x][y]>1;n=o?-1:0;
                for(i=-2;++i<2;) // another pair of nested for loops - this one iterates over a 3x3 grid around *each* cell of the 2D array;
                {                // this includes wrap-around (note the modulus sign in the if statement below);
                    for(j=-2;++j<2;)
                    {
                        if(u[(w+x+i)%w][(h+y+j)%h]>0)++n; // this is where the first interesting thing lies - the bit which makes wrap-around a reality;
                    }
                }
                if(o&n>1&n<4|!o&n==3)r.add(new Point(x,y)); // this is the second interesting bit of my code - perhaps more so as I use bitwise operators to calculate the number of neighbours (x,y) has;
                                                            // (since I'm technically dealing with 0s and 1s, it's not a total misuse of them imo);
                System.out.print(u[x][y]+(y>h-2?"\n":""));  // that extra part of the print statement adds a newline if we reached the end of the current 'line';
            }
        }
        // since the information about the new generation is now in the array list, this array can be emptied out, ready to receive said info on the new generation;
        for(int[]t:u)Arrays.fill(t,0);
    }
} // end of lambda statement

(more information about lambda statements in Java 8 here)

Yes, there's a catch with my approach.

As most of you probably noticed, my golfed code as it currently stands will loop forever. To prevent this, a counter can be introduced at the top and used in the while loop to only display n (in this case, 5) iterations as follows (notice the new b variable added):

u->{int b=0,w=u.length,h=u[0].length,x,y,i,j,n;Stack<Point>r=new Stack<Point>();for(;++b<6;){for(Point c:r)u[c.x][c.y]=1;r.clear();for(x=0;x<w;++x)for(y=0;y<h;++y){boolean o=u[x][y]>0;n=o?-1:0;for(i=-2;++i<2;)for(j=-2;++j<2;)if(u[(w+x+i)%w][(h+y+j)%h]>0)++n;if(o&n>1&n<4|!o&n==3)r.add(new Point(x,y));System.out.print(u[x][y]+(y>h-2?"\n":""));}for(int[]t:u)Arrays.fill(t,0);}}

Additionally, a few points worth mentioning. This program does not check if the input is correct and will, therefore, fail with (most likely) an ArrayOutOfBoundsException; as such, make sure to check that the input is valid by completely filling in a part of an array (skewered arrays will throw the exception mentioned above). Also, the board as it currently is looks 'fluid' - that is, there is no separation between one generation and the next. If you wish to add that in to double-check that the generations being produced are indeed valid, an extra System.out.println(); needs to be added just before for(int[]t:u)Arrays.fill(t,0); (see this Try it online! for clarity). And last, but not least, given that this is my first code golf, any feedback is greatly appreciated :)

Old code from previous 388 byte answer:

u->{int w=u.length,h=u[0].length,x,y,i,j,n;ArrayList<Point>r=new ArrayList<Point>();while(true){for(Point c:r)u[c.x][c.y]=1;r.clear();for(x=0;x<w;++x){for(y=0;y<h;++y){boolean o=u[x][y]==1;n=o?-1:0;for(i=-2;++i<2;)for(j=-2;++j<2;)if(u[(w+x+i)%w][(h+y+j)%h]==1)++n;if(o&n>1&n<4|!o&n==3)r.add(new Point(x,y));System.out.print(u[x][y]);}System.out.println();}for(int[]t:u)Arrays.fill(t,0);}}

And from the initial 400 byte answer:

int w=35,h=20,x,y,i,j,n;ArrayList<Point>l=new ArrayList<Point>(),r;while(true){int[][]u=new int[w][h];for(Point c:l)u[c.x][c.y]=1;r=new ArrayList<Point>();for(x=0;x<w;++x){for(y=0;y<h;++y){boolean o=u[x][y]==1;n=o?-1:0;for(i=-2;++i<2;)for(j=-2;++j<2;)if(u[(w+x+i)%w][(h+y+j)%h]==1)++n;if(o&n>1&n<4|!o&n==3)r.add(new Point(x,y));System.out.print(u[x][y]);}System.out.println();}l.clear();l.addAll(r);}
  • Amazing first post, welcome to PPCG! – Zacharý Aug 14 '17 at 1:20
  • Thanks, I'm definitely going to be doing more of these - they're fun :) – NotBaal Aug 14 '17 at 1:26
  • Join us, we have Dennis. Also, this is not a complete program nor a function, which it needs to be, IIRC. – Zacharý Aug 14 '17 at 1:28
  • Oh right forgot the 'program' part :P Editing that in in a bit. – NotBaal Aug 14 '17 at 2:04
  • It can just be a function too. – Zacharý Aug 14 '17 at 2:06

Stencil, 6 bytes

Not my favourite language, but it is short…

4 code bytes plus the nlist and Torus flags.

3∊me

Try it online!

Is…
3 3
 a member of
m the moore-neighbourhood-count with self or
e the moore-neighbourhood-count without self
…?

Scala - 799 chars

Run as a script. A mouse click on a square toggles it on or off and any key starts or stops generation.

import java.awt.Color._
import swing._
import event._
import actors.Actor._
new SimpleSwingApplication{var(y,r,b)=(200,false,Array.fill(20,20)(false))
lazy val u=new Panel{actor{loop{if(r){b=Array.tabulate(20,20){(i,j)=>def^(i:Int)= -19*(i min 0)+(i max 0)%20
var(c,n,r)=(0,b(i)(j),-1 to 1)
for(x<-r;y<-r;if x!=0||y!=0){if(b(^(i+x))(^(j+y)))c+=1}
if(n&&(c<2||c>3))false else if(!n&&c==3)true else n}};repaint;Thread.sleep(y)}}
focusable=true
preferredSize=new Dimension(y,y)
listenTo(mouse.clicks,keys)
reactions+={case e:MouseClicked=>val(i,j)=(e.point.x/10,e.point.y/10);b(i)(j)= !b(i)(j)case _:KeyTyped=>r= !r}
override def paintComponent(g:Graphics2D){g.clearRect(0,0,y,y);g.setColor(red)
for(x<-0 to 19;y<-0 to 19 if b(x)(y))g.fillRect(x*10,y*10,9,9)}}
def top=new Frame{contents=u}}.main(null)

J, 45

I thought I'd give J a try. It's not particularly well golfed yet, but I'll give it another try soon.

(]+.&(3&=)+)+/((4&{.,(_4&{.))(>,{,~<i:1))&|.

Example:

   f =: 5 5 $ 0 1 0 0 0   0 0 1 0 0   1 1 1 0 0   0 0 0 0 0    0 0 0 0 0
   f
0 1 0 0 0
0 0 1 0 0
1 1 1 0 0
0 0 0 0 0
0 0 0 0 0
   f (]+.&(3&=)+)+/((4&{.,(_4&{.))(>,{,~<i:1))&|. f
0 0 0 0 0
1 0 1 0 0
0 1 1 0 0
0 1 0 0 0
0 0 0 0 0

Matlab (152)

b=uint8(rand(20)<0.2)
s=@(m)imfilter(m,[1 1 1;1 0 1;1 1 1],'circular')
p=@(m,n)uint8((n==3)|(m&(n==2)))
while 1
imshow(b)
drawnow
b=p(b,s(b))
end

I dont have Matlab installed right now to test it, I just golfed the code that I wrote a few years ago.
Ungolfed:

%% initialize
Bsize = 20;
nsteps = 100;
board = uint8(rand(Bsize)<0.2); % fill 20% of the board
boardsum = @(im) imfilter(im,[1 1 1; 1 0 1; 1 1 1], 'circular');
step = @(im, sumim) uint8((sumim==3) | (im & (sumim==2)) );

%% run
for i = 1:nsteps
    imshow(kron(board,uint8(ones(4))), [])
    drawnow
    ss(p,i) = sum(board(:));
    board = step(board, boardsum(board));
end
  • Boardsize is hardcoded but can be anything
  • wraps around
  • for user input one can change the inital board either by hardcoding another matrix or using the variable editor. Not pretty, but it works
  • 20 chars can be saved if the graphical output is skipped, the board will still be printed as text at every iteration. One-pixel cells which change every millisecond are not very useful anyway
  • works in R2014a, just tested – masterX244 Oct 6 '14 at 13:12

Perl, 218 216 211 202 bytes

$,=$/;$~=AX3AAAx76;$b=pack('(A79)23',<>)x6;{print unpack'(a79)23a0',$b;select$v,$v,$v,0.1;$b=pack'(A)*',unpack'((x7a/(x13)X4Ax!18)1817@0)4',pack'((a*)17xx!18)*',unpack"x1737(AA$~Ax$~AA$~@)2222",$b;redo}

(No newline at the end of this code.)

Reads the starting pattern from standard input, as a text file where live cells are represented as 1, dead cells represented as a space, lines are separated by a newline. The input shall not have characters other than these. Lines can be variable length, and will be padded or truncated to exactly 79 wide. Example input is a glider gun:

                                  1
                                1 1
                      11      11            11
                     1   1    11            11
          11        1     1   11
          11        1   1 11    1 1
                    1     1       1
                     1   1
                      11









                                         11
                                         1
                                          111
                                            1

As the program runs Game of Life, every state is dumped to the standard output in a format similar to the input, then delays 0.1 seconds. The delay can be customized by changing the fourth argument of the select call.

The game board is hard-coded to size 79x23. It is wrapped in a torus: if you leave the board on the bottom, you end up at the top; if you leave on the right side, you end up at the left side but shifted one row down.

Here's an alternate version that doesn't read any input and starts from a random board:

$,=$/;$/=AX3AAAx76;$b=pack("(A)*",map{rand 3<1}0..1816)x6;{print unpack'(a79)23a0',$b;select$v,$v,$v,0.1;$b=pack'(A)*',unpack'((x7a/(x13)X4Ax!18)1817@0)4',pack'((a*)17xx!18)*',unpack"x1737(AA$/Ax$/AA$/@)2222",$b;redo}

This code is derived from an obfuscated game of life perl program I wrote years ago. I have changed it a lot to make the board toroidal and golf the code.

This is probably not the shortest method to implement Game of Life in perl, but it's one of the less comprehensible ones.

The board is stored in $b as a string of '1' and ' ', one for each cell, only the whole thing is repeated at least three times. The third unpack call extracts 17 values for each cell: there's one for the cell itself and two for each of the eight neighboring cells, in an arbitrary order, and each value is '1' or an empty string. The cell should be live in the next iteration iff the number of '1' values among these 17 values is 5, 6, or 7. The third pack call concatenates these 17 values to a 18 character wide field left aligned and padded with nul bytes on the right. The second unpack call takes such a 18 wide field, dispatches on the character at position 7, unpacks the space from position 17 if it's a '1', or unpacks the character from position 4 otherwise. This result is exactly the value the cell should have in the next generation.

Python, 589 bytes

Mouse buttons: left - put a cell, right - remove a cell, middle - start/stop.

from Tkinter import*
import copy
z=range
F=50
T=Tk()
S=9
f=[F*[0]for i in'7'*F]
c=Canvas(T,width=S*F,height=S*F)
c.pack()
def p(x,y,a):f[y][x]=f[y][x]or c.create_oval(x*S,y*S,x*S+S,y*S+S)if a else c.delete(f[y][x])
r=1
def R(e):global r;r=1-r
exec("c.bind('<Button-%i>',lambda e:p(e.x/S,e.y/S,%i));"*2%(1,1,3,0))
c.bind('<Button-2>',R)
def L():
 T.after(99,L)
 if r:return
 g=copy.deepcopy(f)
 for y in z(F):
	for x in z(F):
	 n=8
	 for j in z(-1,2):
		for i in z(-1,2):
		 if i or j:n-=not g[(y+j)%F][(x+i)%F]
	 if 1<n<4:
		if n==3and not g[y][x]:p(x,y,1)
	 else:p(x,y,0)
L()
T.mainloop()

And here is a version where you can drag mouse to draw. Graphics are a bit more pleasant.

from Tkinter import*
import copy
z=range
F=50
T=Tk()
S=9
f=[F*[0]for i in'7'*F]
c=Canvas(T,bg='white',width=S*F,height=S*F)
c.pack()
def p(x,y,a):f[y][x]=f[y][x]or c.create_rectangle(x*S,y*S,x*S+S,y*S+S,fill='gray')if a else c.delete(f[y][x])
r=1
def R(e):global r;r=1-r
exec("c.bind('<Button-%i>',lambda e:p(e.x/S,e.y/S,%i));c.bind('<B%i-Motion>',lambda e:p(e.x/S,e.y/S,%i));"*2%(1,1,1,1,3,0,3,0))
c.bind('<Button-2>',R)
def L():
 T.after(99,L)
 if r:return
 g=copy.deepcopy(f)
 for y in z(F):
  for x in z(F):
   n=8
   for j in z(-1,2):
    for i in z(-1,2):
     if i or j:n-=not g[(y+j)%F][(x+i)%F]
   if 1<n<4:
    if n==3and not g[y][x]:p(x,y,1)
   else:p(x,y,0)
L()
T.mainloop()
  • This doesn't follow the game of life rules correctly. – Steven Rumbalski Aug 23 '11 at 13:23
  • 1
    @StevenRumbalski: Oh really? – Oleh Prypin Aug 23 '11 at 14:00
  • 2
    really. You have an indentation error in your second version. The section starting with if 1<n<4: should be indented at the same level as for j in z(-1,2): – Steven Rumbalski Aug 23 '11 at 18:36

Processing 536 532

int h=22,t=24,i,j;int[][]w=new int[t][t],b=new int[t][t];int[]q={1,0,-1};void draw(){if(t<9){clear();for(i=2;i<h;i++){for(j=2;j<h;j++)w[i][j]=b[i][j];w[i][1]=w[i][21];w[i][h]=w[i][2];w[1][i]=w[21][i];w[h][i]=w[2][i];}for(i=1;i<23;i++)for(j=1;j<23;j++){t=-w[i][j];for(int s:q)for(int d:q)t+=w[i+s][j+d];b[i][j]=w[i][j]>0&(t<2|t>3)?0:t==3?1:b[i][j];}a();}}void keyPressed(){t=0;}void mousePressed(){int i=mouseX/5+2,j=mouseY/5+2;w[i][j]=b[i][j]=1;a();}void a(){for(i=0;i<h-2;i++)for(j=0;j<h-2;j++)if(w[i+2][j+2]==1)rect(i*5,j*5,5,5);}

I believe this satisfies all of the requirements.

Ungolfed:

int h=22,t=24,i,j;
int[][]w=new int[t][t],b=new int[t][t];
int[]q={1,0,-1};
void draw(){
  if(t<9){
  clear();
  for(i=2;i<h;i++){
    for(j=2;j<h;j++)
      w[i][j]=b[i][j];  
    w[i][1]=w[i][21];
    w[i][h]=w[i][2];
    w[1][i]=w[21][i];
    w[h][i]=w[2][i];
  }
  for(i=1;i<23;i++)
    for(j=1;j<23;j++){
      t=-w[i][j];
      for(int s:q)
        for(int d:q)
          t+=w[i+s][j+d];        
      b[i][j]=w[i][j]>0&(t<2|t>3)?0:t==3?1:b[i][j];  
  }
  a();
}
}
void keyPressed(){
  t=0;
}
void mousePressed(){
  int i=mouseX/5+2,j=mouseY/5+2;
  w[i][j]=b[i][j]=1;
  a();
}
void a(){
  for(i=0;i<h-2;i++)
    for(j=0;j<h-2;j++)
      if(w[i+2][j+2]==1)
        rect(i*5,j*5,5,5);
  }  

Python 2, 456 bytes

While I know this is an old post, I couldn't help myself from giving it a shot. The initial board can be any size as long as you draw a border around it and have an extra space on the last line.

Golf.py

import time,itertools as w,sys;t,q=map(lambda x:list(x[:-1]),sys.stdin.readlines()),list(w.product(range(-1,2),range(-1,2)));del q[4];n=map(lambda x:x[:],t[:])
while time.sleep(0.1)==None:
 for j in range(1,len(t)-1):
  for i in range(1,len(t[j])-1):x=sum(map(lambda s:1 if t[j+s[0]][i+s[1]]in'@'else 0,q));f=t[j][i];n[j][i]='@'if(f=='@'and(x==3 or x==2))or(f==' 'and x==3)else' '
 t=map(lambda x:x[:],n[:]);print'\n'.join(list(map(lambda x:''.join(x),t)))

Input.txt (note the extra space on the last line)

+----------------------------------------+
|                    @                   |
|                     @                  |
|                   @@@                  |
|                                        |
|                                        |
|                                        |
|                                        |
|                                        |
|                                        |
|                                        |
|                                        |
|                                        |
|                                        |
|                                        |
|                                        |
|                                        |
|                                        |
|                                        |
|                                        |
|                                        |
+----------------------------------------+ 

How to Run

python Golf.py < input.txt
  • time.sleep(0.1)==None => not time.sleep(.1), (f=='@'and(x==3 or x==2))or(f==' 'and x==3) => x==3or f=='@'and x==2 – CalculatorFeline Jun 22 '17 at 3:35
  • ^, You forgot one, 1 if=>1if. – Zacharý Aug 17 '17 at 20:05

Processing 270,261 249 bytes

Grid is the 100*100 pixels of screen, input comes in the form of a png picture

void setup(){image(loadImage("g.png"),0,0);}void draw(){loadPixels();int n,i=0,j,l=10000;int[]a=new int[l],p=pixels;for(;i<l;a[i]=n==5?-1<<24:n==6?p[i]:-1,i++)for(j=n=0;j<9;j++)n+=j!=4?p[(i+l-1+j%3+100*(j/3-1))%l]&1:0;arrayCopy(a,p);updatePixels();}

Ungolfed

void setup() {
  image(loadImage("g.png"), 0, 0);
}
void draw() {
  loadPixels();
  int c=100, i=0, n, l=c*c, b=color(0);
  int[]a=new int[l], p=pixels;
  for (; i<l; i++) {
    n=p[(i+l-101)%l]&1;
    n+=p[(i+l-100)%l]&1;
    n+=p[(i+l-99)%l]&1;
    n+=p[(i+l-1)%l]&1;
    n+=p[(i+1)%l]&1;
    n+=p[(i+99)%l]&1;
    n+=p[(i+100)%l]&1;
    n+=p[(i+101)%l]&1;
    a[i]=n==5?b:p[i]==b&&n==6?b:-1;
  }
  arrayCopy(a, pixels, l);
  updatePixels();
}

screenshot

Postscript 529 515

Started with the example from Rosetta Code. Invoke with a filename argument (gs -- gol.ps pulsar), the file containing 20*20 binary numbers (separated by space). Infinite loop: draw board, wait for enter, calculate next generation.

[/f ARGUMENTS 0 get(r)file/n 20>>begin[/m
n 1 sub/b[n{[n{f token pop}repeat]}repeat]/c 400
n div/F{dup 0 lt{n add}if dup n ge{n sub}if}>>begin{0
1 m{dup 0 1 m{2 copy b exch get exch get 1 xor setgray
c mul exch c mul c c rectfill dup}for pop pop}for
showpage/b[0 1 m{/x exch def[0 1 m{/y exch def 0
y 1 sub 1 y 1 add{F dup x 1 sub 1 x
1 add{F b exch get exch get 3 2 roll add exch
dup}for pop pop}for b x get y get sub b x get y get
0 eq{3 eq{1}{0}ifelse}{dup 2 eq exch 3 eq
or{1}{0}ifelse}ifelse}for]}for]def}loop

Spaced, with a few stack comments (just the ones I needed).

[
/f ARGUMENTS 0 get(r)file
/n 20
/sz 400
%/r{rand 2147483647 div}
>>begin
[
/m n 1 sub
/b[
%n{[n{r .15 le{1}{0}ifelse}repeat]}repeat
 n{[n{f token pop}repeat]}repeat
]
/c sz n div
/F{dup 0 lt{n add}if dup n ge{n sub}if}
>>begin
{
    0 1 m{dup % y y
    0 1 m{ % y y x
        2 copy b exch get exch get 1 xor setgray
        c mul exch c mul c c rectfill
        dup 
    }for pop pop}for
    pstack
    showpage
    /b[0 1 m{/x exch def
      [0 1 m{/y exch def
          0   
          y 1 sub 1 y 1 add{F dup %s y y
          x 1 sub 1 x 1 add{F %s y y x
              b exch get exch get %s y bxy
              3 2 roll add exch %s+bxy y
              dup %s y y
          }for pop pop}for
          b x get y get sub
          b x get y get
          0 eq{3 eq{1}{0}ifelse}{dup 2 eq exch 3 eq or{1}{0}ifelse}ifelse
      }for]
      }for]def
}loop

pulsar data file:

0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 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 1 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 1 0 0 0 0 1 0 1 0 0 0 0 1 0 0 0 0
0 0 0 1 0 0 0 0 1 0 1 0 0 0 0 1 0 0 0 0
0 0 0 1 0 0 0 0 1 0 1 0 0 0 0 1 0 0 0 0
0 0 0 0 0 1 1 1 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 0 1 1 1 0 0 0 1 1 1 0 0 0 0 0 0
0 0 0 1 0 0 0 0 1 0 1 0 0 0 0 1 0 0 0 0
0 0 0 1 0 0 0 0 1 0 1 0 0 0 0 1 0 0 0 0
0 0 0 1 0 0 0 0 1 0 1 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 1 1 1 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 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

JavaScript 676

Sorry Griffin, I just couldn't look at your code and not re-write it slightly... had to shave off two characters but it was damn worth it!

b=[];r=c=s=20;U=document;onload=function(){for(z=E=0;z<c;++z)for(b.push(t=[]),j=0;j<r;j++)with(U.body.appendChild(U.createElement("button")))t.push(0),id=z+"_"+j,style.position="absolute",style.left=s*j+"px",style.top=s*z+"px",onclick=a}; ondblclick=function(){A=E=E?clearInterval(A):setInterval(function(){Q=[];for(z=0;z<c;++z){R=[];for(j=0;j<r;)W=(c+z-1)%c,X=(c+z+1)%c,Y=(r+j-1)%r,Z=(r+j+1)%r,n=b[W][Y]+b[z][Y]+b[X][Y]+b[W][j]+b[X][j]+b[W][Z]+b[z][Z]+b[X][Z],R.push(b[z][j++]?4>n&&1<n:3==n);Q.push(R)}b=Q.slice();d()})};function a(e){E?0:P=e.target.id.split("_");b[P[0]][P[1]]^=1;d()}function d(){for(z=0;z<c;++z)for(j=0;j<r;)U.getElementById(z+"_"+j).innerHTML=b[z][j++]-0}

But as they say, it's easier to ask for forgiveness than permission... ;)

Octave (153)

the same as Matlab by DenDenDo at Shortest Game of Life , but had to change imshow to imagesc:

b=uint8(rand(20)<0.2)
s=@(m)imfilter(m,[1 1 1;1 0 1;1 1 1],'circular')
p=@(m,n)uint8((n==3)|(m&(n==2)))
while 1
imagesc(b)
drawnow
b=p(b,s(b))
end

Python 2: 334 Bytes

Only 6 years late.

import time
s='';s=map(list,iter(raw_input,s));k=len(s);l=(-1,0,1);n=int;z=range
while 1:
 r=[[0]*k for i in z(k)]
 for i in z(k*k):
  a,b=i//k,i%k
  m,g=sum([n(s[(a+c)%k][(b+d)%k])for c in l for d in l if c|d]),n(s[a][b])
  r[a][b]=n((m==2)&g or m==3)
  print'*'if r[a][b]else' ',
  if b-k+1==0:print
 s=r;time.sleep(.2);print"\033c"

You can run it like:

python gol.py
0000000
0001000
0000100
0011100
0000000
0000000
0000000

Where the 0s and 1s represent dead and live cells, an extra newline at the end begins execution.

Grids must be square.

It's easier to run than the shortest python one, supports any sized grids, and looks pretty when run.

It's also 100 bytes more, so there's that.

PHP, 201 bytes (not tested)

for($s=file(f);print"\n";$s=$t)foreach($s as$y=>$r)for($x=-print"
";"
"<$c=$s[$y][++$x];print$t[$y][$x]=" X"[$n<4&$n>2-$a])for($n=-$a=$c>A,$i=$x-!!$x-1;$i++<=$x;)for($k=$y-2;$k++<=$y;)$n+=$s[$k][$i]>A;

Run with -nr.

breakdown

for($s=file(f);                         # import input from file "f"
    print"\n";                              # infinite loop: 1. print newline
    $s=$t)                                  # 3. copy target to source, next iteration
    foreach($s as$y=>$r)                    # 2. loop through lines
        for($x=-print"\n";"\n"<$c=$s[$y][++$x]; # print newline, loop $x/$c through line characters (before line break)
            print                                   # 5. print new cell
                $t[$y][$x]=" X"[$n>2-$a&$n<4])      # 4. new cell is alive if neighbour count<4 and >2 (>1 if alive)
            for($n=-                                # 2. init neighbour count: exclude self
                $a=$c>A,                            # 1. $a=cell is alife
                $i=$x-!!$x-1;$i++<=$x;)             # 3. loop $i from one left to one right of current position
                for($k=$y-2;$k++<=$y;)                  # loop $k from one above to one below current position
                    $n+=$s[$k][$i]>A;                       # increase neighbor count if neighbour is alife

VBA (Excel), 546* Bytes

Sub t()
f=[a1:t20]
For Each c In f.Cells
c.Value=""
r=c.Row
l=c.Column
If g(r,0,0,l,-1,0)Then h=h+1
If g(r,0,0,l,1,21)Then h=h+1
If g(r,-1,0,l,0,0)Then h=h+1
If g(r,1,21,l,0,0)Then h=h+1
If g(r,1,21,l,-1,0)Then h=h+1
If g(r,-1,0,l,1,21)Then h=h+1
If g(r,-1,0,l,-1,0)Then h=h+1
If g(r,1,21,l,1,21)Then h=h+1
If h=3Or(h=2And c.Interior.Color=0)Then c.Value="A"
Next
f.Interior.ColorIndex=0
For Each c In f
If c.Value="A"Then c.Interior.Color=0
Next
End Sub
Function g(r,e,f,c,q,z)
g=(Cells(IIf(r+e=f,Abs(f-20),r+e),IIf(c+q=z,Abs(z-20),c+q)).Interior.Color=0)
End Function

Create the living cells by highlighting cells in A1:T20 and coloring them black.

*When t is run, it executes a single tick. I added a button on mine to click repeatedly. If this doesn't satisfy the requirements, I'll add a do-->while[counta(f)]>0 and a DoEvents for +34 bytes.

[I'll edit this with a link when I upload a copy of my macro-enabled Excel doc]

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.