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.
-
<canvas id="drawBoard" width="400" height="400">
-
Your browser does not support canvas.
-
</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
-
<script language="javascript">
-
// Settings
-
var x = 160; // How many cells on the X axis
-
var y = 140; // How many cells on the Y axis
-
var pixels_per_value = 4; // How many pixels wide should be a cell
-
var delay_between_frames = 400;// In ms
-
-
-
// Calculate the canvas width and height
-
var canvas_x = x * pixels_per_value;
-
var canvas_y = y * pixels_per_value;
-
-
// Create our matrix
-
var matrix = new Array(y);
-
var matrix_tmp = new Array(y);
-
for (i = 0; i < y; i++)
-
{
-
matrix[i] = new Array(x);
-
matrix_tmp[i] = new Array(x);
-
}
-
-
// Fill with some random points
-
var random = 1600;
-
var m,n;
-
for (i = 0; i < random; i++)
-
{
-
m = Math.floor(Math.random()*y);
-
n = Math.floor(Math.random()*x);
-
matrix[m][n] = 1;
-
}
-
-
// Get the canvas reference and the 2D context
-
var canvas = document.getElementById('drawBoard');
-
// Set canvas size
-
canvas.width = canvas_x;
-
canvas.height = canvas_y;
-
var context = canvas.getContext('2d');
-
-
// Draw the first cell generation
-
draw_matrix();
-
-
// Call for the next generation of the cell colony
-
setTimeout("process_life()", delay_between_frames);
-
-
-
function process_life()
-
{
-
var neighbours = 0;
-
matrix_tmp = matrix.clone();
-
for (i = 0; i < y; i++)
-
{
-
for (j = 0; j < x; j++)
-
{
-
neighbours = count_neighbours(i,j);
-
// Underpopulation
-
if (neighbours < 2)
-
{
-
matrix_tmp[i][j] = 0;
-
}
-
// Overcrowding
-
if (neighbours > 3)
-
{
-
matrix_tmp[i][j] = 0;
-
}
-
// Birth
-
if (neighbours == 3)
-
{
-
matrix_tmp[i][j] = 1;
-
}
-
}
-
}
-
matrix = matrix_tmp.clone();
-
draw_matrix();
-
setTimeout("process_life()", delay_between_frames);
-
}
-
-
// Added so we can copy the array between steps
-
Array.prototype.clone = function ()
-
{
-
var tmp = new Array();
-
for (var property in this)
-
{
-
tmp[property] = typeof (this[property]) == 'object' ? this[property].clone() : this[property];
-
}
-
return tmp;
-
}
-
-
-
function count_neighbours(i, j)
-
{
-
var count = 0;
-
// Check for its maximum 8 neighbours
-
if (matrix[i][j-1] == 1) count++;
-
if (matrix[i][j+1] == 1) count++;
-
//
-
if (matrix[i-1] != undefined)
-
{
-
if (matrix[i-1][j] == 1) count++;
-
if (matrix[i-1][j-1] == 1) count++;
-
if (matrix[i-1][j+1] == 1) count++;
-
}
-
if (matrix[i+1] != undefined)
-
{
-
if (matrix[i+1][j] == 1) count++;
-
if (matrix[i+1][j-1] == 1) count++;
-
if (matrix[i+1][j+1] == 1) count++;
-
}
-
return count;
-
}
-
-
function draw_matrix()
-
{
-
for (i = 0; i < y; i++)
-
{
-
for (j = 0; j < x; j++)
-
{
-
draw_matrix_point(j, i, matrix[i][j]);
-
}
-
}
-
}
-
-
-
function draw_matrix_point(i, j, status)
-
{
-
var origin_x = i * pixels_per_value;
-
var origin_y = j * pixels_per_value;
-
if (status == 1)
-
{
-
context.fillStyle = '#00FF00';
-
}
-
else
-
{
-
context.fillStyle = '#FF0000';
-
}
-
draw_rectangle(context, origin_x, origin_y, pixels_per_value, pixels_per_value);
-
}
-
-
// Draw a rectangle based on x/y origin point and having a specified width and height
-
function draw_rectangle(context, origin_x, origin_y, width, height)
-
{
-
context.beginPath();
-
context.rect(origin_x, origin_y, width, height);
-
context.closePath();
-
context.fill();
-
}
-
</script>
If you have any questions .. feel free to ask
Click here to see the working project.
Latest Comments