Skip to content


Cellular Automata – Conway’s Game of Life in HTML 5

I had to do a school project involving automata so, after searching what this means .. I came to “cellular automaton” and then to the “Conway’s Game of Life” on wikipedia. I remember doing such a project on RentACoder few years ago in Visual Basic but I didn’t knew this fancy name for it … “cellular automata” :-)

The rules are pretty simple :

  • A cell with 0 or 1 neighbor dies because of underpopulation
  • A cell with 4 or more neighbors dies because of overpopulation
  • If an empty space has exactly 3 cells then a new cell is born in that empty space
  • If none of the above rules apply then the space does not change (a live cell remanins alive, and an empty space is still empty)

For implementing it .. I choosed the canvas object from HTML 5 specs as I wanted to learn a little bit about it.

The first step was writing the canvas tags with a default message in case the user’s browser does not support it.

  1. <canvas id="drawBoard" width="400" height="400">
  2. Your browser does not support canvas.
  3. </canvas>

After this .. came the fun part .. javascript :)

The code below is pretty simple :

  • We declare how many cells we want on the X/Y axes, how many pixels wide should be a cell and the delay between drawing the next generation of cells
  • We create 2 arrays, one for storing the initial colony and one for the next generation
  • We randomly fill with live cells the initial colony
  • We draw the initial colony and then we process the colony using the game’s rules
JAVASCRIPT [Show Plain Code]:
  1. <script language="javascript">
  2. // Settings
  3. var x = 160; // How many cells on the X axis
  4. var y = 140; // How many cells on the Y axis
  5. var pixels_per_value = 4; // How many pixels wide should be a cell
  6. var delay_between_frames = 400;// In ms
  7.  
  8.  
  9. // Calculate the canvas width and height
  10. var canvas_x = x * pixels_per_value;
  11. var canvas_y = y * pixels_per_value;
  12.  
  13. // Create our matrix
  14. var matrix = new Array(y);
  15. var matrix_tmp = new Array(y);
  16. for (i = 0; i < y; i++)
  17. {
  18.         matrix[i] = new Array(x);
  19.         matrix_tmp[i] = new Array(x);
  20. }
  21.  
  22. // Fill with some random points
  23. var random = 1600;
  24. var m,n;
  25. for (i = 0; i < random; i++)
  26. {
  27.         m = Math.floor(Math.random()*y);
  28.         n = Math.floor(Math.random()*x);
  29.         matrix[m][n] = 1;
  30. }
  31.  
  32. // Get the canvas reference and the 2D context
  33. var canvas = document.getElementById('drawBoard');
  34. // Set canvas size
  35. canvas.width = canvas_x;
  36. canvas.height = canvas_y;
  37. var context = canvas.getContext('2d');
  38.  
  39. // Draw the first cell generation
  40. draw_matrix();
  41.  
  42. // Call for the next generation of the cell colony
  43. setTimeout("process_life()", delay_between_frames);
  44.  
  45.  
  46. function process_life()
  47. {
  48.         var neighbours = 0;
  49.         matrix_tmp = matrix.clone();
  50.         for (i = 0; i < y; i++)
  51.         {
  52.                 for (j = 0; j < x; j++)
  53.                 {
  54.                         neighbours = count_neighbours(i,j);
  55.                         // Underpopulation
  56.                         if (neighbours < 2)
  57.                         {
  58.                                 matrix_tmp[i][j] = 0;
  59.                         }
  60.                         // Overcrowding
  61.                         if (neighbours > 3)
  62.                         {
  63.                                 matrix_tmp[i][j] = 0;
  64.                         }
  65.                         // Birth
  66.                         if (neighbours == 3)
  67.                         {
  68.                                 matrix_tmp[i][j] = 1;
  69.                         }
  70.                 }
  71.         }
  72.         matrix = matrix_tmp.clone();
  73.         draw_matrix();
  74.         setTimeout("process_life()", delay_between_frames);
  75. }
  76.  
  77. // Added so we can copy the array between steps
  78. Array.prototype.clone = function ()
  79. {
  80.         var tmp = new Array();
  81.         for (var property in this)
  82.         {
  83.                 tmp[property] = typeof (this[property]) == 'object'  ? this[property].clone() : this[property];
  84.         }
  85.         return tmp;
  86. }
  87.  
  88.  
  89. function count_neighbours(i, j)
  90. {
  91.         var count = 0;
  92.         // Check for its maximum 8 neighbours
  93.         if (matrix[i][j-1] == 1) count++;
  94.         if (matrix[i][j+1] == 1) count++;
  95.         //
  96.         if (matrix[i-1] != undefined)
  97.         {
  98.                 if (matrix[i-1][j] == 1) count++;
  99.                 if (matrix[i-1][j-1] == 1) count++;
  100.                 if (matrix[i-1][j+1] == 1) count++;
  101.         }
  102.         if (matrix[i+1] != undefined)
  103.         {
  104.                 if (matrix[i+1][j] == 1) count++;
  105.                 if (matrix[i+1][j-1] == 1) count++;
  106.                 if (matrix[i+1][j+1] == 1) count++;
  107.         }
  108.         return count;
  109. }
  110.  
  111. function draw_matrix()
  112. {
  113.         for (i = 0; i < y; i++)
  114.         {
  115.                 for (j = 0; j < x; j++)
  116.                 {
  117.                         draw_matrix_point(j, i, matrix[i][j]);
  118.                 }
  119.         }
  120. }
  121.  
  122.  
  123. function draw_matrix_point(i, j, status)
  124. {
  125.         var origin_x = i * pixels_per_value;
  126.         var origin_y = j * pixels_per_value;
  127.         if (status == 1)
  128.         {
  129.                 context.fillStyle = '#00FF00';
  130.         }
  131.         else
  132.         {
  133.                 context.fillStyle = '#FF0000';
  134.         }
  135.         draw_rectangle(context, origin_x, origin_y, pixels_per_value, pixels_per_value);
  136. }
  137.  
  138. // Draw a rectangle based on x/y origin point and having a specified width and height
  139. function draw_rectangle(context, origin_x, origin_y, width, height)
  140. {
  141.         context.beginPath();
  142.         context.rect(origin_x, origin_y, width, height);
  143.         context.closePath();
  144.         context.fill();
  145. }
  146. </script>

If you have any questions .. feel free to ask :)

Click here to see the working project.


Posted in HTML, Javascript Tips & Tricks.


0 Responses

Stay in touch with the conversation, subscribe to the RSS feed for comments on this post.



Some HTML is OK

or, reply to this post via trackback.


Get Adobe Flash playerPlugin by wpburn.com wordpress themes