Project 1: The Game of Life

Explore the worlds of cellular atomata & artificial life in a one page app using HTML, CSS and JavaScript. It’s time to integrate your skills, that is markup, style and behavior, all in one page, by creating an interactive and dynamic application right in your browser. In this project we’ll make heavy use of the DOM, events, timing and simple logic to create a truly generative application.

Start Here

Welcome

Welcome to Project #1: Building the Game of Life. If this is your first project you can get started by reading the “Start Here” section and then proceed down the page as you complete each section. Good luck, and remember the community is here if you need help (or want to give help). Hint: you’ll find the community chat icon at the top of any section that is expanded.

Start Here

Ready to take all your HTML, CSS and JavaScript knowledge and focus it on building an interactive, dynamic one-page app right in the browser? Us too.

Don’t worry, we’re not going to implement just any old toy application, some boring payroll example, or some other less-than-exciting project. No, we’re going to implement something truly interesting—The Game of Life. What is The Game of Life? We’ll give you the full run down on that, but before we do, let’s first talk about what you need to complete this project in the next section.

Prerequisites & Tools

Before we actually get started, let’s talk about what do you need to know to take on this project. First up: HTML and CSS. Now, we don’t use a lot of HTML and CSS but you should know the basics. If you’re in need of a quick review, focus on how to use ids and classes (in HTML and for selecting in CSS), how to build a table, and generally how the Document Object Model (the DOM) works.

You’ll also need to understand the fundamentals of JavaScript programming; we’ll be using functions, loops, arrays, and, because this is a web app, we’ll also be manipulating the DOM and handling events using JavaScript code. If you’ve read an introductory JavaScript book, you’ll be prepared; of course, we’re partial to Head First JavaScript Programming, and if you’ve read Chapters One through Ten, you’ll be in great shape to take on The Game of Life.

Tools

So what tools do you need to complete this project? Simple: one or more modern browsers (the latest version of Chrome, Firefox, Safari, or IE will do just fine) and any editor. On this latter point we’re agnositic: if you love IntelliJ, good for you. If a stripped down text editor or vi is your thing? More power to you. Just make sure whatever editor you use is either designed specifically for HTML, CSS and JavaScript programming, or is in “plain text” mode (that means, don’t use Microsoft Word!).

What about source code?

You can download all the completed code for this project from github. However, resist the urge. By writing the code yourself as you progress through the project, the concepts will sink in more deeply and you’ll build better mental muscle memory. We’ll also be prompting you to try to figure some of it out on your own, which will help the concepts sink in even further. If you get stuck, first try the community, then as a last resort fall back on the source code.

With that out of the way, let’s get warmed up with a little exercise in the next section.

Exercise

You probably know what an algorithm is. It’s a set of instructions for getting something done. And, you might assume that to do interesting things, you need a complex algorithm, right?

Not so! In fact, in this project we’re going to use a very simple algorithm, and with it, we’ll get some interesting and unintuitive results. And, to demonstrate this, let’s start by doing a little Gedankenexperiment, otherwise known as a thought experiment:

Consider a sheet of graph paper and imagine that each square on the grid can hold a living cell. For every square on the grid, the cell can be in one of two states: living or dead. If the square holds a living cell it is filled in, otherwise it is blank.

Now take several pieces of graph paper (or at least imagine you are), and grab a pencil. On each sheet, using the graph paper lines, mark off a square grid, say 25×25 squares. Now, on the first sheet randomly draw a small circle in some of them (and not others). The circles indicate those squares have live cells in them. We recommend filling in about 25% of the squares.

Now, referring to first sheet, fill in the cells of the grid of the second sheet, by following this algorithm. For each cell on the first sheet:

  1. If a cell has fewer than two living adjacent neighbors then the cell dies, by under-population. If a cell dies, don’t mark it on the second sheet.
  2. If a cell has two or three live neighbors, it lives on to the next generation, so mark it on the second sheet.
  3. If a live cell has more than three live neighbors, it dies because of overcrowding, so don’t mark it on the second sheet.
  4. Finally, if any dead cell has exactly three live neighbors, it becomes a live cell by reproduction, so mark it as live on the second sheet.

Repeat this algorithm for every cell on the first page. Then, repeat the process by using the second sheet as the basis to run the rules above, and mark the third sheet, and so on.

Now, you have to admit that while this algorithm might be tedious it is nevertheless straightforward, with just four simple rules. Of course, you don’t have to go to all the trouble of computing the algorithm by hand, unless you really want to, because we’ve already done it for you. Take a look at the following video where we show our results, straight from the WickedlySmart Lab. As you watch, make sure to pay attention to how the grid changes over time:

