- [11/30/2012] Clarification on update-CA3.
When I say (about update-CA3)
“instead of producing a new grid,
it should have the side effect that all the cells have updated their states,”
my intention is to place emphasis on new.
That is, your function should still return a grid -- in fact, it should return the same grid --
only the cells stored within the grid have updated their states.
Cellular Automata: Part 3,
For the final project deliverable,
you will revise your implementation of Conway's Game of Life
to utilize our version of object-oriented design.
The cells in your grid will now be objects as described in class.
You will use the principles covered in class and in Sections 39-41
to create a cell class that encapsulates appropriate state variables and services
relevant to a cell.
Thus, a cell will be a service manager function
that consumes messages and provides access to services.
Definitions and other details
We are only changing the underlying representation of cells.
Now, a cell will be an object, or in the terminology of your text, an interface.
Your cell objects must respond to the following messages
and provide the appropriate services:
- 'show-self:: image (returns the appropriate image corresponding to this cell's current state)
- 'current:: 1 or 0 (returns this cell's current state)
- 'determine-new: (void) (causes this cell to compute, but not switch to, it's new state)
- 'switch-to-new: (void) (causes this cell to change to its previously computed new state)
- 'set-state:: ( number -> (void) ) (sets the cell's state to the given value;
useful if you want to reset the grid to a particular configuration)
The key problem you may immediately notice is,
How will a cell know its neighbors?
Note that your grid definition, (vectorof (vectorof cell)),
has changed implicitly by way of the new definition of a cell.
So how can a cell access its neighbors?
A good approach for this is to provide
a cell's row and column as well as the grid itself as arguments to the cell constructor
when you first create a cell-object.
Note, each cell should only get created once and then persist throughout the simulation.
Using this approach, a cell has ready access to its neighbors,
since it has its own coordinates within the grid and the grid as a whole.
However, as you create the cell objects, you may need to store them in their appropriate grid locations
Finally, you'll need to make minor alterations to the rest of your program
that displays the grid and updates it.
The basic approach you'll want to use is to have all of the cell-objects
‘determine-new’ by querying the ‘current’ state of their respective neighbors,
and then have all the cell-objects ‘switch-to-new’.
Finally, have all the cell-objects ‘show-self’ according to their (new) current states.
You'll want to repeat this sequence
as many times as needed.
Your main function, oo-cgol,
should accept (as before) two arguments -- a number of times to simulate updates
and an initial grid.
And of course,
oo-cgol should simulate the generations of the grid according to the rules for
Conway's Game of Life from the second deliverable.
- Top-level constants. As before, you should have top-level identifiers:
CELL-SIZE for the size of a rendered cell
(either diameter or square edge length);
WRAP? that when true causes cells on the edge of the grid
to be treated as neighbors of cells on the opposite edges.
The size of your display should depend on the CELL-SIZE
and the number of rows and columns in your grid.
- Cell constructor. Define a cell ‘class’
with a constructor called make-cell-object.
This constructor should consume four arguments (in order),
an initial state (either 1 or 0), a row index, a column index,
and a grid in which the cell object resides.
Your cell objects must support the messages and services described above.
- Random grid. Modify your function, random-grid
that consumes two numbers for row and columns
and a third number for the probability of a live cell.
Your function should return a grid (as defined with vectors above)
that has been appropriately initialized with cell objects.
- Updating grids. Write the function, update-CA3,
using your previous code for update-CA2.
As before, the function should consume and return a grid.
However, instead of producing a new grid,
it should have the side effect that all the cells have updated their states.
That is, cells must persist.
As before, the updates around the edges
should reflect the current value of WRAP?.
- Rendering grids. Write a function, draw-CA3,
that ideally will be a modest revision of your draw-CA2 function.
Your draw-CA3 should consume a grid under our new definitions and return an image.
The size of the resulting image should reflect the CELL-SIZE
and the number of rows and columns in the given grid.
- Animating the Game of Life. Write a function, oo-cgol,
that consumes a number and a grid.
The number specifies how many generations to simulate,
after which the animation should stop.
The given grid represents the initial state of the cellular automata
that is subsequently updated/animated.
The number of rows and columns necessarily follows
from the initial grid that is provided;
this should determine the height and width of your animated display.
Do not forget to include the standard acknowledgements header
at the top of your file.
To grade this deliverable, I will review your code (including
contracts, purpose statements, test cases, indentation, etc.),
and then call oo-cgol
with a given number of steps to simulate
and an initial organism of my choosing.
Submit a single file with your username followed by “P3.rkt” as the name of the file,
which should contain your code fulfilling the above requirements
as well as your acknowledgements.