How I built Conway’s Game of Life in JavaScript

EDIT (APRIL 2020): Saddened to learn today of the death of John Conway, the British mathematician who invented the Game of Life in 1970.

EDIT (MAY 2016): Since writing this post in July 2015 I noticed it’s started to get a bit of traffic from Google. If you’re just interested in the end result, here’s a JSFiddle of my final version of Conway’s Life.  That version has cleaner and more slightly more optimised code than shown here. Original post below:

I’ve recently been focusing on strengthening my JavaScript skills, and the best way to learn a language is to build stuff, so the first challenge I set myself was to build a version of Conway’s Game of Life. It’s a simple concept; the game consists of a grid of cells, each of which can be alive or dead. For every cycle of the game, the cells can be turned on or off based on the following rules:

  • If a dead cell has exactly three live neighbours, it comes to life
  • If a live cell has less than two live neighbours, it dies
  • If a live cell has more than three live neighbours, it dies
  • If a live cell has two or three live neighbours, it continues living

By repeating the cycle over and over, these simple rules create interesting, often unpredictable patterns. I was fascinated by the idea as a kid and wrote a few versions of it in Basic on my ZX Spectrum, so it seemed like a good place to start with JavaScript.

Step 1 – Creating the grid

The grid of cells needs to be stored somewhere, so my first job was to create a two dimensional array. This was an instant stumbling block because I learned JavaSript does not support multi-dimensional arrays. However, I learned I could solve the problem easily because each element of an array can be any type of variable, including an array so, for example, I could create an array of 100 elements, and each of those would contain another 100 element array, which would give us a 100 by 100 cell grid to work with.