Making some Observations

So after trying this little experiment (and viewing the video in the previous section):

  • Did anything surprise you?
  • Did the grid stay populated with live cells longer than you expected?
  • Did you see any interesting cell configurations?
  • Perhaps you saw cell configurations that seem to stabilize for long periods of time?
  • Perhaps you saw cell configurations that seem to move?
  • Did you expect this behavior from four simple rules?

If you didn’t catch some of these behaviors, go back and watch the video a few times before proceeding to the next section.

Field Trip

It’s time for a little excursion to find out a little more about this “Game of Life” and where it comes from. It looks like we have your field trip permission slip signed, so off you go. When you return, the next section will be waiting for you. Have fun!

What’s the Plan?

Let’s take a quick look at what we’ll actually be building in this project. After that we’ll get a game plan together for how we’re going to tackle the task of building it.

Game of Life Walk Through

Let’s take a look at what this project is going to look like when we’re finished. In this video we’ll step through all the ins and outs of this simple interface for the Game of Life.

After viewing, the next section is already waiting on you…

Game Plan

We need a game plan. In technical terms we want to build a one-page browser-based app that implements the Game of Life. So how should we approach building it? We’re going to use a common technique used to build apps that breaks the problem down into three components:

The first component is going to be the view we see in the browser. This is largely going to be done using HTML and CSS, and will provide us with a visual, clickable grid as well as a set of buttons to control the game.

Next we’ll have some code that just worries about handling the user’s actions, whether the user is clicking on the grid, or one of the buttons. Say, the user clicks on a cell in the grid, this code make sure everything happens behind the scenes to reflect that change in the grid.

Finally, we have the data structure (some people call this the model), which tracks the state of the grid, and knows how to compute future generations of the grid.

Now that you’ve got the big picture of how we’re going to approach this, let’s get started first on the grid view by creating some markup and style. As you’re going to see we’ll ultimately need a little code to get our view on screen as well.

Audience Question

Are we using Model-View-Controller (MVC) to structure this project?

Yep. Model View Controller, or MVC for short, is a design pattern used widely in many systems. MVC gives you a way to structure your implementation so there is a clean separation between your view code, the code that deals with controlling the app, and the underlying data, or model, used in your app. Why would you go to all that trouble? Experience shows it makes your code way more maintainable.

We’re going to lightly adhere to this structure for this code as the real goal of this project is building a single page app that integrates what you know about HTML, CSS and JavaScript.

Let us know if you’d like to see a project that focuses on MVC, and, should the topic interest you, you can find more information on MVC at the Portland Pattern Repository’s Wiki.

Create the View

Let’s lay the groundwork for our Game of Life interface by building the first part of our view with HTML and CSS. We’ll be building on this as we progress.

HTML - Coding the Markup

As we said, we’ll begin with the markup for our Game of Life page, and we’re going to keep it quite minimal because our focus in this project is on the interaction between the markup, the style and the behavior and not on writing fancy web pages. We don’t need a lot of HTML and CSS; to code a compelling Game of Life, all we really need is a basic grid.

So first, let’s get all the required HTML out of the way:

As just a quick flyover, notice that we’re linking to a CSS file, “life.css” (which we’ll get to next), and that we’re also including a JavaScript file, “code.js”, at the bottom of the page. By placing the JavaScript at the bottom of the page we can ensure the rest of the page is loaded (and, more importantly, the DOM has been created) before the JavaScript begins its execution.

Now let’s look more closely at the body of the HTML. The structure is quite simple. It consists of two <div> elements: one with an id of gridContainer, that will hold the grid, and another with an id of controls to hold our buttons to control the game. We’re going to begin with start and clear buttons, and add a random button later in the project.

Going back to the grid, right now all we have is a simple div that is going to hold the grid. We obviously don’t have a grid yet, and how are we going to represent the grid anyway? We’re going to use an HTML table. Now we could just type in a table with hundreds or thousands of table cells in now, but instead, we’re going to use our programming skills to write code to do it for us. That is, we’re going to create the grid dynamically, using JavaScript. Not only is that going save us a lot of typing, it also makes the job of creating grids of different sizes easier.

So, for now, go ahead and create your HTML file. We’ll create the “life.css” file in the next section, and then we’ll start tackling the JavaScript to create the grid dynamically.

CSS - Adding some Style

