wp-content/uploads/2016/01/PBS_Logo.png

In this instalment it’s finally time to bring our Cellular Automaton prototypes to life by implementing Conway’s Game of Life. By the end of this instalment we’ll have reached a real milestone — our first web app! Granted, it won’t be a very feature-rich web app, but you have to start somewhere!

As usual, I’ve collected the code files for this instalment into a ZIP file which you can download here. As well as the ZIP file, I’ve also published a tagged release of the bartificer.ca.js code on GitHub which you’ll need for this instalment’s challenge.

PBS 41 Challenge — Sample Solution

I used the file pbs40.html from the ZIP file for instalment 40 as my starting point for the challenge.

The first change I made was to add a star rating field:

To make the form look right I also moved some things around when I added the stars, but I’m not going to focus on that kind of cosmetic change here.

Next, I added a reset button. The HTML markup is straight forward:

To make the submit button stand out stronger than the reset button I added the following CSS to make the text on the submit button bold:

Finally, I added a reset event handler to ensure all my custom validations and UI behave properly when the form gets reset:

You’ll find my full solution in this instalment’s zip file as pbs41-challenge-solution.html.

Back to Cellular Automata & Conway’s Game of Life

We’ll be using my sample solution from the challenge set way back in instalment 36 as the starting point for our work today. We’ll be updating the core JavaScript prototypes in lib/bartificer.ca.js, we’ll be adding test cases to test/tests.js, viewing the results of our tests via test/index.html, and finally we’ll update sample.html to become an implementation of Conway’s Game of Life. The sample solution is available on GitHub.

As you can probably infer from the list of files we’ll be editing, we’ll be exercising many of the skills we’ve built up throughout this series — JavaScript prototypes, unit testing with QUnit, HTML forms, and jQuery. While we won’t be focusing on it much, all the sample code will also contain JSDoc comments.

A Quick Refresher

It’s been a few months since we last worked on these prototypes, so let’s refresh our memory a little before we dive in.

Firstly — the prototypes we are building model a mathematical construct known as a cellular automaton, or CA. BTW — the correct plural is cellular automata.

A CA consists of a grid of cells, each of which has a current state. That state is just a value, and it can be anything — a number, some text, an abstract concept, anything! Like a CPU, a CA moves forward in time in discrete steps. Each time it steps forward the state of all each cell is re-calculated according so some pre-defined set of rules, and that new state can be based on the preset state of the cell itself, and the present state of all eight of the cells that touch it (referred to as neighbouring cells). What differentiates one CA from another is the set of possible states for each cell, and the rule set used to calculate the next state.

Conway’s Game of Life is a specific CA where each cell can be in one of two states, alive, or dead, and where the next state of each cell is determined by the following four rules (wording form Wikipedia):

  1. Any live cell with fewer than two live neighbours dies, as if caused by underpopulation.
  2. Any live cell with two or three live neighbours lives on to the next generation.
  3. Any live cell with more than three live neighbours dies, as if by overpopulation.
  4. Any dead cell with exactly three live neighbours becomes a live cell, as if by reproduction.

Our aim in this project is to build a collection of prototypes that can be used to add any arbitrary CA into a web page. We’ll test our prototypes by implementing Conway’s game of life.

The prototypes we’re building will be contained within the namespace bartificer.ca, and there will be two of them. The CAs generated with these prototypes will be rendered on web pages as tables — a single table representing the CA as a whole, and a table cell for each cell within the CA.

The bartificer.ca.Cell Prototype

This prototype models a single cell within a CA.

In terms of data attributes it stores a current state and a next state, its x and y coordinates within the automaton as a whole, and a jQuery object representing the cell’s <td> element within the <table>.

In terms of functions this prototype provides the usual panoply of accessor methods, and a method to move the state from the current state to the next.

The bartificer.ca.Automaton Prototype

This prototype models the CA as a whole.

In terms of data attributes it contains a grid of cells as a 2D array of bartificer.ca.Cell objects, a reference to the function to use to calculate the next state of each cell (the step function), and a reference to a function for styling a given cell so it visually represents its current state (the render function).

Add a Function to Set the Automaton State

As things stand the bartificer.ca.Cell prototype is pretty much complete.

The bartificer.ca.Automaton prototype is where we’ll be focusing our work in this instalment. As things stand the prototype can successfully store all the needed data, but it’s missing the functions to initialise the state of each cell, and to move the automaton forward one step at a time.

Let’s start by writing a function to set the state of each cell in the CA to some initial value. We’ll name this new function .setState().

This function will need one argument, the new state information, and it will need to pass the same validation as the optional sixth argument already supported by the constructor. Rather than duplicating the constructor code in both functions, we should re-factor the validation code into a private helper function that can then be called from both the constructor and the new .setState() function. In fact, I’m going to implement this as two functions, one that throws errors with detailed error messages, and one which simply returns true or false:

With these new functions written we can alter the validation check in the constructor so it simply becomes:

In theory, these changes to the code’s structure should have had no effect on the code’s functionality. That’s literally what it means to re-factor code. Before we proceed we should validate that we haven’t introduced any bugs during our refactoring by re-running the QUnit test suite (test/index.html).

We’re now ready to write our function for setting the state of a CA.

