Conway's Game of Life

Conway's game of life is not, strictly speaking, geometric art. However, as you progress through the stages of 'life' in this 'game' you'll often see interesting geometric patterns emerge. Let's start by looking at a few examples. 

Examples

Sometimes, you'll get patterns that end after a certain number of timepoints: 

 

Other times, you'll get patterns that continuously repeat: 

 

Even if you start from a completely random assortment of white and black pixels, you can get something that looks pretty interesting.

Okay, that looks pretty neat, but what is it? 

Conway's Game of Life relies on each pixel in the image having a state: alive (black) or dead (white). For each 'tick' of the clock (i.e. for each video frame) you evaluate for each pixel whether it will remain in its current state or change state. 

The rules of life 

You determine what happens to each pixel by evaluating its neighbors. In a square grid, every pixel has eight neighbors (except the border pixels, which have less). Then, you evaluate these four rules:

  1. Any live cell with fewer than two live neighbors dies, as if by under-population.
  2. Any live cell with two or three live neighbors lives on to the next generation.
  3. Any live cell with more than three live neighbors dies, as if by over-population.
  4. Any dead cell with exactly three live neighbors becomes a live cell, as if by reproduction.

(source: wikipedia)

You can play around with Conway's game of life easily here. Or, you can use the code I provide below (which also allows you to make a video). 

Code

% To use this code, you can either run one of the pre-programmed examples
% (i.e. set startingMatrix to 1, 2, 3, 4, or 5), or make up your own "life"
% matrix. Set makeVideo to 1 if you want to record a video

makeVideo=0;
startingMatrix=5;

% Pattern that ends 
if startingMatrix==1
    size1=17;
    size2=17;
    iterations=15;
    life=zeros(size1,size2,iterations+1);
    life(8,8:10)=[1 1 1];
    life(9,8)=1;
    life(9,10)=1;
    life(10,9:10)=[1 1];
    life(11,8)=1;
end

% Pattern that repeats
if startingMatrix==2
    size1=11;
    size2=18;
    iterations=50;
    life=zeros(size1,size2,iterations+1);
    life(4,7:12)=[1,1,1,1,1,1];
    life(8,7:12)=[1 1 1 1 1 1];
    life(5,6)=1;
    life(5,13)=1;
    life(7,6)=1;
    life(7,13)=1;
    life(6,5)=1;
    life(6,14)=1;
end

% Simple repeating pattern
if startingMatrix==3
    size1=5;
    size2=5;
    iterations=8;
    life=zeros(size1,size2,iterations+1);
    life(2:4,3)=[1;1;1];
end

% Pattern that repeats
if startingMatrix==4
    size1=17;
    size2=17;
    iterations=4;
    life=zeros(size1,size2,iterations+1);    
    life(3,5:7)=[1 1 1];
    life(3,11:13)=[1 1 1];
    life(8,5:7)=[1 1 1];
    life(8,11:13)=[1 1 1];
    life(10,5:7)=[1 1 1];
    life(10,11:13)=[1 1 1];
    life(15,5:7)= [1 1 1];
    life(15,11:13)= [1 1 1];
    life(5:7,3)=[1;1;1];
    life(11:13,3)=[1;1;1];
    life(5:7,8)=[1;1;1];
    life(11:13,8)=[1;1;1];
    life(5:7,10)=[1;1;1];
    life(11:13,10)=[1;1;1];
    life(5:7,15)=[1;1;1];
    life(11:13,15)=[1;1;1];
end

% Start with a random matrix
if startingMatrix==5
    size1=50;
    size2=50;
    iterations=600;
    life=ones(size1,size2,iterations+1);   
    for i=1:size1
        for j=1:size2
            life(i,j)=round(rand);
        end
    end
end

% If making a video, initialize the video
if makeVideo==1
    writerObj = VideoWriter('GameOfLifeStopExample1.avi'); % Name it.
    writerObj.FrameRate = 1;
    writerObj.Quality=100;
    open(writerObj)    
end

% Initialize the figure and display the starting matrix
figure('Position',[10,10,700,700],'Color',[1 1 1]);
imagesc(life(:,:,1))
hold on
axis off
axis equal

% Plot the grid
for m=0:size1
    plot([0,size2]+.5,[m,m]+.5,'Color',[0.6 0.6 0.6],'LineWidth',1.5);
end
for m=0:size2
    plot([m,m]+.5,[0,size1]+.5,'Color',[0.6 0.6 0.6],'LineWidth',1.5);
end
colormap('hot')
colormap(flipud(colormap))

