Run update21b, to create the cs21b/labs/11
directory. This week's lab depends on last week's lab. If you are
still having issues with your Grid and Cell classes,
you'll need to correct them first. Once your previous lab is working
correctly, copy your grid.py solution from your
labs/10 directory into your labs/11 directory. You
will add the new code for this week's lab to the file called
gameoflife.py.
Read through this entire lab description before you begin coding
your solution. Then go to the section on getting started and
follow the directions given there to begin.
Introduction
For this assignment, you will implement a class called
GameOfLife that can be used to play John Conway's Game of
Life. The GameOfLife class will use the Grid
and Cell classes you wrote for the previous lab.
The Game of Life simulates the evolution of a cellular automata in
a two dimensional grid world. During the simulation, a cell either
lives or dies based on its state and the state of its neighbors. The
neighbors of a cell are the eight cells that directly surround it. If
a cell is on the edge of the grid, it will only have five neighboring
cells. If a cell is in the corner of the grid, it will only have
three neighboring cells. To play the game of life first, an initial
configuration of the grid's cells are set. Then, at each time step, a
cell's state changes according to the following rules:
- For a 'live' cell:
- if it has only one or no live neighbors, it dies from loneliness
- if it has four or more live neighbors, it dies due to overpopulation
- if it has two or three live neighbors, it stays alive
- For a 'dead' cell:
- if exactly three of its neighbors are alive, it comes alive
Requirements
- You must implement a GameOfLife class that stores a
Grid as data. You may store additional data in the class as
well.
- Your GameOfLife class should have at least these methods
(you may add more if you'd like):
- __init__: the constructor takes the desired width and
height of the grid as parameters and creates the Grid object data
member.
- startWalkerGame: creates a starting point world of the
walker pattern in the lower left corner (see the sample output section
for what this pattern should look like). The walker pattern should
cause a set of live cells to move diagonally toward the upper right
corner of the screen.
- startExpanderGame: creates a starting point world of the
expander pattern such that it is drawn centered in the grid
(see the sample output section for what this pattern should look
like). Be sure to use the getWidth() and getHeight()
methods of the grid to help you determine its center. The expander
game should cause the initial pattern to expand outward and then end
with four stable structures on the grid.
- startToggleGame: a starting point world that the user
can specify by toggling cells in the grid using the mouse.
- startRandomGame: takes a percentage as a parameter, and
randomly turns on the requested percentage of cells in the grid.
- playGame: plays the game of life, based on the rules
given above, until the user presses the 'q' key to quit. Uses
the sleep function from the time library to delay
0.2 seconds between each step.
- The final version of your main program should prompt the user
to enter the width and height of the grid, create a
GameOfLife object of the given dimensions. For each of the
game starting points (walker, expander, toggle, and random) in turn
your program should:
- call the appropriate start method to initialize the world for
that game
- start the game when the user presses any key
- play the game until the user presses 'q' key to quit
- clear the grid prior to starting the next game
You should follow the directions in the next section to implement and
test your program incrementally.
Getting Started
- At the bottom of your grid.py file, make sure that you call your main program like this:
if __name__ == '__main__': main()
This ensures that when you import this file into another program that
the main program inside this file will not be called.
- Create the GameOfLife class incrementally. First
implement the __init__ and playGame
methods.
- Next test that you've implemented the rules correctly. One way
to test for correctness is to try a pattern that repeats in a well
known way. For example, if you initialize three cells in a column to
be alive, then in the next time step the live cells will flip to be
three cells in a row with the same middle cell. This pattern repeats
forever (alternating between three cells in a row and three cells in a
column). Here is a pattern on a 5 by 5 grid based on this:
- Once the above test pattern successfully flips between a
vertical and a horizontal line, you can implement each of the games,
testing after adding each one.
Sample output
In the sample output given below, only the initial starting
conditions of each game are shown.
$ python gameoflife.py
This program plays Conway's Game of Life
Enter width of the grid: 21
Enter height of the grid: 21
Try the walker game.
Press any key to start the game.
Press q key to quit.
Try the expander game.
Press any key to start the game.
Press q key to quit.
Try the toggle game.
In this game you create your own starting point by
clicking on cells to make them alive.
Press any key when done toggling.
Press q key to quit.
Try the random game.
Press any key to start the game.
Press q key to quit.
Optional Extensions
Do not try these extensions until you have the basic assignment
implemented, tested, and working correctly.
Add other starting point methods that initialize the world to
different configurations. There are many that will lead to
interesting patterns that repeat forever or that converge to a static
pattern. Look online for some examples.
Submit
Once you are satisfied with your program, hand it in by typing
handin21b in a terminal window.