Exploring Cyclic Space Automata with PNGwriter


This is a simple implementation of a Cyclic Cellular Automata. The rules are as follows:

  1. Initialize a 2D array with random values between 0 and the max level of states a cell can have.
  2. If a cell has at least one neighbor which value is higher by 1, that cell is eaten by the neighbor (the value changes to the value of the neighbor).
  3. Cells with a value of max-value can only be eaten by cells with a value of 0.   In that case, the value cycles to 0, thus the name cyclic-space.
  4. Repeat the last 2 steps and eventually a stable pattern will emerge.


For more information about cellular automata, see the Wikipedia page on Cellular Automaton and this other PNGwriter example.

Here are some images generated with 14 levels.

000000000.png
0 iterations
000000015.png
15 iterations
000000030.png
30 iterations
000000050.png
50 iterations


The sequence of images can be easily combined into a movie. I used Apple's Quicktime Player (File --> Open Image Sequence...). The movies can be found here: Movies. They are in .mov and .avi format. The .avis have a lower image quality. The filename contains information about how many frames it contains, how many levels were used as part of the rules and if 4 or 8 neighbours were considered. Email me at the email listed in the Contacts section if the movies link does not work, as it is hosted on a different server.

Here's the code:
/* Cyclic Space - Example program for PNGwriter
 * http://pngwriter.sourceforge.net/
 * By Paul Blackburn */

#include <pngwriter.h>
#include <stdlib.h>
#include <time.h>

#define rand_max 2147483647



int main()
{
   int width = 300;
   int height = 300;
   int maxiter = 500;
   
   // Create the PNGwriter instance. 
   pngwriter out(width, height, 0, "out.png");
   
   int k, i, j;
  
   
   // Create old and new grids
   
   int ** grid;
   grid = new int * [width];
   for(k = 0; k < width; k++)
     {
	grid[k] = new int [height];
     }

   int ** newgrid;
   newgrid = new int * [width];
   for(k = 0; k < width; k++)
     {
	newgrid[k] = new int [height];
     }

  
   // Seed random number generator
   int maxstates = 14;
   srandom( time(NULL) );   
   
   //Grid initially randomized.
   for(i = 0; i < width; i++)
     {
	for(j = 0; j < height; j++)
	  {
	     grid[i][j] = random()%maxstates;
	  }
     }

   // Copy to other grid
   for(i = 0; i < width; i++)
     {
	for(j = 0; j < height; j++)
	  {
	     newgrid[i][j] = grid[i][j];
	  }
     }
   
   int jp, jm, ip, im;
   
   // Start iterating
   
   for(int iteration = 0; iteration < maxiter; iteration++)
     {
	
	for(i = 0; i < width; i++)
	  {
	     for(j = 0; j < height; j++)
	       {

		  jp = j+1;
		  jm = j-1;
		  ip = i+1;
		  im = i-1;
		  
		  //Cyclic boundary conditions.
		  
		  if(im == -1)
		    {
		       im = width-1;
		    }
		  
		  if(ip == width)
		    {
		       ip = 0;
		    }
		  
		  if(jm == -1)
		    {
		       jm = height-1;
		    }
		  
		  if(jp == height)
		    {
		       jp = 0;
		    }
		  
		  // Rules
		  
		  if( 
		      (  (grid[im][j] == 0) || 
			 (grid[ip][j] == 0) ||
			 (grid[i][jm] == 0) ||
			 (grid[i][jp] == 0)
			 
			 || (grid[im][jm] == 0) || 
			 (grid[ip][jp] == 0) ||
			 (grid[ip][jm] == 0) ||
			 (grid[im][jp] == 0)  )
		      && 
		      (  grid[i][j] == (maxstates-1) )
		      )
		    {
		       newgrid[i][j] = 0;
		       continue;
		    }
		  
		  if( 
		      (  (grid[im][j] == grid[i][j]+1) || 
			 (grid[ip][j] == grid[i][j]+1) ||
			 (grid[i][jm] == grid[i][j]+1) ||
			 (grid[i][jp] == grid[i][j]+1)  
			 
			 || (grid[im][jm] == grid[i][j]+1) || 
			 (grid[ip][jp] == grid[i][j]+1) ||
			 (grid[ip][jm] == grid[i][j]+1) ||
			 (grid[im][jp] == grid[i][j]+1)  
			 
			 
			 )
		      )
		    {
		       newgrid[i][j] = grid[i][j]+1;
		       continue;
		    }
	       }
	  }
	
	// Copy old grid to new grid
	
	for(i = 0; i < width; i++)
	  {
	     for(j = 0; j < height; j++)
	       {
		  grid[i][j] = newgrid[i][j];
	       }
	  }
	
	// Plot the result, with level of red according to the state that pixel is in.
	for(i = 0; i < width; i++)
	  {
	     for(j = 0; j < height; j++)
	       {
		  out.plot(i+1,j+1, ((double) grid[i][j])/(maxstates-1), 0.0, 0.0);
	       }
	  }

	// Rename this instance given the iteration number.
	out.pngwriter_rename((unsigned long int) iteration);   

	// Write the file to disk.
	out.close();
	
     } //iteration
   
   // Delete grids.
   for(k = 0; k < width; k++)
     {
	delete [] grid[k];
     }
   delete [] grid;

   for(k = 0; k < width; k++)
     {
	delete [] newgrid[k];
     }
   delete [] newgrid;

   return 0;
}



syntax highlighted by Code2HTML, v. 0.9.1
Valid CSS!


© 2002, 2003, 2004, 2005, 2006, 2007 Paul Blackburn