Overview
The simple-model.rkt
module defines a simple, deterministic, model for
testing purposes. As discussed in the previous step,
a model is defined by a function for generating the initial grid, a function
for update the grid, and a predicate for testing if the grid has stabilized.
We ignore the initial grid for the moment and focus on the other two components:
The Simple Model
The simple model uses the following rules:
-
A cell can be either Well, Ill, or Immune.
-
If a Well cell has two or more Ill neighbors, then the cell becomes Ill.
-
A cell remains Ill for five simulation steps, at which point the cell becomes Immune.
-
The simulation is stable when either every cell is Immune or there are no Well cells with two or more Ill neighbors.
Cells
The first step is to define a representation of cells in the grid: Add the following definitions to your code:
;; the health of a cell
(define-type Health (U 'Well 'Ill 'Immune))
;; A (Cell health ticks) represents the state of a grid cell, where health is the current
;; health of the cell and ticks is the number of simulation steps until an ill cell
;; turns immune. If the cell is not ill, then ticks should be 0.
(define-struct Simple-Cell
([health : Health]
[recovery-time : Integer]))
(: is-ill? : Simple-Cell -> Boolean)
(define (is-ill? cell) (symbol=? (Simple-Cell-health cell) 'Ill))
;; a grid of cells in the simple model
(define-type Simple-Grid (Grid Simple-Cell))
Updating the Grid
Update the grid for a simulation step basically requires updating every cell according to the above rules. Implement a function with the following signature
(: update-cell : Simple-Grid -> Coord Simple-Cell -> Simple-Cell)
that takes a grid argument and returns a function for updating individual cells. With this function in hand, it is easy to define a function for updating the whole grid:
(: update-grid : Simple-Grid -> Simple-Grid)
;; update the grid for one time step
(define (update-grid grid)
(grid-map-with-coord (update-cell grid) grid))
Checking for a Stable Grid
You should implement the following function that tests if a grid is stable (as described above):
(: stable? : Simple-Grid -> Boolean)
Since both this function and the update-cell
function require counting the number
of Ill neighbors, you may be able to factor out common code into a helper function.
Building a Model
Since the main purpose of the simple model is to serve as a test case for the other parts of the project, we want to be able to specify specific initial grids. We do this by supplying a list of initial cell values that are used to update an initial grid where everyone is Well.
Add the following utility type definition to the simple-model.rkt
file:
;; A specified initial cell value
(define-struct Simple-Init-Cell
([coord : Coord]
[health : Health]
[recovery-time : Integer]))
We provide the following function for generating an initial grid:
(: initial-grid : (Listof Simple-Init-Cell) -> Natural Natural -> Simple-Grid)
;; generate an initial grid from a list of initial cell values and
;; the grid dimensions.
(define (initial-grid init-cells)
(lambda ([nr : Natural] [nc : Natural])
(local
{(: update : Simple-Init-Cell Simple-Grid -> Simple-Grid)
;; update a single cell as specified by the initial cell value
(define (update init-cell grid)
(match init-cell
[(Simple-Init-Cell (Coord r c) h t)
(grid-set grid (Coord (modulo r nr) (modulo c nc)) (Simple-Cell h t))]))}
;; apply the update operation for each initial cell value
(foldl update
(build-grid nr nc (lambda ([c : Coord]) (Simple-Cell 'Well 0)))
init-cells))))
The you can define a function make-simple-model
that takes a list of
initial cell values and returns a Simple-Cell
model.
(: make-simple-model : (Listof Simple-Init-Cell) -> (Model Simple-Cell))
Rendering
The simple-model.rkt
file also defines support for rendering cells
in the simple model. Draw the cells as circles with black outlines and where
the fill color depends on the health of the cell.
Implement a function for creating the rendering information for the
simple model from the cell radius and the refresh rate:
(: render-simple-model : Integer Positive-Real -> (Render-Info Simple-Cell))
Exports
;; ===== Exports =====
(provide (struct-out Simple-Init-Cell)
Simple-Cell
Simple-Grid)
(provide make-simple-model
render-simple-model)