function createArray(rows) { //creates a 2 dimensional array of required height
var arr = [];
for (var i = 0; i < rows; i++) {
arr[i] = [];
return arr;

This function returns an array with n elements and places an empty array in each of them using a FOR loop. We don’t need to worry about specifying the number of elements in those sub-arrays, because JavaScript lets you dynamically add new elements to an array. This means we can simply add as many variables as we need when we populate the grid.

We can now create our grid by calling this function and assigning its output to a variable:

var theGrid = createArray(gridWidth);

gridWidth is a variable defined earlier in the code simply stating how big we want our grid to be – I wanted this to be easy to change because I didn’t know at this stage how quickly the game would run with large grids.

Step 2 – Populating the grid

For the sake of simplicity I wanted the starting game state to be random. So I wrote this function to randomly populate the grid array with ones and zeros, live or dead cells. Since the theGrid is a global variable (more on this decision late), we don’t need to pass anything to this function or return anything from it, we just call it directly after we have created the array.

To make this work, I had to learn how to do random numbers in JavaScript. Math.random() returns a floating point number between 0 and 1, so I poked around on StackExchange to learn how to convert that into the nice clean 1 or 0 that I wanted to fill each cell with.

function fillRandom() { //fill the grid randomly
for (var j = 0; j < gridHeight; j++) { //iterate through rows
for (var k = 0; k < gridWidth; k++) { //iterate through columns
var rawRandom = Math.random(); //get a raw random number
var improvedNum = (rawRandom * 2); //convert it to an int
var randomBinary = Math.floor(improvedNum);
if (randomBinary === 1) {
theGrid[j][k] = 1;
} else {
theGrid[j][k] = 0;

Step 3 – Drawing the grid on screen

At this stage I had only really learned core JavaScript and didn’t know anything about Canvas, other than I should probably use it for any kind of graphical output. I needed to write a function to draw each grid cell in the array as a pixel on a Canvas, so I asked the internet how to draw a single pixel on a Canvas, and then cannibalised that code to work with my drawGrid function. I hard-coded the Canvas size to 400 by 400, because I didn’t envisage using a grid larger than that and I could use a smaller grid without changing the Canvas dimensions.

function drawGrid() { //draw the contents of the grid onto a canvas
var c = document.getElementById(“myCanvas”);
var ctx = c.getContext(“2d”);
ctx.clearRect(0, 0, 400, 400); //this should clear the canvas ahead of each redraw
for (var j = 1; j < gridHeight; j++) { //iterate through rows
for (var k = 1; k < gridWidth; k++) { //iterate through columns
if (theGrid[j][k] === 1) {
ctx.fillStyle = “#FF0000”;
ctx.fillRect(j, k, 1, 1);

Step 4 – Update the grid

Now I’ve created a grid, randomly populated with living and dead cells, and drawn that grid to the screen. The next thing I need to do is apply the game rules to the current grid state, switching the cells on or off as required to create the subsequent state. This is the main chunk of game-logic.

It was easy enough in theory: we simply look at each element in theGrid array, count up the number of live cells around it (each cell has a total of eight neighbours which could be dead or alive) and then use that total to decide whether the current cell lives or dies.

The problem this creates is that you cannot update theGrid array as you’re doing this, because if you change the state of a cell that means the you’ve changed the state of the grid before you’ve finished updating all of the other cells.

The way I tried to get around this was by reading the current state of the grid from the Canvas, so I could update theGrid array whilst referencing the as-yet unchanged game-grid on the screen. Simple, update the entire array, redraw the Canvas, repeat.

I learned that the Canvas method, getImageData(), would allow me to get the current state of each pixel in the grid, so I used that to calculate the total number of live neighbours for each cell. I thought I was being clever and efficient by using this approach – I was wrong. It turns out that reading from and writing to the Canvas is relatively slow, and even using this approach for a small 100×100 grid was clunky, with maybe one or two updates per second.

So I switched to the obvious alternative – using two arrays: theGrid holds the current state of the game board, and a second array mirrorGrid is used in the update function to store the new state of the board. Once the board has been completely updated, the contents of mirrorGrid are copied to theGrid ahead of the screen being updated. The performance was instantly and significantly improved – even on a much larger grid the update cycle ran at least ten times faster.

Here’s the function which performs this:

function updateGrid() { //perform one iteration of grid update
for (var j = 1; j < gridHeight – 1; j++) { //iterate through rows
for (var k = 1; k < gridWidth – 1; k++) { //iterate through columns
var totalCells = 0;
//add up the total values for the surrounding cells
totalCells += theGrid[j – 1][k – 1]; //top left
totalCells += theGrid[j – 1][k]; //top center
totalCells += theGrid[j – 1][k + 1]; //top right
totalCells += theGrid[j][k – 1]; //middle left
totalCells += theGrid[j][k + 1]; //middle right
totalCells += theGrid[j + 1][k – 1]; //bottom left
totalCells += theGrid[j + 1][k]; //bottom center
totalCells += theGrid[j + 1][k + 1]; //bottom right
//apply the rules to each cell
if (theGrid[j][k] === 0) {
switch (totalCells) {
case 3:
mirrorGrid[j][k] = 1; //if cell is dead and has 3 neighbours, switch it on
mirrorGrid[j][k] = 0; //otherwise leave it dead
} else if (theGrid[j][k] === 1) { //apply rules to living cell
switch (totalCells) {
case 0:
case 1:
mirrorGrid[j][k] = 0; //die of lonelines
case 2:
case 3:
mirrorGrid[j][k] = 1; //carry on living
case 4:
case 5:
case 6:
case 7:
case 8:
mirrorGrid[j][k] = 0; //die of overcrowding
mirrorGrid[j][k] = 0; //
//copy mirrorGrid to theGrid
for (var j = 0; j < gridHeight; j++) { //iterate through rows
for (var k = 0; k < gridWidth; k++) { //iterate through columns
theGrid[j][k] = mirrorGrid[j][k];

Step 5 – Creating the game loop

Now I’d written all of the main components of the game: create a grid, randomly populate it, draw the current grid state on the screen, update the grid by applying the rules to each cell. What I wanted to do next is run the updateGrid() and drawGrid() functions in some kind of loop so the board would keep updating for as long as I wanted.

At first I tried simply setting up a FOR loop and calling the two functions within it for a hundred or so iterations, but this didn’t work. The code would either hang completely or take a really long time to draw just one frame before hanging. I didn’t understand why the drawGrid() function wasn’t working every time I called it in the loop.

The internet rescued be again and I learned about requestAnimationFrame(), which is ideal for this kind of problem because it makes the browser update the screen whenever it’s called. So, the function to run the game loop infinitely is like so:

function tick() { //main loop

When function tick() is called, it first draws the current state of the grid, then updates the grid, then tells the browser to update the screen and calls itself again to repeat the loop. So the flow of the code goes like this:

  1. Create an array to store the grid
  2. Create a mirror array to use when updating the grid
  3. Fill the grid with random cells
  4. Draw the current grid state to the screen
  5. Apply the rules to each cell and update the grid
  6. Keep repeating the last two steps

You can see the complete code in action here:

Obviously there are lots of refinements that could be added, such as allowing the user to pause the game, reset the grid, draw their own patterns on the grid, etc, but at this stage all I really wanted to do is get a functioning version of Life up and running. I’ll add in all the window dressing as my next project.

Performance improvements

The first thing I was keen to do is find out if there were any ways in which I could make the code run faster, so I could use larger grids without sacrificing update speed. Switching to the two-array update approach I mentioned in step 4 really made a huge difference to performance, but I thought I could learn a few things about code optimisation by trying to squeeze any additional performance from my code.

The first thing I learned was that you can use console.time() and console.timeEnd() to find out how much time different parts of your code take to execute, so I tried using it on my functions while I experimented with potential optimisations.

I read that using locally scoped variables in functions is faster than global variables, so I tried making local copies of theGrid array in both the updateGrid() and drawGrid() functions, but this didn’t seem to make any discernible difference to the execution time of either.

I’ve also read an article about pre-rendering to an off-screen Canvas before writing to the on-screen one, as this apparently improves performance, although I haven’t yet tried it as my Canvas knowledge is still shaky.

I was hoping that there would be some easy performance tweaks I could make to the updateGrid() function, as this is clearly where most of the work is taking place, but I’ve not learned anything yet that will help with that.

(EDIT MAY 2016: I tried this off screen rendering method eventually, but it made almost no different to performance. At this stage, the only way I can think of to make a JS version of this game to show significant performance is to use a better algorithm for updating the grid. I recently read about the “List Life” approach, which speeds things up by only updating the parts of the grid which feature live cells, instead of checking every single cell on each iteration. It sounds interesting, but i haven’t had time to give it a try yet. Please let me know if you produce a JS version of this, I’d love to see it. )

10 Replies to “How I built Conway’s Game of Life in JavaScript”

  1. Thank you! Very good tutorial! I think that, when filling the grid, you could use the Math.round() function, instead of the lengthy workaround, of multiplying by 2 and then getting the floor number. It removes a few lines of code, like this:
    var rawRandom = Math.random();
    var randomBinary = Math.round(rawRandom);
    theGrid[j][k] = randomBinary;

  2. It doesn’t work, because the array is declared just with one site:

    var gridHeight = 400;
    var gridWidth = 400;
    var theGrid = createArray(gridWidth);

  3. Those cases are all covered by the default outcome at the bottom of the switch statement. When you boil down the rules of Life:

    2 live neighbouring cells = a dead cell stays dead, a live cell stays live. So the current cell just remains in its existing state.

    3 live neighbouring cells = a dead cell comes to life, a live cell stays live. So the current cell is always live.

    Any other number of live neighbouring cells (less than two, more than three) and the cell dies or stays dead – which is the default outcome of the switch case, so if totalCells does not equal 2 or 3 then the current cell is always dead.

  4. all those useless vars lol.
    how about:
    theGrid[j][k] = Math.round(Math.random());

  5. Thanks for sharing the JS code and notes for “the Life”!
    Building the code with Vue js – it could greatly speed up the executions time as Vue will only updates the changing elements of the DOM.
    Might be worth to give it a try.

Comments are closed.