Conway's Game of Life
This week we'll explore the simulation of entities on a 2D grid. The entities will interact with each other to determine how they change over time. The overall concept is called cellular automata, and you'll implement a specific version of cellular automata that implement Conway's Game of Life. Please at least skim the wikipedia page if you have not seen the Game of Life before.
Tasks
This week you'll 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. We will use the Java Swing graphical user interface package in order to display our landscape. The end result of the project will be a window that displays Conway's Game of Life.
Cell Class
First, download Cell.java. 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 that specifies the Cell's state. A True argument means the Cell is alive, a False argument means the Cell is dead.public boolean getAlive( )
returns whether the Cell is alive.public void setAlive( boolean alive )
sets the Cell's 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 "1" for dead. This will override the default toString method in the Object class.
Implement the methods, and test them with a main method.
Landscape Class
First, download Landscape.java. The Landscape class should have a field to hold the array of Cell object references and implement the following methods. You may also want to have fields to hold the number of rows and the number of columns in the grid.
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 Landscape( int rows, int cols, double chance)
operates the same as the above, except that each cell independently starts with a chance of being alive equal tochance
.public void reset()
recreates the grid via the same method as it was originally created.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. The returned list should not contain the Cell at (row, col).
Implement the methods, and test them with a main method.
Landscape Visualization
Make it possible to visualize your Landscape.
- Download and Analyze Java Swing Code
Use Java's Graphics class as reference. Particularly
setColor()
anddrawOval()
.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.
- Drawing the Cells
You'll notice that we've already filled in the code for the Landscape's
draw()
method. Take a minute to observe how it works: it iterates through the Cells in the Landscape and draws ovals to the Graphics object whose color depends on whether the Cell is alive or dead.+ (more detail)
A Graphics object enables you to set drawing parameters, such as the color, and to draw shapes into the current window. See the Java documentation for the complete set of capabilities.
Test your visualization by running LandscapeDisplay as your main program. Your default initial Landscape should be all zeros/dead cells. Make sure to test a case where some of the grid cells have been set to alive.
Updating Cell States
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 remain alive. If a dead Cell has exactly three living neighbors, it will be set to alive. Otherwise, the Cell will remain dead.
Correctly writing these rules is important, so test out your system by downloading CellTests.java. You should also create tests for the Landscape class.
Advancing the Game
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 Cell grid of the same size. For each grid location create a new cell and copy over the alive status of the original cell in that location.
Go through each Cell in the temporary grid, using a nested loop, and call updateState(), passing the list of neighbors of the Cell in the original grid to the Cell. When the code has updated all of the Cells, you need to transfer the information back. You can just assign the temporary grid back to the original grid field.
Testing Landscape
As always, it's best to write good tests for your code. We've started a testing suite for Landscape here, your job is to complete it.
LifeSimulation Class
Create a new LifeSimulation.java class that is modeled on LandscapeDisplay.main()
.
It should include a loop that calls the advance() method of the Landscape, calls the
repaint() method of LandscapeDisplay, and calls Thread.sleep( 250 )
to pause for
250 milliseconds before starting the next iteration. Each iteration of the loop is one time step of the
simulation.
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. It's useful to test your code by first just visualizing the initial board. Then have your simulation go forward by one time step and stop. See if the results make sense before going further.
Required Pictures 1 and 2: include in your report a picture of your board's initial state and the following state after one update.
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.
Required Animation; make a short video or animated gif of your simulation and include it in your report.
+ (more detail)
After the display is repainted (in the loop you wrote above), add the following line to save the current display:
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.
Exploration
How do the parameters of grid dimensions and initial status chance affect the number of living cells after a sufficiently long time (say, 1000 rounds)? In your report's results section, develop a hypothesis, test it, and back up your results with sufficient experimental evidence.
Extensions
As last week, these are only recommendations and you can choose from these ideas or develop your own. Any extension you take must be adequately detailed in your report.- 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, the density of the initial board, 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.
- Implement a method to determine if the game is effectively 'over': that is, if the board has begun cycling through the same iterations. Reflect on the trade-off between memory-space and time efficiency of your solution.
- Create more than one type of Cell and give each type different rules. Be sure to explain your design in the report and discuss what you expected as well as the results.
- Be creative with the GUI. Add buttons or other controls to the window. These might let the user start, stop, or pause the simulation, set the density of the start situation, and reset the simulation.
Report
Your intended audience for your report are your peers not in the class, but who have taken a CS course. Your report should explain the core CS concept used, present the results of your program, and discuss the meaning of the results: what did you discover and does it make sense?
Your project report should contain the following elements. Please include a header for each section.
- Abstract
A brief summary of the project, in your own words. This should be no more than a few sentences. Give the reader context and identify the key purpose of the assignment. Each assignment will have both a core CS purpose--usually a new data structure--and an application such as a simulation or analysis.
Writing an effective abstract is an important skill. Consider the following questions while writing it.
- Does it describe the specific project application?
- Does it describe the results of your simulation or analysis?
- Is it concise?
- Are all of the terms well-defined?
- Does it read logically and in the proper order?
- Results
Present your results. Include text output, images, tables, graphs, or qualitative descriptions, as appropriate. Include a discussion as to whether the results make sense and what they mean. This week, be sure to include the image of a sequential turn and your results from the exploration section.
- Extensions
Describe any extensions you undertook, including text output, graphs, tables, or images demonstrating those extensions. If you added any modules, functions, or other design components, note their structure and the algorithms you used. If you tried different update rules, for example, show how those affected the overall simulation results.
- References/Acknowledgements
A list of people you worked with, including TAs and instructors. 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.
Handin
Here's a checklist of everything you should do when you are finished with a project and are ready to turn it in. Go ahead and follow these steps to turn in your code from today.
+ Create a report and export to pdf
- Create a report in your favorite text editor. For this lab, include a document with your name in it.
- Print to PDF (Windows)
- Open a file in a Windows application.
- Choose "File > Print".
- Choose "Adobe PDF" as the printer in the Print dialog box.
- Click Print. Type a name for your file, and click Save.
- Print to PDF (Mac OS)
- Open a file in a Mac OS application.
- Click the "PDF" button and choose "Save As Adobe PDF".
- Choose the "Adobe PDF Settings" and click "Continue".
- Type a name for your file, and click "Save".
- Export to PDF Google Drive
- Choose "File" > "Download" > "PDF Document (.pdf)"
+ Prepare your project folder
- In Finder, move your lab folder inside your project folder. For example, if you have
Lab02
andproject_02
folders both on your Desktop, drag theLab02
folder insideproject_02
.
+ Submit your project on Google Drive
- On Google Drive, locate the folder named with your Colby username that was shared with you earlier.
- Upload the relevant files into the matching project folder. you can ‘drag and drop’ the files into the project folder on Drive. (".class" files are not relevant)
- Note that once the files are copied, Google drive records submission time and any changes made. No further changes are allowed unless you want to make another submission.