Spatial Simulation: Game of Life
This week begins a multi-week project during which we'll explore the simulation of entities on a 2D grid. The entities will interact with the grid and with each other, simulating various social phenomena.
The inspiration for this series of projects comes from both research on cellular automata, such as Conway's Game of Life, and work at the Brookings Institute by Epstein and Axtell on modeling human social dynamics. There are a number of newer publications and white papers on the Brookings Institute web site with more recent results, including significant models of the spread of disease.
Here are the links to the API's for the most recent versions of Java:
Create a new project folder for this week's project.
This week you'll first develop three classes: a Cell, a Landscape, and a LifeSimulation. The Cell will represent a location on the Landscape. The Landscape will represent a 2D grid of Cells, and a LifeSimulation will control the rules and actions of the simulation. The end result will be a text-based simulaton of Conway's Game of Life.
For each class, create a main method that tests the capabilities of the class.
Cell - a Cell object represents one location on a regular grid. The
Cell class should store its own location in the grid, store whether it
is alive or not, and implement the following methods.
- public Cell(int row, int col, boolean alive) - constructor method.
- public void setPosition( int row, int col ) - sets the Cell's position.
- public void setAlive( boolean alive ) - sets the Cell's alive state.
- public int getRow() - returns the row value of the Cell's position.
- public int getCol() - returns the column value of the Cell's position.
- public boolean isAlive() - returns whether the Cell is alive.
- public String toString() - returns a string that indicates the alive state of the Cell as a one-character string. For example, you could use a "0" for alive and " " for dead. This will override the default toString method in the Object class.
Landscape - create a java class called Landscape, which will hold a 2D
grid of Cell object references. The Landscape class should have a
field to hold the array of Cell object references and implement the
- public Landscape( int rows, int cols ) - sets the number of rows and columns to the specified values and allocates the grid of Cell references. Then it should allocate a Cell for each location in the Grid.
- public void reset() - sets all of the Cells to be dead. [Option: create a reset method for a Cell and call that, instead of forcing the Cell to a specific state.]
- public int getRows() - returns the number of rows in the Landscape.
- public int getCols() - returns the number of columns in the Landscape.
- public Cell getCell( int row, int col ) - returns a reference to the Cell located at position (r, c).
- public String toString() - converts the Landscape into a text-based string representation. At the end of each row, put a carriage return ("\n").
- public ArrayList<Cell> getNeighbors( int row, int col ) - returns a list of references to the neighbors of the Cell at location (row, col). Pay attention to the boundaries of the Landscape when writing this function.
LifeSimulation - create a Java class called LifeSimulation, which will
hold a Landscape and drives a simulation of the Game of Life. You may
also want to keep track of the time state (number of iterations) the
simulation has executed. The LifeSimulation should implement the
- public LifeSimulation(int rows, int cols) - initialize the Landscape to the given size. Use the Landscape reset method to set the initial values.
- public void initializeRandom( double density ) - go through each cell in the Landscape and set it to alive with the probability given by density, where density is in the range [0.0, 1.0].
- public String toString() - converts the LifeSimulation to a text-based string representation. The minimum required is to simply return the result of calling toString on the Landscape.
At this point, test your LifeSimulation by creating a LifeSimulation object, initializing it, and printing it out. To run a simulation, you need to write a few more methods.
Add a method to the Cell class:
public boolean updateState( ArrayList<Cell> neighbors )
The updateState method should look at the Cell's neighbors (passed as input) and update its own state information. The default rule should be if a live Cell has either two or three live neighbors, then it will be set to alive. If a dead Cell has exactly three neighbors, it will be set to alive. Otherwise, the Cell will be set to dead.
Add a method to the Landscape class:
public void advance()
The advance method should move all Cells forward one generation. Note that the rules for the Game of Life require all Cells to be updated simultaneously. Therefore, you cannot update the Cells in place one at a time (why not?).
Instead, create a temporary Landscape of the same size. Then duplicate the alive status of the original Landscape with the temporary Landscape (you need to loop over the original and set the temporary Cell alive values). One design option is to make a new constructor that takes a Landscape as its argument and creates a true copy.
Then go through each Cell in the temporary Landscape and call updateState, passing the list of neighbors of the Cell in the original Landscape to the Cell. When the code has updated all of the Cells, you need to transfer the information back. You can just assign the grid of the temporary Landscape to the grid of the original one.
Add a method to the LifeSimulation class:
public void simulate(int n) throws InterruptedException
The simulate method should run the simulation n times, printing out the current Landscape at each step. You can use Thread.sleep() to slow down the simulation. Thread.sleep takes milliseconds as its argument. If you call simulate from any other function (e.g. main) then you will also have to add the 'throws InterruptedException' to the function definition.
Finally, update your LifeSimulation main method to create a
LifeSimulation, initialize it, and then simulate it some number of
times, perhaps using an argument from the command line. Start with
small Landscapes for testing.
If you want to test your program using a known pattern, go to the Wikipedia page on the Game of Life and look up an example. Then create a new initialization method that sets the Landscape to the specified pattern.
- Modify the main method in LifeSimulation to make use of command line parameters. For example, it would be nice to control the size of the Landscape and the number of iterations used in the simulation.
- Try modifying the updateState function in the Cell class to implement different rules. Think about how to do this using good design rather than having many copies of the Cell class or commenting/un-commenting blocks of code.
- Create more than one type of Cell and give each type different rules.
- Be creative with the visual representation.
Make your writeup for the project a wiki page in your personal space. If you have questions about making a wiki page, stop by my office or ask in lab.
Your writeup should have a simple format.
- A brief description of the overall task, in your own words.
- As explanation of your solution, focusing on the interesting bits. The interesting bits here are things like the toString functions, initializing the Landscape, and creating the simulation rules.
Printouts, pictures, or results to show what you did. You can do
screen captures of your terminal to show the initial and final
landscapes. You can also dump your terminal output to a file.
$ java LifeSimulation > output.txt
- Other results to demonstrate extensions you undertook. If you tried different update rules, for example, show how those affected the overall simulation results.
- A brief conclusion and description of what you learned.
- A list of people you worked with, including TAs, and professors. Include in that list anyone whose code you may have seen, such as those of friends who have taken the course in a previous semester.
Once you have written up your assignment, give the page the label:
You can give any page a label when you're editing it using the label field at the bottom of the page.
Do not put code on your writeup page or anywhere it can be publicly accessed. To hand in code, put it in your folder on the Courses fileserver. Create a directory for each project inside the private folder inside your username folder.