% life Implementation of Conway's Game of Life [PHYS210-ca]
%
% Life is a 2D 2-state cellular automata using 8 cell neighbourhood 
% and the following update rule (states are 0 ("dead") and 1 ("live")):
%
%    S_{n}   N-live  S_{n+1}
%
%     0        3        1
%     1        2        1
%     1        3        1
%
%     OTHERWISE         0
%
% Here S_{n}, S_{n+1} are the states at the n-th and n+1-st time steps,
% and N-live is the number of live states (1's) in the neighbourhood at 
% step n.
% 
% This version uses 'dead' boundary conditions.
% 
% Loops over the individual cells are used.  See 'lifea' for a much
% more efficient version that uses whole array operations.
%
% Function 'latout' used to generate file output for subsequent 
% visualization with 'xflat2d_rgb'.
% 
% After running this script, use
%
%    xflat2d_rgb < life.dat
%
% to visualize evolution.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% Disable paging so that diagnostic (tracing) output appears as script 
% executes
more off;

% Script name (for diagnostic messages)
S = 'life';

% Initial data types
id_random = 0;
id_random_frac = 0.5;

id_glider = 1;

% Which initial data type?
id_type = id_random;

% Dimensions of arena (lattice)
nx = 50;
ny = 50;

% Number of generations
nt = 200;

% Echo parameter settings.
fprintf('life: id_type=%d  nx=%d  ny=%d  nt=%d\n', id_type, nx, ny, nt);

% Define arena and initialize to "all dead"
c = zeros(nx,ny,nt);

% Initialize arena according to chosen initial data type.
% Ensure that initialization maintains 0's on boundaries.

if id_type == id_random
   % Use random initial conditions in central part of arena
   % (TODO: controlled by id_random_frac), dead elsewhere
   wx = fix(id_random_frac * nx);
   wy = fix(id_random_frac * nx);
   c(2:nx-1,2:ny-1,1) = fix(2 * rand(nx-2,ny-2));
elseif id_type == id_glider
   % Set initial data to a single glider in lower-left hand corner
   % that will then propagate up and to the right
   cx = 5;
   cy = ny - 5;
   c(cx,  cy,  1) = 1;
   c(cx+1,cy,  1) = 1;
   c(cx+2,cy,  1) = 1;
   c(cx+2,cy+1,1) = 1;
   c(cx+1,cy+2,1) = 1;
else
   fprintf('%s: Invalid [id_type] = %d\n', S, id_type);
end

% Evolve for a total of nt generations
for n = 1 : nt - 1
   fprintf('%s: Step %d of %d\n', S, n, nt);
   % Note the limits on the loops: "dead" boundary conditions are 
   % used (and initially set), so don't update boundary cells
   for i = 2 : nx - 1
      for j = 2 : ny - 1
         % Compute the number of live cells in the neighbourhood
         count = c(i+1,j-1,n) + c(i+1,j,n) + c(i+1,j+1,n) + ...
                 c(i  ,j-1,n)              + c(i  ,j+1,n) + ...
                 c(i-1,j-1,n) + c(i-1,j,n) + c(i-1,j+1,n);
         % Update the cell state according to the rules
         if c(i,j,n) == 1
            if (count == 2) | (count == 3)
               c(i,j,n+1) = 1;
            else
               c(i,j,n+1) = 0;
            end
         else
            if count == 3
               c(i,j,n+1) = 1;
            else
               c(i,j,n+1) = 0;
            end
         end
      end
   end
end

% Define colours (3 element vectors of RGB values) for latout ... 
% 
% 0 (dead) -> white 
% 1 (live) -> blue

rgb = [[1.0 1.0 1.0]; [0.0 0.0 1.0]];

% Output the entire evolution of the arena states ... Note that 
% the 4th argument to latout, which is optional, enables tracing
% messages in the function.  Its value (10 in this case), specifies
% how frequently messages will be output to the terminal in the 
% function's main loop ...

latout('life.dat', c, rgb, 10);
