Create Conway's Game of Life on the HTML5 canvas

Spicy Yoghurt | Last updated: 25 May 2020 | JavaScript tutorial

Create Conway's Game of Life in JavaScript

Learn how to create Conway's Game of Life on the HTML5 canvas with JavaScript. Implement the game rules and check which cells will live or die each generation, to create your own simulation of life!

Conway's Game of Life

In 1970 the mathematician John Conway invented The Game of Life. It's not so much a game as you know them, it's more like a simulation (the more technical term would be cellular automaton). The game consists of a grid of cells, who can all be either dead or alive. Every step of the game, the grid will evolve and determine who will keep living and who will not.

Your browser does not support the HTML5 canvas tag.
Restart

The game requires no input, except for an initial state of the cells. All cells apply a set of rules each step of the evolution to determine their fate.

The game rules

The rules a pretty simple. Every cell observes its surrounding neighbours to check whether its living area is underpopulated, overpopulated or suitable to live in. Each cell has 8 neighbours (except for the ones at the edge of the canvas).

  • A dead cell will come alive if exactly 3 neighbours are living
  • A living cell will stay alive if 2 or 3 neighbours are living
  • Cells with less than 2 neighbours will die of underpopulation, cells with 4 or more neighbours will die of overpopulation

You can play this game on paper and think of initial starting states that will result in interesting shapes or even moving objects. Real fanatics are even looking for so called guns and spaceships (or gliders), patterns that will emit cells or look like a moving object. Here's an example of a Gosper glider gun:

An animated GIF of a Gosper glider gun creating gliders

For this tutorial you're not going to use paper, but going to create The Game of Life with JavaScript on the HTML5 canvas and generate starting positions and new generations through code.

Define the appearance and behaviour of a single cell

Let's start by creating the framework for a single cell. It doesn't have to be smart, it's just a square on a grid that can be either alive or dead. Each state will be drawn with a different color.

When a new cell is created, its state of being is determined randomly. A cell has about 50% chance to start alive, but you can easily tweak that percentage to create different starting situations.

Start by creating a new Cell class and implement a draw() method. You can choose to draw a square or go for another shape, like the circles used in this tutorial.


            class Cell
            {
                // Set the size for each cell
                static width = 10;
                static height = 10;

                constructor (context, gridX, gridY)
                {
                    this.context = context;

                    // Store the position of this cell in the grid
                    this.gridX = gridX;
                    this.gridY = gridY;

                    // Make random squares alive
                    this.alive = Math.random() > 0.5;
                }

                draw() {
                    // Draw a square, let the state determine the color
                    this.context.fillStyle = this.alive?'#ff8080':'#303030';
                    this.context.fillRect(this.gridX * Cell.width, this.gridY * Cell.height, Cell.width, Cell.height);
                }
            }
        

Build a grid with a lot of cells

Once you have your cell framework ready, you can start to create a lot of cells. You're going to build a grid of 75x40 items. That's 3000 cells in total! The grid has the right measurements to completely fill the canvas element since each cell is 10x10 pixels and the canvas is 750x400. You can create a new grid of cells with a nested for loop:



        this.gameObjects = [];

        createGrid()
        {
            for (let y = 0; y < GameWorld.numRows; y++) {
                for (let x = 0; x < GameWorld.numColumns; x++) {
                    this.gameObjects.push(new Cell(this.context, x, y));
                }
            }
        }
        

Add a game loop to repeat all operations

The creation of new generations of cells doesn't happen just once, it has to happen for hundred of times. You need a way to keep calculating the current situation. A loop would be perfect for this. In games, a core loop like this is called a game loop.

There are a lot of ways to create a game loop, but a really robust way of doing it is by using requestAnimationFrame(). We have a nice tutorial on game loops if you're looking for a more in-depth explanation. Here's a example:


        // Start your loop for the first time
        window.requestAnimationFrame(() => this.gameLoop());

        gameLoop() {
            // Check the surrounding of each cell
            this.checkSurrounding();

            // Clear the screen
            this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);

            // Draw all the game objects
            for (let i = 0; i < this.gameObjects.length; i++) {
                this.gameObjects[i].draw();
            }

            // The loop function has reached it's end, keep requesting new frames
            setTimeout( () => {
                window.requestAnimationFrame(() => this.gameLoop());
            }, 100) // The delay will make the game easier to follow
        }
        

