Due: Monday, February 20, 2017, 11:59 pm

Spatial Simulation: Game of Life

This week 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.

Tasks

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 simulation of Conway's Game of Life.

  1. Cell: a Cell object represents one location on a regular grid. The Cell class should store whether or not it is alive and implement the following methods.

    • public Cell( ) constructor method. (by default, the Cell is dead)
    • public Cell( boolean alive ) constructor method.
    • public boolean getAlive( ) returns whether the Cell is alive.
    • public void setAlive( boolean alive ) sets the Cell's alive state.
    • 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.

    Implement the methods, and test them with a main method.

  2. 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 following methods.

    • 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 (row, col).
    • 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

    Implement the methods, and test them with a main method.

  3. Make it possible to visualize your Landcsape.
    1. Download the code for the LandscapeDisplay class. Read the code and note its fields and methods. Its job is to display a Landscape. To do so, it stores a Landscape object in a field. It opens a window and calls the draw method on the Landscape, which, in turn, calls the draw method on the Cells. Before you can compile the LandscapeDisplay class, you will need to add those draw methods.
    2. Add a method to your Cell class: public void draw( Graphics g, int x, int y, int scale ). It draws the cell on the Graphics object at location x, y with the size scaled by scale.
    3. Add a method to your Landscape class: public void draw( Graphics g, int gridScale ). It loops through the cells in Grid, calling their draw methods at positions calculated from their positions in the grid. i.e.
      	public void draw( Graphics g, int gridScale ) {
      		// draw all the cells
      		for (int i = 0; i < this.getRows(); i++) {
      			for (int j = 0; j < this.getCols(); j++) {
      				this.grid[i][j].draw(g, i*gridScale, j*gridScale, gridScale);
      			}
      		}
      	}
      

    Test your visualization by running LandscapeDisplay as your main program.

  4. Add a method to the Cell class: public void updateState( ArrayList<Cell> neighbors ). This method updates whether or not the cell is alive in the next time step, given its neighbors in the current time step.

    The updateState method should look at the Cell's neighbors on the provided Landscape 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 living neighbors, it will be set to alive. Otherwise, the Cell will be set to dead.

  5. 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.

  6. LifeSimulation: create a new LifeSimulation.java class that is modeled on LandscapeDisplay.main. It should include a loop that (1 iteration per time step) calls the advance method of the Landscape, calls the repaint method of display, and calls Thread.sleep( 250 ) (to pause for 250 milliseconds between time steps).

    Test your simulation with random initial conditions. Consider using a command line argument to control the grid size and the number of time steps in the simulation.

    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.

    Now make an animated gif so that you can include the output of your simulation in your write-up. After the display is repainted (in the loop you wrote above), add the following line:

    display.saveImage( "data/life_frame_" + String.format( "%03d", i ) + ".png" );
    

    The output should be a series of images of the simulation, using zero-padding to make sure that numeric and alphabetical orders are the same (e.g. 002 comes before 010 alphbetically, but 2 does not come before 10 alphabetically). Then, create a data directory in your project directory, run your program, and make the animated gif using convert (an ImageMagick program).

    mkdir data
    java LifeSimulation
    convert -delay 60 data/life_frame_*.png mysim.gif
    

    Another way to get your animation is to record a screen video. It does not matter which way you use. But you are expected to show your animation in your write-up.

Extensions

  1. 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.

  2. 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.

  3. Create more than one type of Cell and give each type different rules.

  4. Be creative with the visual representation.

Writeup

Your writeup should have a simple format.

Handin

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.

Once you have written up your assignment, give the page the label:

cs231s17project2

You can give any wiki page a label using the label field at the bottom of the page. The label is different from the title.

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.

© 2017 Ying Li. Page last modified: .