Now let’s create a style file for the Game of Life. We do have a bit of a chicken and egg problem in that most of the CSS provides the style for our grid, but we don’t have a grid yet. So, here’s what we’re going to do: we’re going to create a file, “life.css” in the same folder as the file where your HTML is, and enter the CSS. Then, once we’ve written the code to generate the grid we’ll come back and take another look at the CSS. That said, do pay attention as you enter the CSS; as you’ll see, most of the properties relate to styling a table to look like a grid as well as styling the dead and live cells.

After you’ve created the “life.css” file and entered the CSS proceed to the next section.

Deep Thoughts

You already know we’re going to use a table to represent our grid—that is, we’re going to use HTML’s <table>, <tr>, and <td> elements to implement the visual aspect of the grid. Given your general knowledge of browser technologies (HTML, CSS, etc.), can you think of other ways we might have approached creating a grid?

What do you think are the advantages and disadvantages of these various approaches?

Answers, think of your own before reading.

Here’s our thinking:

We could use a proprietary technology, like Adobe Flash, which could result in a fantastic user experience—that is, for those users who can actually run Flash (some mobile platforms, for instance, would be an issue). Also, maintainability might also be an issue given not as many developers are working with Flash these days.

Another option would be to use the HTML Canvas element. This would be an excellent option for displaying the grid and would most likely result in faster performance for the grid updates. In fact, the only reason we didn’t use the Canvas is because we wanted this project to focus on integration of the HTML, CSS and JavaScript, without the distraction of other technologies.

Did you come up with any others? Feel free to discuss in the forum (use the community icon above).

Create the Grid

It’s time to write some code. In this module we’ll cover everything about the grid, how to create it and how it is going to work. And by the end of the section we’ll have a lot of groundwork complete.

UI Design

So we have everything set up in our HTML page, except the actual grid. Remember, we’ve got some CSS already set up to style the table, but we still need the HTML. In this video we’ll take a look at how we’re going to represent the grid as an HTML table, and rather than entering a huge set of table elements by hand, we’ll be writing code to do that for us, which we’ll get to in just a sec…

Overheard on the Forum
Okay, I get we’re going to make the grid out of a <table> element, and we’re going to somehow do it programmatically using JavaScript. But what exactly does that mean, and why aren’t we just typing the markup in?
You don’t want to type it in by hand, that would require typing hundreds of table elements. Not only would it take forever, that sounds very error prone!
We are programmers; there’s no reason to type all that in. We can do it with JavaScript DOM methods, like document.createElement(), and then create the <table> element and all the <tr> elements for the table rows and the <td> elements for the table cells with code.
Okay, I think I get it, sorta. So if we know how big the grid is, we can just step through the rows and columns and use the DOM methods to create the various elements we need?
Right. More precisely, you’d use createElement() to create each element and the appendElement() method to add them to the DOM.
Don’t forget too, we’ll need to figure out how to use the CSS classes we’ve already set up.
I don’t think it’ll be too bad. We should really think through everything we need before we jump into the code. That way we’ll have no surprises.
That works for me!
Exercise: Try creating the grid

You now know the approach we’re going to use to create a grid using HTML tables. Make a quick sketch or write some pseudocode for how the table is going to be created. Remember to take into account that we might want to be able to create grids of different sizes, so you might need a couple of variables, say rows and cols, to represent the number of rows and columns respectively.

If you aren’t that familiar with dynamically creating DOM elements with JavaScript, don’t worry; just think through how this might work and write some quick pseudocode.

After you’ve sketched out your own version of this, we’ll implement the code together in the next section.

Programmatically creating the Grid

Now that you’ve thought about how you might generate the table, let’s work through writing the actual code. First, you’ll need to create a new file, “code.js” to hold your code. You’ll want to place “code.js” in the folder with your HTML and CSS. Remember, you’ve already linked to this file from your HTML. Now let’s work through the code to generate the grid:

It’s time to get this code typed in to your “code.js” file. Here’s the source (but remember, we encourage you to type it in yourself):

Crash Test

At this point you should have a set of files, including “index.html”, “life.css”, and “code.js”, all in the same folder. Open “index.html” in your favorite browser. If all goes well you’ll see a nice grid displayed on your page with two control buttons.

Follow along as we test our grid:

If you don’t see a nice grid, then here are a few things you can do to debug the situation:

  1. Make sure you’re using a modern browser.
  2. Double check all your code, markup and JavaScript for missing elements or typos.
  3. Make use of your JavaScript console to see if there are any error messages.
  4. Finally, reach out to the forum if you are really stuck.
Audience Question

I heard that global variables are evil in JavaScript, yet you seem to be using them. How come?