In this example the loops starts by checking the surroundings of each cell, it then draws all cells to the canvas. It has a small delay build in before requesting the next frame, to make the evolution of the game easier to follow.

If you want to learn more about drawing graphics on the HTML5 canvas, check out this tutorial.

Check the surrounding cells

For every step in the evolution of this Game of Life, all cells need to check their neighbours to see if their area is under- or overpopulated. You can do this by looping over all cells and check how many neighbours are alive per cell.

Counting living neighbours

In the example above, the red cell is the one currently checking its environment. It should count all green cells as living and exclude itself, coming to a total of 3 living neighbours.

You'll need to build in some safety to skip checking beyond the edges of the grid. All cells beyond the grid count as being dead.


        checkSurrounding ()
        {
            // Loop over all cells
            for (let x = 0; x < GameWorld.numColumns; x++) {
                for (let y = 0; y < GameWorld.numRows; y++) {
                    // Count the nearby population
                    let numAlive = this.isAlive(x - 1, y - 1) + this.isAlive(x, y - 1) + this.isAlive(x + 1, y - 1) + this.isAlive(x - 1, y) + this.isAlive(x + 1, y) + this.isAlive(x - 1, y + 1) + this.isAlive(x, y + 1) + this.isAlive(x + 1, y + 1);
                }
            }
        }

        isAlive(x, y)
        {
            if (x < 0 || x >= GameWorld.numColumns || y < 0 || y >= GameWorld.numRows){
                return false;
            }

            return this.gameObjects[this.gridToIndex(x, y)].alive?1:0;
        }

        gridToIndex(x, y){
            return x + (y * GameWorld.numColumns);
        }
        

Implement the game rules

Now that you know how many cells are alive, you can implement the game rules. Basically they boil down to these three conditional statements:

  • A cell with 2 living neighbours keeps its current state
  • A cell with 3 living neighbours always comes alive
  • Every other cell ends up dead

When you translate this into code you'll end up with something like this:


                let centerIndex = this.gridToIndex(x, y);

                if (numAlive == 2){
                    // Do nothing
                }else if (numAlive == 3){
                    // Make alive
                    this.gameObjects[centerIndex].alive = true;
                }else{
                    // Make dead
                    this.gameObjects[centerIndex].alive = false;
                }
        

What's going wrong here?

Ok, that's it! You should have a running example now. Let's check it out in the canvas below.

Your browser does not support the HTML5 canvas tag.

That's odd, it's not looking like the patterns you would expect coming from The Game of Life. The cells aren't behaving like they're supposed to, their evolution seems to be a bit too aggressive.

Calculate each generation simultaneously

The solution is to not change the current state of any cells when you're still checking their surroundings. Only change the state when all cells have been checked, so the whole new generation is created simultaneously. It's quite easy to implement by temporarily storing the new state of a cell and applying it after all cells are checked. Here's an example:



            if (numAlive == 2){
                // Do nothing
                this.gameObjects[centerIndex].nextAlive = this.gameObjects[centerIndex].alive;
            }else if (numAlive == 3){
                // Make alive
                this.gameObjects[centerIndex].nextAlive = true;
            }else{
                // Make dead
                this.gameObjects[centerIndex].nextAlive = false;
            }

            // Apply the new state to the cells
            for (let i = 0; i < this.gameObjects.length; i++) {
                this.gameObjects[i].alive = this.gameObjects[i].nextAlive;
            }
        

When you try to run you game again, the simulation will look a lot different. It should now resemble the example at the top of this page. Well done, you have your own Game of Life running!

Experiment with different variations

You can experiment a bit further and try different colors, shapes, or even game rules. A fun one is to keep count of how long a cell has been dead and assign a color to each level of decay, so you get a nice fade-out effect. Here's a quick example:

Conclusion

The Game of Life is a cellular automaton that can easily be implemented through code with JavaScript. The game rules decide which cell will live or die and this results in interesting patterns. With a game loop and just a few conditional statements you can make your HTML canvas come alive!

That's all for now, if you liked this tutorial or have any questions, please let us know in the comment section! You can download the final code here.

Leave a comment