| CPSC 120 | Principles of Computer Science | Fall 2025 |
Topics showcase applications of the core concepts, in this case arrays, loops, and conditionals.
In this lab, you'll implement classic 1D and 2D cellular automata — Wolfram's elementary CA and Conway's Game of Life — as well as explore an application of 2D CAs.
To hand in your sketches:
Make sure that your name and a short description of the sketch are included in a comment at the beginning of each sketch.
Make sure that you've auto-formatted each sketch.
Copy the entire elementaryCA, gameoflife, and firesim directories from your sketchbook (~/cs120/sketchbook) to your handin directory (found inside /classes/cs120/handin). Also copy the entire elementaryCA_ec and firesim_ec directories from your sketchbook to your handin directory if you did any extra credit.
Like labs, topics are individual assignments — what you hand in must be your own work, your own ideas, your own effort. You may get help in office hours and from Teaching Fellows, but you may not work together with a partner or in a group with others to create solutions or write code.
The policies on late work and extensions, academic integrity, and the use of AI for topics are the same as for lab 2. Review the policies there. One extension token is needed for revise-and-resubmit without an initial handin.
Also review assignments and evaluation on the Policies page for how topics factor into the final grade. The short version: topics are optional for a passing grade (C-), but achieving proficiency for at least some topics is required for a higher grade.
Review the slides from 11/24 for more about cellular automata as well as specifics for how to implement the 1D and 2D CAs you'll be implementing below.
Do the exercises in order. Note: following the steps outlined below is required for credit — achieving the end result by some other means will not count.
Read through all of each exercise before you start on it. In particular, note that the "to do this" steps are what you should actually do to complete the exercise — don't just read the first sentence of the problem, look at the example, and try to write the sketch from there. Follow the steps!
Put your name and a description of the sketch in comments at the beginning of each sketch. Also don't forget to Auto Format your code before handing it in.
Be sure to save your sketch frequently (ctrl-S). (Every time you run your sketch is good.) The editor does not auto-save!
For this exercise you will create an elementary 1D cellular automaton. (Extra credit options allow you to further explore its behavior.) To do this, follow the steps below. "As described in the slides" refers to the "Implementing Elementary CAs" slides from class on 11/24.
Create a new sketch, add a comment with your name and a description of the sketch, and save it with the name elementaryCA.
Add code to open a drawing window and clear the background to white.
Set up the array of cells as described in the slides:
Define the rule set: declare and initialize an animation variable
boolean[] ruleset = { false, true, false, true, true, false, true, false };
draw() will generate and draw all of the generations of the CA. Start with just drawing the current generation: as described in the slides, write the loop for drawing one row. Use the standard going-through-an-array loop as the starting point — add the x coordinate to that as an additional loop variable. Make the rectangles 10x10, outline each rectangle in black, and hardcode the y position so that the row of rectangles is at the top of the window. When this step is complete, you should be able to run your sketch and see the initial generation (all cells white except for the middle one) displayed at the top of the drawing window.
Wrap the "draw one row" loop with a loop to repeat drawing rows as described in the slides, but with only the loop variable for the y coordinate of the row — the result of this step should be a sketch which fills the drawing window with copies of the initial generation.
Add the "compute the next generation" step:
When this step is complete, you should have a working sketch which displays the Sierpinski triangle pattern.
The rule set discussed in class and implemented above is known as Rule 90. An interesting property of this rule is that it generates the very regular Sierpinski triangle pattern when started with a single "live" cell, but it generates a pattern that stays random when started with a random initial configuration.
Modify the sketch to start with a random initial configuration so you can see this behavior: comment out the lines where you set the middle cell to true and the others to false (this means to put // at the beginning of each of those lines to keep them in the program but remove them from execution) and instead initialize each cell to true or false randomly. The slides on initialization options for elementary CAs show how to make a choice with equal probability — set the current cell to true in the if part and false in the else part.
Note: because the cells are initialized in draw() instead of setup(), to keep the picture stable, it is necessary to ensure that the same random initial configuration is used in each frame: add the statement
randomSeed(0);
just before you initialize all the cells of the array. You can replace 0 with another value — the particular value given to randomSeed doesn't matter, just that the same value is given to it each time.
For this exercise you will implement Conway's Game of Life. To do this, follow the steps below. "As described in the slides" refers to the "Conway's Game of Life" and the "Implementing 2D CAs" slides from class on 11/24.
Create a new sketch, add a comment with your name and a description of the sketch, and save it with the name gameoflife.
Add code to open a drawing window and clear the background to white.
Set up the 2D array of cells as described in the slides:
In draw(), draw the current generation of the CA as described in the slides. Start with the nested go-through-every-slot-of-a-2D-array loop pattern, then add the x and y coordinate loop variables to that framework. When this step is complete, you should be able to see the randomly-initialized initial generation of the CA.
Add the "compute the next generation" step at the end of draw(), after the current generation is drawn:
When this step is complete, you should have a working Game of Life sketch, though it probably runs very quickly.
To slow the evolution of the CA down, put the statement
frameRate(10);
in setup(). This adjusts the speed of the animation so that draw() is only called 10 times per second instead of the usual 60.
Finally, add code so that clicking the mouse resets the CA to a new random initial configuration.
You are encouraged to watch the simulation a bit — can you identify some of the still life, oscillator, and spaceship patterns mentioned in class?
For this exercise you will implement the simulation of a spreading forest fire as discussed in class. To do this, follow the steps below. "As described in the slides" refers to the "Fire Simulation" slides from class on 11/24.
Since the fire simulation is also a 2D cellular automaton, you can use your Game of Life sketch as a starting point: save that sketch with the name firesim, then update the comment (in firesim!) to accurately describing this sketch.
Each cell in the fire simulation has three possible states instead of just two: change the cells variable to be an array of ints instead of booleans. (This means changing types from boolean to int.) A value of 0 will represent an empty cell, a value of 1 will represent a tree, and a value of 2 will represent a burning tree.
Update the initialization and click-to-reset code to set the starting value of each cell as follows:
if ( random(1.0) < 0.8 ) { // probability of a tree
if ( random(1.0) < 0.01 ) { // probability of burning
cells[i][j] = 2; // burning
} else {
cells[i][j] = 1; // tree
}
} else {
cells[i][j] = 0; // empty
}
This sets up a scenario where each cell has a 80% chance of starting off as a tree, and each tree cell has a 1% chance of starting off as a burning tree.
Update the drawing code to correctly set the color: empty cells should be yellow, tree cells should be green, and burning cells should be reddish brown. You can use the color selector (Tools → Color Selector...) to pick appropriate colors.
Update the "compute the next generation" code to use the rules described in class (and in the slides). Use a pcatch of 0.8 (a tree has an 80% chance of catching fire if it has at least one burning neighbor).
You should now be able to run the simulation and see how the fire spreads through the forest.
Experiment with some other probabilities to see how this affects the spread of the fire: try various combinations of 0.2, 0.5, and 0.8 for the probability of a cell being initialized to a tree and 0.2, 0.5, and 0.8 for the probability of a tree catching fire if it has a burning neighbor. What do you observe?
You can earn extra credit by going substantially beyond the required elements. Some possibilities:
Elementary CAs — save a copy of your elementaryCA sketch with the name elementaryCA_ec as a starting point, then modify the copy:
Have clicking the mouse toggle between the middle-cell-live and random initial configurations for the CA.
Explore different rule sets leading to different classes of behaviors when started with a random initial configuration. (See here for more on specific rules to try. The numbering system for the rules is explained here. You can use this converter to convert a base 10 (decimal) rule number like 90 to binary so you can initialize the rule set; if the resulting binary number has fewer than 8 digits, add 0s to the left side.) Have clicking the mouse cycle through two or more interesting rule sets.
Make the cell size smaller to better show the big picture view of how the CA evolves from one generation to the next.
Fire simulation — save a copy of your firesim sketch with the name firesim_ec as a starting point, then modify the copy:
Add a new simulation rule: if a cell contains a tree, it is struck by lightning with probability plightning and a tree struck by lighting catches fire with probability pcatch. The probability plightning of a tree getting hit by lightning should be pretty low — start with a value like 2% (0.02) and adjust higher or lower from there. Also experiment with different pcatch values such as 0.2, 0.5, and 0.8. (Use the same pcatch value for trees catching fire from burning neighbors as from lightning strikes.)
Have a tree take two time steps to burn completely. Do this by adding a fourth cell state: 3 represents a freshly ignited tree, while 2 represents a tree that has already been burning for one generation. Update the simulation rules accordingly: a freshly ignited cell (state 3) becomes an already burning tree (state 2) and an already burning tree (state 2) becomes empty (state 0). If a cell with a tree catches fire (from a burning neighbor or lightning), it becomes freshly ignited (state 3). Experiment with different probabilities for a cell being a tree in the initial configuration and for pcatch to see what difference this makes.