It’s true, global variables can cause problems when you’re coding. The issue is this: how can you be sure your global variable names aren’t the same names someone else is using? Take rows, for instance; you’d think that might be a fairly common variable name, and if you happen to load in some external libraries, you could be in real trouble if two sets of code are using the same variables.

In this project, however, our focus is quite narrow: we’re working on integrating a set of technologies (namely, HTML, CSS and JavaScript), and we’re keep the implementation quite simple; that is, we’re not using any external libraries and we’re building a very small code base. So, we won’t run into any conflicts with our global variable names.

That said, we’ll focus on using best practices around variable names, scope, modules and external libraries in an upcoming project (including using functions to hide variables). You can refer to Head First JavaScript Programming for a discussion of global variables in the mean time.

Interact with the Grid

Our grid is in place, but it’s just sitting there, staring at us, doing nothing—if only we could interact with the grid to turn on some cells. In this module we’re going to do just that by adding a click handler and then using our CSS powers to turn on and off cells.

How to turn on a cell

In just a sec we’re going to wire up our grid so we can click on it. But before we do, let’s have a look at how we’re going to leverage our existing CSS to turn cells (visually) on and off.

Do you know your Events?

Remember that the DOM allows you to assign handlers to various events. Handlers are just functions that get called when the event occurs. Do you remember the event you’ll need to react to a click event on an HTML element? Try your luck below:

onload

onclick

onmouseover

onkeypress

Adding a click handler

Now it’s time to add a click handler to our code so we can add live cells to the grid. Here’s what we’re after: we want you to be able to click on a dead cell to change it to live, and then click on it again to change it back to dead (in case you change your mind). Remember, to do that, when a cell is clicked, our handler is going to make use of the two CSS classes live and dead. So, the click handler will be responsible for checking the state the cell, that is, live or dead, and then setting the cell to the opposite state (dead or live).

Follow along with the video to add the click handler to your code:

Here’s the full code:

If you’ve got it all added to your “code.js” file, move on to the next section where we test the code.

Crash Test

Let’s test the code to add live cells to the grid. Reload the page and try clicking on cells in the grid. If you click on an empty cell—that is, a dead cell—you should see it come alive. If you change your mind, just click on the cell again to change it back to dead.

Here’s what our test looks like:

Deep Thoughts

We’ve visually added live cells to the grid, so you can see when a cell is live or dead. But, so far, our grid doesn’t actually do anything interesting. Think at a high level about what we still need to do to turn this visual representation into the Game of Life? What are the steps? Think about the model-view-controller design we talked about up front; how does what you’ve done so far fit into that?

Take a Break

Okay, it’s time to take a breather and let everything sink in. After all, you’ve already got a lot of the foundation poured for the Game of Life. So, before we move on and start implementing the game logic, how about a little inspiration?

Grab your favorite beverage or snack and watch this video clip. Sorry, here’s a spoiler alert: this video shows the Game of Life implemented in the Game of Life. Prepare to have your mind blown:

Handle Button Clicks

The buttons give us a way of controlling the flow of the Game of Life–we can start the game, stop it or continue computing new generations. We can also wipe the grid clear and start over. We’re going to setup some handlers to do some work when the user clicks on the buttons. Then in the following modules we’ll implement their complete functionality.

How to Handle the Button Clicks

Our grid is in place, and we can add live cells to the game; now it’s time to get the buttons set up. In this module we’re going to get the button handlers in place, and the initial button states working. Then, in later modules, we’ll start filling in the game play. Before we dive into the button handler code though, let’s prepare by making sure we know exactly how the buttons are going to work in the video below:

Exercise: Designing the Button Handers

No pressure, but let’s say you’re in front of the whiteboard, your teammates gathered around you, and you need to do a little whiteboard sketch and pseudocode to show how the button handlers are going to work. Remember, the Start button is doing triple duty: it serves as a Start button at the beginning of the game, and after you’ve hit Clear. Once you start the game, however, it changes to Pause. And if you click the button while it is the Pause button, then it changes to a Continue button.

Also make sure you are considering a variable to keep track of whether the game is running or not. We’ll call it playing. The playing variable should initially be set to false; when you click the Start button, then playing should be set to true. And, when you click Pause then playing should be false. Clicking Continue sets playing goes back to true again. And finally, if you click Clear, then playing is set to false again. So there’s a lot to keep track of here.

To sketch out how this is going to work, use whatever method you like: a diagram, some pseudocode, whatever works for you. Don’t stress if you don’t think you have it all; you’re just trying to wrap your brain around everything the handlers need to do. After you’ve completed this exercise, proceed to the next section and we’ll work up some code together.