% Grab a frame for the video
if makeVideo==1
    frame = getframe(1);
    writeVideo(writerObj, frame) 
end
pause(1)
finish=0;

% Repeat for each iteration
for i=2:iterations+1
    % Clear the current axes
    cla
    % For each row
    for j=1:size1
        % For each column
        for k=1:size2
            % Edge case: corner
            if j==1 && k==1
                a=life(j+1,k,i-1);
                b=life(j,k+1,i-1);
                c=0;
                d=0;
                e=life(j+1,k+1,i-1);
                f=0;
                g=0;
                h=0;
                
            % Edge case: corner
            elseif j==1 && k==size2
                a=life(j+1,k,i-1);
                b=life(j,k-1,i-1);
                c=0;
                d=0;
                e=life(j+1,k-1,i-1);
                f=0;
                g=0;
                h=0;
                
            % Edge case: corner
            elseif j==size1 && k==size2
                a=life(j-1,k,i-1);
                b=life(j,k-1,i-1);
                c=0;
                d=0;
                e=life(j-1,k-1,i-1);
                f=0;
                g=0;
                h=0;
                
            % Edge case: corner              
            elseif j==size1 && k==1
                a=life(j-1,k,i-1);
                b=life(j,k+1,i-1);
                c=0;
                d=0;
                e=life(j-1,k+1,i-1);
                f=0;
                g=0;
                h=0;
            
            % Edge case: side
            elseif j==1
                a=life(j+1,k,i-1);
                b=life(j,k-1,i-1);
                c=life(j,k+1,i-1);
                d=0;
                e=life(j+1,k-1,i-1);
                f=life(j+1,k+1,i-1);
                g=0;
                h=0;
                
            % Edge case: side
            elseif k==1
                a=life(j+1,k,i-1);
                b=life(j-1,k,i-1);
                c=life(j,k+1,i-1);
                d=0;
                e=life(j+1,k+1,i-1);
                f=life(j-1,k+1,i-1);
                g=0;
                h=0;
              
            % Edge case: side
            elseif j==size1
                a=life(j-1,k,i-1);
                b=life(j,k-1,i-1);
                c=life(j,k+1,i-1);
                d=0;
                e=life(j-1,k-1,i-1);
                f=life(j-1,k+1,i-1);
                g=0;
                h=0;
               
            % Edge case: side
            elseif k==size2
                a=life(j+1,k,i-1);
                b=life(j-1,k,i-1);
                c=life(j,k-1,i-1);
                d=0;
                e=life(j-1,k-1,i-1);
                f=life(j+1,k-1,i-1);
                g=0;
                h=0;
            
            % For any non-border pixel
            else
                a=life(j,k-1,i-1);
                b=life(j,k+1,i-1);
                c=life(j-1,k,i-1);
                d=life(j+1,k,i-1);
                e=life(j-1,k-1,i-1);
                f=life(j-1,k+1,i-1);
                g=life(j+1,k+1,i-1);
                h=life(j+1,k-1,i-1);

            end
            
            % If the square is alive
            if life(j,k,i-1)==1
                if a+b+c+d+e+f+g+h==2 || a+b+c+d+e+f+g+h==3
                    life(j,k,i)=1;
                elseif a+b+c+d+e+f+g+h>3
                    life(j,k,i)=0;
                elseif a+b+c+d+e+f+g+h==0 || a+b+c+d+e+f+g+h==1
                    life(j,k,i)=0;
                end
                
            % If the square is dead
            elseif life(j,k,i-1)==0
                if a+b+c+d+e+f+g+h==3
                    life(j,k,i)=1;
                else
                    life(j,k,i)=0;
                end
            end
            
        end
    end

    % If you've reached a state where life no longer changes, end the
    % simulation
    if life(:,:,i)==life(:,:,i-1)
        disp(['SAME at round ',num2str(i-2)]);
        finish=i-2;
        break
    else
        finish=i-1;
    end
   
    % Display the current state
    imagesc(life(:,:,i));
    hold on
    
    % Draw the grid
    for m=0:size1
        plot([0,size2]+.5,[m,m]+.5,'Color',[0.6 0.6 0.6],'LineWidth',1.5);
    end
    for m=0:size2
        plot([m,m]+.5,[0,size1]+.5,'Color',[0.6 0.6 0.6],'LineWidth',1.5);
    end
    axis off
    axis equal
    pause(1)
    
    % Grab a frame for the video
    if makeVideo==1
        frame = getframe(1);
        writeVideo(writerObj, frame) 
    end    
end

% Terminate the video
if makeVideo==1
    close(writerObj)
end