Implementing Conway’s Game of Life With React — Part 2

Miguel Furtado
Runtime Revolution
Published in
6 min readOct 11, 2018

--

Photo by Jeremy Bishop on Unsplash

In part 1 of implementing Conway’s Game of Life, we learned about React and one of the things it can be used for. We also learned what Conway’s Game of Life is, along with its rules. Afterwards, we went on to the wonders of starting our React project, implementing the structure and visual aspects of our game. The end result was this:

Game View

Currently we are displaying the board and the header that allows us to manipulate the look of our board. We can also start and stop the game. Still, even if it is looking amazing(!), it doesn’t do what we want it to, which is to actually run the game.

In part 2 we are going to focus more on the logic of the game. Here is where we are going to apply the rules that we learned about in part 1.

You can find the code for the project here.

To host your game you can use the web platform Netlify. If you wish to try the game you can do it here.

Implementing The Game Logic

Before we get into the actual implementation of the game, there’s one thing that I should mention: this is not the “best” way to implement the game logic and board representation. Ideally we would use Hashlife, but at present I am not familiar with it enough to properly implement it (who knows, maybe there will be a blogpost about it). With that in mind, any suggestions to improve the code and game logic are welcome and appreciated.

So let’s get started. First thing first, we focus on our Universe.js file. This is where we will define the logic. A few things to have in mind, we need something to represent a generation, each loop that changes the state of the board, and also something that represents the state of the next generation. We are going to need to have something that identifies our live cells and dead cells. Therefore the basic setup for our class will be the following:

The first thing that I believe is important to define is what is in our constructor. This is going to be the entry point for each generation, so it’s good to define what we need for it to work, be it the first or 1000th time being generated.

Before going into detail on what the functions will be used for, let’s remember the 4 rules of the game:

  1. A live cell with less than two live neighbours dies.
  2. A live cell with two or three neighbours lives on to the next generation.
  3. A live cell with more than tree neighbours dies.
  4. A dead cell with exactly three neighbours is reborn and becomes a live cell.

Now that we have recalled the rules, let’s get into the details of what the functions actually do.

  1. getGeneration will give us the current generation we are in.
  2. getLiveCells will give us a Map of the live cells in each generation.
  3. addCell will take a cell position (we will get into this with further detail later) and add it to the Map of liveCells.
  4. removeCell will remove a cell from the Map of cells.
  5. isCellAlive will receive a position and lets us know if a cell is alive or not.
  6. storeCell will receive a position and it will be used in the behaviour of an individual cell. This last one will allow the user to set the initial state of a cell and the board.
  7. addGeneration is the one that will allow, in each generation, to calculate the new live and dead cells and, of course, the new Universe.
  8. calculateLiveCellsNeighbors will receive a position and, like the name suggests, calculate our live cells for the next generation, and also take into account the neighbors that each live cell has.
  9. calculateDeadCellsNeighbors will receive a position and calculate the dead cells that are going to remain dead or be reborn.

Let’s start implementing them. First we focus on getGeneration, getLiveCells, addCell, removeCell and isCellAlive. Change your Universe.js to look like this:

The position object will be used to let us know the position of a cell. This object has x and y coordinates to represent where it is located in a two dimensional space. This will also help us to calculate the live and dead cells.

Next up is to implement the storeCell function. This one will be used later in the App.js component. Add the following code to the storeCell function.

As you can see in the return statement, we are returning a new universe. This is what allows us to re-render the board on our App.js component.

It’s time to implement the real stuff that will actually use the rules. So for this let’s define the addGeneration function.

This function will be used to access the functions that will let us know the live cells for the next generation. In the end it will return the new Universe with the current generation value and the next generation of live cells.

After defining this, let’s focus on applying the rules to the live cells, finding the neighbors for each live cell, and determining what their next state is. Add the following to the calculateLiveCellsNeighbors function.

Finally, we check what will happen to all the dead cells that we discovered while applying the rules to the live cells in the previous function. The logic is similar to the calculateLiveCellsNeighbors so I won’t go into too much detail. In the calculateDeadCellsNeighbors function add this:

Alright! Our logic for the game is complete! But it still doesn’t do anything. This is since in our App.js component we aren’t using any of this logic. So let’s start by adding it. First thing to do is import our Universe file. Add the import to the top of your component import Universe from './logic/Universe';. Now we can access its functions.

Do you remember the runGame function? Well, it’s one of the most important since it will run the logic and give us our universe for each generation! So let’s add some stuff to it and our component state.

Now we focus on how we are building our board. Currently we are using our renderBoard function to render the board, but this one doesn’t account for a cell being either dead or alive. Let’s change it up so that it can properly display this.

Here we are passing down a new function, storeCell that used the one we defined in our Universe.js with the same name. Let’s add it so our cell component knows what this function is.

Our Cell component still needs to know what he is receiving and what do to with this new information. We have to change the component to the following:

Also for this to work we need to update our App.css file since we are not using the .cellContainer class anymore. So remove the .cellContainer and add the following classes instead.

The only thing missing now is updating our render function to show the current generation. So change it to look like this:

That’s about it, time to run the game and see what it looks like! So head over to your console and start your project or try the game here. In the end using the most know pattern, R-pentomino, it should be behaving like the video:

This marks the end of this series. I hope it managed to give some insight into React, along with the implementation of Conway’s Game of Life. Any feedback/suggestions or doubts are welcome and appreciated.

Happy programming.

I love building products and I found my place to do so at Runtime-Revolution. If you are interested in who we are and what we do, make sure to reach out!

--

--