The Game of Life, also known simply as Life, is a cellular automaton devised by the British mathematician John Horton Conway in 1970
The universe of the Game of Life is an infinite, two-dimensional orthogonal grid of square cells, each of which is in one of two possible states, alive or dead, (or populated and unpopulated, respectively). Every cell interacts with its eight neighbours, which are the cells that are horizontally, vertically, or diagonally adjacent. At each step in time, the following transitions occur:
- Any live cell with fewer than two live neighbors dies, as if by underpopulation.
- Any live cell with two or three live neighbors lives on to the next generation.
- Any live cell with more than three live neighbors dies, as if by overpopulation.
- Any dead cell with exactly three live neighbors becomes a live cell, as if by reproduction.
Application can be divided into two parts - server and client. Server is placed in the root of the project, while client application is placed inside client folder. Client is built by React.js and it is using CRA. This application also contains worker script, which is a periodical running job for generating new cells in Game Of Life, which is located in clock/clock.js
. It contains a cron job running every 2 seconds. For persistance it is using Redis
key-value database. Socket.io
is being used for server-client communication for updating clients with new data. For authenthication, json web tokens
are being used, thus keeping the server stateless. lua
is used for Redis
scripting.
This implementation requires node.js
installed v10
or newer. You Should also have Redis
installed and running
For development you should first run install all requirements both in server and client (client folder)
$ npm install
For running server you should run in project root
folder:
$ npm start
For running react application you should navigate to client
and run:
$ npm start
For running the cron job you should navigate to the root folder and run:
$ npm start
Port 5000
is used by default for http api server, and port 3000
is used for front end application serving.
The following environmental variables can be set
Variable | description | default value |
---|---|---|
REDIS_URL |
Url of Redis instance to connect |
none / localhost |
PORT |
Port of the server application | 5000 |
Prefix |
the prefix of Redis keys. Usefull for running multiple apps connected to the same Redis instance |
none / "" |
HEIGHT |
The height of the Game Of Life table | 20 |
WIDTH |
The width of the Game Of Life table | 40 |
secret |
The secret for being | none / "" |
For testing, mocha
is used, you can find all unit tests inside test
folder. Type npm run test
for running all tests.
First we need to install dependencies, then build client application. For that just run the follwoing command inside root project.
$ npm install
$ npm run heroku-postbuild
Then application will be ready to run by:
$ npm start
Do not forget to run periodical jobs
$ node clock/clock.js
Have heroku command line toolbet ready to use and just run the following:
$ git push heroku master
For scaling application, just setup load balancer and connect to the application instances. Make sure Sticky Sessions are enabled for correct socket.io
communication.
All instances should be connected to the same Redis
instance/cluster. Redis is single threaded, and all commands are running one by one, which is preserving concurent reads. Redis PubSub
is being used for notifying data changes from Redis to server application.
At this moment the algorithm written in lua
is looping through all keys and deciding should it be revieved or killed. For the future we can just select all live cells, then select their neighbours as well, and loop only through them. Although theoretically in worst case those two algorithms will have O(width*height)
complexity, but in practice, this optimisation will behave very good, as not all cells are live