Implementing the Button Handlers

Okay, let’s write some code. Watch the video below and follow along in your own code.

Here’s the full code:

Get the new code added to your “code.js” file if you haven’t already and we’ll test it next.

Crash Test

Let’s test the buttons. When you reload the page, the buttons should be Start and Clear.

Click on the Start button. The button should change to Pause. That means the game is playing (and the playing variable is set to true). You should see “Play the game” in the console. Click Pause and the button should change to Continue, and playing will be false again. Finally, click Clear and the button on the left should read Start again, and playing should be false.

We’ll go through all of this in the video, so follow along below and make sure your code is working in the same way.

Create the Grid Model

We’ve got the view and the controllers mostly complete. Now what we need is our model. The model is where we’re going to store the state of the game. This is where we’ll keep track of the live and dead cells for computing the next generation of cells.

A Little Architecture: the Model

We have a view—that is, a visual interface for our game—and we have a way to add live cells to the grid and some buttons to control the game, so now we need a way to store the state of the game. The state is the information about which cells are alive and which cells are dead in the grid. We need this state to play the game. Right now we have the information about which cells are alive and which are dead in the HTML and CSS—that is, in the view—but this is just our visual interface. Where we really need it is in a model.

Remember the exercise you did earlier with the graph paper? You took one piece of graph paper and filled out some of the cells to make them alive. You can think of this as the state of the grid. Then you applied the rules of the game to this piece of graph paper, and stored the next state on a new piece of graph paper.

We’re going to do exactly the same thing with our code. Only instead of using graph paper to store the state, we’re going to use two arrays. We’ll use one array for the state of the grid as it is now (and as you see it in the view), and we’ll use a second array to store the next state of the grid as we apply the rules of the game.

These two arrays, and the functions we use to apply the rules of the game to the state stored in these arrays and to generate the next state, are called the model.

Overheard on the Forum
Before we get started on the code, I have a question about the arrays. Each array has to represent the state of the grid. And the grid has rows and columns. I can see how to use an array to represent say one row in a grid, but how can we use an array to represent rows and columns?
I think we’ll have to use two dimensional arrays. So we’ll have an array, and each value in that array will be another array.
That makes my head hurt a bit. Can you explain a bit more?
Let’s take a small example. Imagine you have a grid with two rows and two columns. So you basically have a grid with four cells. You’ll need a = new Array(2);, and then a[0] = new Array(2); and a[1] = new Array(2);.
So then how do you access the cells in the grid?
Like this: if you want the top left cell, you say a[0][0]. That says, “get the array in a[0] and then get the value in index 0 of that array.” And if you want the top right cell, you say a[0][1]. And so on. In the game, you’ll do that same thing, except for a much bigger grid, and use rows and cols instead of 2 for the size of the arrays.
Okay, I think I’m getting it! So the cells in the first row of our grid will be a[0][0], a[0][1], a[0][2] all the way to a[0][cols-1]. And the next row will be a[1][0], a[1][1], … a[1][cols-1], and so on. Right?
You’ve got it. Now let’s get started on the code.
Code

We’re going to implement the model—that is, the grid state—with two, two-dimensional arrays: one for the current state, and one for the next state. You can think of the current state as the first piece of graph paper, after you’ve filled it in, and the next state as the piece of graph paper you use to compute the next state of the game.

You might be asking “don’t we need more than two arrays? Don’t we need a new array for each generation of we compute?” Good question. But, unlike our graph paper, we can reuse the old array on the next round of the game. Oh, we should also mention that in the model we’re going to use 0 to represent a dead cell, and 1 to represent a live cell, so our two state arrays will be filled with 0’s and 1’s as we play the game.

With that out of the way, let’s write some code.

Here is the complete code with the two data structures we will be using to store the state of the grid:

Get this code added to your file “code.js” if you haven’t already and then we’ll test it.

Crash Test

It’s time to test the code for the model, and make sure that when we click on a cell in the grid, it’s being stored as state in the array correctly. We’ll test this code using the JavaScript console, so open your browser, load the page, and then open up the console. Watch the video below and follow along as we test our code.

Going Deeper

Here’s a little advanced thought experiment and design question for you: one of the reasons for dividing a design into a model, view and controller is so that we can treat them independently. For instance, we might swap in a totally different view on top of the same model, or we might replace our model with a more efficient implementation. In either case, we’d hope to do this with minimal changes to our existing code.

Now take a look at our code here:

    if (classes.indexOf("live") > -1) {
        this.setAttribute("class", "dead");
        grid[row][col] = 0;
    } else {
        this.setAttribute("class", "live");
        grid[row][col] = 1;
    }