We’ll add support for specifying the state in one of three formats:

  1. A single state as a number, string, or boolean. This single state should be applied to each cell.
  2. A 2D array of states, i.e., a 2D array of numbers, strings, or booleans. This grid must have exactly the same dimensions as the CA itself, and each cell in the CA will have its state updated to match the value of the corresponding array element.
  3. A callback that takes the x and y coordinates of the cell as arguments, and returns a valid state, i.e. a boolean, number, or string. This function will be called once for each cell to determine its new state.

We now know everything needed to implement the function:

Before we can test our new function using the JavaScript console on sample.html we need to tweak the sample CA defined in that file so it renders a state of true as green and false as red. We can do that by changing line 25 from:

To:

With that change made we can enter the following in the console on sample.html to set each cell in our CA to a state of true or false at random.:

As you can see, this sets our automaton to a random state:

We should now update our constructor so it calls this function when passed an optional sixth argument. We just need to add the following to the end of the constructor:

Finally, we need to add tests for this new functionality to our QUnit test suite. We should add tests to check that both the constructor, and the .setState() function both correctly set the state of a CA.

Let’s start by adding tests to verify that the constructor successfully initialises all cells to a given state when passed a state as an optional sixth argument. I did this by adding the following code to the bottom of the ‘bartificer.ca.Automaton prototype > constructor: argument processing’ test:

Next I added a separate test for the .setState() function:

Now that we know this much of the code is working we should update our sample page so it initialises the CA to a random state automatically. We do this by updating the initialisation code in sample.html to:

Add a Step Function

Now that we can set an initial state on our CAs the next thing we need the ability to tick the CA forward by one step, updating the state of all the cells using the step function.

We’ll do that by adding a function named .step() to the bartificer.ca.Automaton prototype. This function will do the following:

  1. Loop through the entire grid and set the next state of each cell
  2. Loop through the entire grid and advance and re-render each cell

In order to calculate the next state of any given cell we need to call the step function with the current state of the cell, and the current state of all it’s neighbouring cells. This means that before we can write .step(), we need to write a function for returning the current state of all the neighbours of a given cell. We’ll name this function .cellNeighbourStates(), and have it return an array of eight cell states where the state in position zero is the one from the cell directly above the current cell, and then clockwise from there.

I think you’ll agree there is a lot of room for error in the body of this function — let’s write and run a QUnit test to make sure we got it right before we go any further!

Now that we know .cellNeighbourStates() works correctly we’re ready to write .step():

Before we go any further, let’s create a QUnit test for our new function:

To test our step function visually, let’s update sample.html to go from using an anonymous function that always sets the next state to true, to one that inverts the state of each cell. We can do this by changing the anonymous function passed to the bartificer.ca.Automaton constructor from:

To:

If we now re-load sample.html in our browser we can see .step() in action by entering the following in the JavaScript console:

This should cause every cell to invert – all the red cells should go green, and vice-versa.

Implementing the Game of Life

We’re now ready to create a step function that implements the rules of the game of life (see above).

With that function written we can again update our call to the bartificer.ca.Automaton constructor so it uses this step function. The Game of Life needs a littler more room to really work, so let’s also update our call to the constructor to build a CA with more rows and columns:

We can now advance the game of life one step at a time by repeatedly entering the following into the JavaScript console on sample.html:

Adding a Step Button

Now that we can advance the game of life one step at a time using the JavaScript console we’re ready to add a button to the page to expose that functionality to users.

First, we’ll need some HTML markup for the button. At the moment the entire <main> element is used as the container for the CA. We should move the CA into a <div> within <main> so we can also add the button into <main>. This gives us the following new markup for the main section of the page:

Note that this change in markup means we need to change the jQuery object we pass into the bartificer.ca.Automaton constructor from $('main') to $('#game_of_life_container').

With the markup added, we now need to add a click handler inside the document ready handler:

Now that our sample page implements Conway’s Game of Life, it makes sense to tweak the text a little, so with all that done, the full source for the final sample page is included below:

You’ll find a stand-alone version of this file in this instalment’s ZIP file as pbs42.html, and you’ll also find a version of it on GitHub as sample.html in the release tagged PBS42-Challenge-StartingPoint.

A Challenge

Using sample.html from the release named PBS42-Challenge-StartingPoint on GitHub as your starting point, expand the UI so it supports the following user actions:

  1. An automatic mode where the CA ticks forward by itself. It should be possible to stop and start the automatic mode
  2. A visible counter that shows the current generation count, i.e. the number of times the .step() function has been called.
  3. For bonus credit, add the ability for users to control the speed of the automatic mode.

Final Thoughts

It’s great to finally get to the point in the series where our three threads — HTML, CSS & JavaScript — have come together into an actual app. We really have created our own zero-player online game!

From a CSS & HTML point of view the next step in the series will be to learn about responsive web design, and we’ll do that using the free and open source Bootstrap 4 library. From a JavaScript point of view the next step will be to upgrade ourselves from JavaScript ES5 to ES6. When we started our explorations of JavaScript ES 6 existed, but there just wasn’t enough browser support to consider using it. Thankfully that has now changed, so it’s time we started to benefit from the improvements ES6 has to offer us.

I was in two minds which to do first, Bootstrap or ES6, but working on this instalment made that decision very easy — we’ll be looking at ES6 in the next instalment. Why? For purely selfish reasons — I’ve been using ES7 in work for the past few months, so being forced to write ES5 code now is just painful! I wish browser support was good enough to go all the way to ES7 in this series, but it’s not, so I’ll have to settle for ES6 for now 🙂