The developer’s task is to show the user how digital cells live and die. The author took advantage of React and its hooks: state management and the ability to abstract from state-related logic make the project easy to read and understand. We share the implementation details and code on Github while we start Frontend development course…
Rules of the game
The universe of the game is an infinite two-dimensional orthogonal grid of square cells, each of which is in one of two possible states: alive or dead (or inhabited and unpopulated, respectively). Each cell interacts with its eight neighbors – cells that are located side by side horizontally, vertically or diagonally. At each step in time, the following transitions occur:
Any living cell with fewer than two living neighbors dies of overpopulation.
Any living cell with two or three living neighbors is passed on to the next generation.
Any living cell with more than three living neighbors dies as if overpopulated.
Any dead cell with three living neighbors becomes a living cell, as if reproducing.
Try it my app, and then let’s talk about how it works under the hood.
The data structure I decided to use to represent the cells is pretty simple. Here is an array of objects:
We create a Grid display component, it is superimposed on the grid array and generates an individual cell for each object in the grid array:
gridSize stores the size of the grid. I have three default sizes: 15×15, 30×30, or 50×50. Different sizes will have different styles. Let’s take a look at the helper functions:
Now let’s look at the logic for changing the cell depending on the generation and how the game controls are connected. All the logic related to state, as well as how we manage the appearance of the grid in a particular generation, is handled in a custom hook.
useGrid contains multiple calls
useState to track the information we use to both iterate generations and control the game:
First, you need to find out if the grid has a combination of cells that you can change. The corresponding logic is located in a helper function
useGrid… I started to draw up a plan for the function using George Poya’s problem solving methods.
We bring the plan to life:
And it’s all! Let’s go to management.
So the first button here is Step 1 Generation.
Implementing the button is pretty straightforward: we have a function
stepThroughAutomata… And below we see the component
On line 13, we have the first button. We just add the property
onClick to this button and pass to it
On line 22, we have an input field that defines the iteration rate.
And finally, there is a third button, the value of which is “Start” or “Stop” depending on whether individual cells are clickable. If the cells are clickable, then the game is running. If not, the game is not running.
You might ask, “Wait a second, when I press the start button, the function
stepThroughAutomata does not start? ” Yes! JS method
setInterval doesn’t work very well with
onClick… Therefore, for this functionality, you had to create your own hook. Let’s see how it works:
Above, we are destructuring all data from
useGrid, but right below this code, we call another custom hook –
useInterval with four parameters. It:
Callback function (here –
The time between calls to the passed function, in milliseconds. Meaning
speedInputthe default is 500.
Boolean value, here
We created a hook
useInterval because the built-in setInterval function doesn’t always go well with how React re-renders components.
We need a way to know that the mesh is changing, and therefore the mesh needs to be re-rendered, and we need to make sure that it changes consistently every
n milliseconds. We can find out with the help of the built-in hook
useRef… First we initialize
savedCallback as a link.
Now let’s use
useEffectto set the current
savedCallback as the passed callback. It has to do with how
setInterval subscribes to an object
window and unsubscribes from him.
We will update
savedCallback.current every time the return value of the callback changes. This should happen every time the callback function is executed.
Moving on to the second challenge
useEffect… Let’s first check if it is true
clickable… If so, then you don’t want to run the function inside: such a launch means that the game is running right now. If
clickable – false, this means that the game is being launched for the first time. Therefore, we quickly initialize the function
tickwhich calls the currently stored callback.
Save the call result
tick and delay, and then immediately unsubscribe using an anonymous function and doing clearInterval with passing
The great thing is that the passed callback is the same function we use to iterate over one generation at a time, so the iteration algorithm is completely reusable.
Hooks allow you to write clean code that can be reused.
Defining neighbors by flattening the mesh into a vector and performing mathematical operations to find neighbors gives spatial complexity
React’s built-in re-render function allows you to create a seamless UI representation of a Life game.
You can continue learning ReactJS in our courses:
Other professions and courses
Data Science and Machine Learning
Python, web development
Java and C #
From the basics to the depth