Notice how you can look at this code and you know exactly how the model is implemented (as a two dimensional array)? And, if we wanted to use a different model, we’d have to go into this code and make changes. Do you think we should have done this differently? How might we improve it?

Make your own notes and feel free to take this discussion to the forum.

Compute One Generation

Now that we’ve got our model in place, we can apply the rules of the game. We’ll refresh our memory about what those rules are, and then implement some functions to compute the next generation of life using those rules.

Getting Prepared

We’re ready to apply the rules of the game to the cells in the grid. To do that, we’re going to use the state stored in grid array. Wherever there’s a 1 in that array, we have a live cell, and wherever there’s a 0, we have a dead cell. Let’s do a quick refresher of the rules of The Game of Life before we start implementing the code:

  • Any live cell with fewer than two live neighbors dies, as if caused by under-population.
  • 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 overcrowding.
  • Any dead cell with exactly three live neighbors becomes a live cell, as if by reproduction.

Now imagine applying these rules to every item in the grid array. We’ll iterate through all the cells in the grid array, and as we iterate, we’ll call a function to apply the rules to every cell, and store the new state of that cell in the nextGrid.

To see how we’re going to do this, watch the video. Then we’ll get started implementing the rules for The Game of Life.

Code

Our goal for this section is simple: to compute one iteration of the Game of Life. After we have that working we’ll turn our attention to updating the display, and then to successively computing new generations.

For now we’re going implement three new functions:

computeNextGen: This function drives the computation by taking one cell in the grid and passing it to applyRules.

applyRules: This function knows how to apply the rules of the game to a single cell.

countNeighbors: This is a helper function that counts the number of live neighbor cells a cell has.

By breaking up the code to play one round of the game into manageable pieces, we can take it one step at a time, and each piece doesn’t get too complex or too long. So follow along with the video as we get these three functions implemented:

The complete code for this step is below. Get it added to your file “code.js”, and then move on to the next step for testing.

Crash Test

Now we’ve got code to play one round of the game. Again, we’ll need to use the console to test the code, so follow along as we give our code a run through and make sure it works.

Research

We’re going to be using a built-in function called setTimeout() in an upcoming section. If you don’t remember the details of this function, take a moment to look it up, using an online reference, in Head First JavaScript Programming (pages 409-412), or another JavaScript reference book.

Field Trip

The Game of Life belongs to a class of applications we call Generative. With generative apps we typically set up initial conditions (like the beginning live/dead cells in the Game of Life) and then let an algorithm drive the behavior from there. Good generative apps generate results we find interesting and often surprising. Generative apps aren’t limited to small graphical universes like the Game of Life; in fact, take break from coding and see how generative systems are influencing other areas of art and science with this video from game designer Will Wright and musician/producer Brian Eno:

Update the View

We’re storing the next generation of life—that is, the state of each cell in the grid—in our model, so now we need to take that state and use it to update the view.

Game Plan

We’ve just implemented the code to compute the next generation of cells, and we’re storing that state in the nextGrid array. But we don’t see that next generation in the view, because all we’re doing so far is updating the model—the arrays where we’re storing the state of the game.

There are two things we need to do to update the view. First, we need to copy the state that’s in nextGrid to grid. We do that so that grid contains the current state of the game. Using our graph paper metaphor, it’s like you’re taking the 2nd sheet of graph paper—the one you just used to create the next generation of cells—and you’re putting it on top of the first piece of graph paper which you don’t need anymore. And, at the same time, you’ll grab a fresh piece of graph paper to compute the next generation. So, we’ll write a function copyAndResetGrid to copy the state from nextGrid to grid, and, at the same time, clear out the nextGrid array, setting every item to 0, so we’re starting fresh.

Once we’ve got the new generation we just computed stored in grid, we’ll use it to update the view. We’ll do that in a new function, updateView, by iterating through the grid array, looking at each item in the array, and setting the class of the corresponding cell in the table to either “dead” or “live” depending on if the array is storing a 0 or 1 at a given location.

Coding the View Update

For this step, we’ll implement two new functions: copyAndResetGrid and updateView.

copyAndResetGrid will copy the values from nextGrid into grid by iterating through all the cells and copying them. In the same iteration, we’ll also reset the values in nextGrid back to zeros.

updateView will look at the state in the model—that is, the data in the grid array—and update the view based on that data. That means if a cell in the grid array has a 1, we’ll update the class of the corresponding cell in the table to “live”. And if a cell in the grid array has a 0, we’ll update the class of the corresponding cell in the table to “dead”.

Once we get this code added, we’ll be able to see one round of life being generated in the browser!

Watch the video below, and follow along in your own code as we implement these two functions:

Here is the complete code for this step. Get your “code.js” file updated and then we’ll test it.

Audience Question

Instead of copying nextGrid to grid, couldn’t we just switch the arrays?

You’re saying we could save some work by using nextGrid as the current state, and grid as the next state for the 2nd generation? And, of course, we’d have to keep switching back and forth so every other generation, we use grid or nextGrid as the current state, and the other array as the next state.

Yes, we certainly could do that. It does save some work, but not all of it, because we need to reset the nextGrid back to all zeros anyway. So as long as we’re iterating, we chose to copy the state from nextGrid to grid. We also think it makes the code a bit easier to understand conceptually.

That said, we like your thinking and once we’ve finished we encourage you to retrofit your code to avoid unnecessary copying.

Crash Test

Let’s test the code we just added to update the view. At this stage, we’re generating one round of the game: we set the initial state by clicking on the grid to make some cells live, we start the game by clicking the start button, and we compute the next generation in the nextGrid, copy that state to grid, and then update the view.

So let’s give it a try in the browser and see what happens. If we’ve got everything right, we’ll the Game of Life rules applied once to the cells in the grid, and see the cells update based on the results of applying the rules.

Iteratively Computing Generations

We’ve got one generation of the game going; now we need to keep the game going for multiple generations, so we can see our cells come to life over time. For that, we’re going to think about how to manage the time of the game, and how that will work with the user interface so you can click on the buttons to pause and stop the game.

Deep Thoughts

Our Game of Life is generating cells for one round of the game; our next task is to keep the game going for multiple generations. Take another look at the code we’ve got so far; to play the game, we’re calling play, which calls computeNextGen.

What do you think is the best way to have our game continue computing new generations? Should we iteratively loop using playing after the Start button is clicked?

function play() {
    while (playing) {
        computeNextGen();
    }
}

Are there any downsides to doing it this way? Can you think of a better way?

Answers, think of your own before reading.

Conceptually, wrapping the computeNextGen function in a loop is the right idea; however, in practice, it is problematic. As it turns out JavaScript only has one thread of control, and so as soon as you begin the while loop, this code will consume most of your browser’s computing resources and make the game controls unresponsive, or slow to act. This approach also doesn’t allow you to control the speed at which each generation is computed, which may be too fast to see the Game of Life computation unfold.

We gave you a hint about how we’re going to approach this when we gave you some research homework on the setTimeout method. By using setTimeout we’ll be able to control the execution of each generation by scheduling it to run asynchronously (meaning the execution of the function to compute the next generation won’t block everything else the browser is doing). Let’s move on to the next section and see how this works.

Using a Timer to Compute Iteratively

Before we dive into the code let’s take a quick look at how we’re going to use a timer in our code to create multiple generations of life in The Game of Life.

Coding the Timer

Okay, you know how we’re going to use a timer to control the rounds of the game, so let’s get the code implemented. We’re going to need two new global variables, timer and reproductionTime to store the timer, and set how long we want to wait between generations. We’ll add those variables to the top of the code.

Then all we’re going to do is call the play function on a timer. This will make sure that as long as the game is going (that is, you haven’t clicked the “pause” or “clear” buttons), the play function will get called again and again, and each time, it will compute a new generation of life.

Watch the video below to follow along as we add this code.

Here’s the full code for this step of the implementation. Get this added to your code in “code.js”, and then we’ll test!

Crash Test

Now’s the big moment; we have our timer code implemented, so now we should be able to play the game and see multiple generations of life unfold. Let’s give it a try…

Notice that with a reproduction time of 100 milliseconds, the game moves pretty fast! Try larger and smaller numbers here, say 10ms or a second (1000ms). Which do you like better? Slower or faster? With a slower reproduction time—that is, a longer delay between calls to the timer function—you get a chance to see the steps of the game. This is helpful for debugging if you notice any problems with your code. But we think it looks a lot cooler with a shorter reproduction time, and 100ms works well.

Clear the Grid

We can start the game, pause the game, and continue the game, but we can’t stop the game and clear the grid. This is important functionality if you want to be able to play the game multiple times.

Coding the Clear Button

Right now, our “clear” button doesn’t do what it’s supposed to do. The handler for this button, clearButtonHandler, simply sets playing back to false (meaning we’ve stopped the game from playing), and sets the startButton back to “start”. So what do we want the “clear” button to actually do?

Well, along with what it already does, we want it to clear out the grid. That means, both the grid in the view (all the table cells), as well as the grid state in the game (in the grid and newGrid arrays). We already have a function to clear the two arrays (resetGrids), so we can call that from clearButtonHandler. We’re also going to need to add the code to make sure all the cells in the table—that is, the grid in the view—are set back to dead by giving them all the class “dead”. Oh, and don’t forget, if you click the “clear” button, you’ll also need to clear the timer so we don’t call play again until you click the “start” button.

Follow along while we get this code implemented.

Here’s the full code for this step:

Crash Test

Let’s get this code tested! Load up the page, and add some cells, click the Start button to play the game for a few rounds, and then click on Clear. The game should stop and the grid should clear completely. Let’s see what happens…

Uh Oh, We have a Bug

We have a bug! Not all of the cells are being cleared from the grid when we click the clear button. What’s going on?

Fixing our Code

Let’s get that bug fixed. We know we need to copy the list of “live” cells from the nodeList we got back from getElementsByClassName("live") into an array first, and then we can iterate over that array and change each cell’s class from “live” to “dead”.

A Little Polish

We’re almost there, we just need to tie up a couple of loose ends. In this module, we’ll add a random button, so we can more easily try lots of different initial states, and we’ll increase the size of the grid so we have more room for more life. Then we’ll do one final test of the code, and we’re done!

Extra Credit: Adding the Random Button

For extra credit, let’s add a random button to the Game of Life. With the random button, we’ll be able to seed the grid with lots of cells, randomly placed on the grid… a little bit more like a real life situation.

First, update your “index.html” file with the following line of HTML; add this line just below the start and clear buttons:

<button id="random">random</button>

We’ve added the button to the HTML, so now we need to update our code in “code.js” to add a click handler for the button. So, we’ll update the function setupControlButtons to assign a click handler, and add a new function randomButtonHandler, the click handler for the button.

This code should be old hat for you at this point: we’re going to loop through every cell in the grid, and randomly assign the class “dead” or “live” to each cell in the view, and a corresponding 0 or 1 to the grid array (the state in our model). To make a random choice between a dead cell and a live cell, we’ll generate a random number 0 or 1 using Math.random and Math.round.

Before we loop, we’ll start out doing two things: we’ll make sure the user can’t click the random button while the game is playing, and we’ll also clear out the current view and model state. We already have code to do the latter—in clearButtonHandler. So we can use that, and just call that function to do that work for us.

Here’s the complete code for the random button. Get this added to your “code.js” file, and then test it. You should be able to click random to add a random initial state to the grid, and then click start to start the game and see your cells come to life.

Final Design Tweaks

One last tweak before we do our final test of The Game of Life. Let’s make the grid a lot bigger, and reduce the size of each cell by half. By doing this, we’ll get much more room for life to grow and expand into, and it will look super cool.

First, edit “code.js” and update the grid size in the variables rows and cols to something bigger, perhaps 50 or 75 each. This makes the grid a lot bigger.

Then, edit “life.css” and change the width and height properties in the td rule to 10px instead of 20px:

td {
    border: 1px solid rgb(90, 90, 90);
    width: 10px;
    height: 10px;
}

Okay, with that change done, it’s time for our last test of the game!

Crash Test

Okay this is it—let’s do the final test of the game, and also take the random button for a whirl.

The Finish Line

You’ve completed The Game of Life project, and implemented the rules for Conway’s Game of Life in the browser. We hope you’re having fun playing the game. Once you’re ready, take a look at some cool things you might do next.

Going Further

Why Stop Now? How about…

Extending your project?

Now that you’ve totally rocked this project, could you take it further? Of course. Here are some ideas:

The Game of Life is just one example of a class of systems called Cellular Automata. In fact, now that you have the basics coded you can easily change out the algorithm to get other interesting computations. Here’s a simple one:

  1. If a cell is live, it stays alive in the next iteration.
  2. If a dead cell has two live cells adjacent to it, the dead cell changes state to live.

Code that and give it a try. Also try varying the number of adjacent cells that need to be alive for a dead cell to change state. Can you think of real systems this simulates? How about forest fires or flu transmission?

Or doing more research?

If you’d like to learn more about cellular automata check out the Cellular Automata Wikipedia page.

Or taking the project in a whole new direction?

Learn about the web sound API and create a generative music app from the Game of Life by assigning samples and sounds to grid locations. You might also check out apps and devices like the Tenori-on for inspiration.

Code: The Complete Code

Just in case you want to see all the JavaScript code in one place, here's the complete code for the finished game.

Pin It on Pinterest