; CSC104 2017 Fall, Project II.
;
; A Program to Model and Visualize the Spread of an Infection.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; AFTER YOU HAVE IMPLEMENTED THE ENTIRE PROGRAM, play with it, adjusting the settings.
;
; Try to find some settings that produce a delicate balance of the spread of infection:
; when running it a few times with those settings can produce visibly different outcomes.
; Also try large and small values, and view the effects.
; Write a couple of paragraphs here summarizing some of your findings:
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; IMPLEMENTATION REQUIREMENTS.
; For each function: uncomment any commented-out check-expects, study them and the description
; of the function, and if you are asked to implement or fix the function then do so.
; Uncomment any definitions that use those functions.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Some list functions.
(require (only-in racket take drop)) ; Imports two fast list functions.
; take : list number list
; drop : list number list
; These function take a list, and a number for how many elements to keep or remove:
(check-expect (take (list gnu fox bee) 2) (list gnu fox))
(check-expect (drop (list gnu fox bee) 2) (list bee))
; A function to make a list with a repeated element.
; constant-list : number any list
(check-expect (constant-list 3 cat) (list cat cat cat))
(check-expect (constant-list 3 cat) (repeated identity cat 3))
; Fix constant-list.
(define (constant-list a-length an-element)
(list))
; Functions to move elements from the front to the back of a list, or vice versa.
; left-cycle : list number list
; right-cycle : list number list
#;(check-expect (left-cycle (list gnu fox bee) 0) (list gnu fox bee))
#;(check-expect (left-cycle (list gnu fox bee) 1) (list fox bee gnu))
#;(check-expect (left-cycle (list gnu fox bee) 2) (list bee gnu fox))
#;(check-expect (left-cycle (list gnu fox bee) 2) (append (list bee) (list gnu fox)))
#;(check-expect (right-cycle (list gnu fox bee) 0) (list gnu fox bee))
#;(check-expect (right-cycle (list gnu fox bee) 1) (list bee gnu fox))
#;(check-expect (right-cycle (list gnu fox bee) 2) (list fox bee gnu))
#;(check-expect (right-cycle (list gnu fox bee) 2)
(append (drop (list gnu fox bee) (- 3 2))
(take (list gnu fox bee) (- 3 2))))
; Implement left-cycle.
; Implement right-cycle.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Managing the Statuses of the Subjects in the Simulation.
; The behaviour of the simulation depends on three numeric settings:
;
; Virulence how likely an infectable person becomes infected
; Duration how long an infected person stays infected
; Immunity how long a person stays immune after an infection ends
;
; Those settings will be stored and passed around in a list.
;
; Using setting names for functions that access them helps us keep track of the order.
;
; virulence : list number
; duration : list number
; immunity : list number
(check-expect (virulence (list 20 10 15)) 20)
(define virulence first)
; That could also have been defined by:
#;(define (virulence some-settings) (first some-settings))
#;(check-expect (duration (list 20 10 15)) 10)
; Implement duration.
#;(check-expect (immunity (list 20 10 15)) 15)
; Implement immunity.
#;(check-expect (virulence-duration-immunity 20 10 15) (list 20 10 15))
; Implement virulence-duration-immunity.
; Some initial settings for the simulation.
#;(define initial-settings (virulence-duration-immunity 20 10 15))
; Infection Status.
;
; A person is either:
;
; Infectable.
; This is represented by zero, and shown as a blue dot.
;
; Infected, with a certain number of days of infection left.
; This is represented by a number which is the *negative* of the number
; of days of infection left, and shown as a red dot.
;
; Immune, with a certain number of days of immunity left.
; This is represented by a *positive* number which is the number of days
; of immunity left, and shown as a green dot.
; Predicates to make reading the code more meaningful:
; infectable? : number boolean
; infected? : number boolean
; immune? : number boolean
#;(check-expect (infectable? -2) #false)
#;(check-expect (infectable? 0) #true)
#;(check-expect (infectable? 3) #false)
#;(check-expect (infected? -2) #true)
#;(check-expect (infected? 0) #false)
#;(check-expect (infected? 3) #false)
#;(check-expect (immune? -2) #false)
#;(check-expect (immune? 0) #false)
#;(check-expect (immune? 3) #true)
; Implement those three functions, and use them where appropriate when checking statuses later.
; A function to produce the initial list of unifected statuses, except for one person on the edge
; of the wrap-around world who starts infected for Duration days.
; initial-statuses : number number list list
#;(define (initial-statuses width height some-settings)
(local [(define dots (* width height))
(define dots/2 (quotient dots 2))]
(append (constant-list dots/2 0)
(list (- (duration some-settings)))
(constant-list (- (- dots dots/2) 1) 0))))
#;(check-expect (initial-statuses 2 3 (virulence-duration-immunity 20 10 15))
(list 0 0
0 -10
0 0))
; A function to produce the colour representing a persons status.
; status-colour : number list
#;(check-expect (status-colour -2) (list 100 0 0))
#;(check-expect (status-colour 0) (list 0 0 100))
#;(check-expect (status-colour 3) (list 0 100 0))
; Fix status-colour.
#;(define (status-colour a-status)
(cond [(infected? a-status) (list 0 0 0)]
[else (list 0 0 0)]))
; A function to update a persons status.
;
; update-status : number number
;
; If infectable, stay infectable.
; If infected, become infected for one less day, except if that makes the person uninfected
; then they become immune for the number of days of immunity specified in the settings.
; If immune, become immune for one less day.
#;(check-expect (update-status 0 (virulence-duration-immunity 20 10 15)) 0)
#;(check-expect (update-status -2 (virulence-duration-immunity 20 10 15)) -1)
#;(check-expect (update-status -1 (virulence-duration-immunity 20 10 15)) 15)
#;(check-expect (update-status 3 (virulence-duration-immunity 20 10 15)) 2)
; Fix update-status.
#;(define (update-status a-status some-settings)
a-status)
; A function to update everyones duration of infection and immunity in a list of statuses.
; update-statuses : list-of-numbers list-of-numbers
#;(check-expect (update-statuses (list 3 -1 0 -2)
(virulence-duration-immunity 20 10 15))
(list 2 15 0 -1))
#;(check-expect (update-statuses (list 3 -1 0 -2)
(virulence-duration-immunity 20 10 15))
(local [(define (update a-status)
(update-status a-status
(virulence-duration-immunity 20 10 15)))]
(list (update 3)
(update -1)
(update 0)
(update -2))))
; Fix update-statuses.
#;(define (update-statuses some-statuses some-settings)
some-statuses)
; A function to possibly infect a subject.
;
; Produce the status representing an infection of Duration days if:
; the status represents someone infectable,
; neighbour-0 or neighbour-1 or neighbour-2 or neighbour-3 is a status for someone infected, and
; the Virulence is more than this randomly chosen number: (random 100).
; Otherwise: leave the subject alone.
;
; infect : number number number number number list number
#;(check-expect (or (infectable? (infect 0 -1 2 -3 4 (virulence-duration-immunity 20 10 15)))
(infected? (infect 0 -1 2 -3 4 (virulence-duration-immunity 20 10 15))))
#true)
#;(check-expect (infectable? (infect 0 -1 2 -3 4 (virulence-duration-immunity 0 10 15)))
#true)
#;(check-expect (infected? (infect 0 -1 2 -3 4 (virulence-duration-immunity 100 10 15)))
#true)
#;(check-expect (infectable? (infect 0 1 -2 3 -4 (virulence-duration-immunity 0 10 15)))
#true)
#;(check-expect (infected? (infect 0 1 -2 3 -4 (virulence-duration-immunity 100 10 15)))
#true)
#;(check-expect (infect 0 1 -2 3 -4 (virulence-duration-immunity 100 10 15))
(- (duration (virulence-duration-immunity 100 10 15))))
#;(check-expect (infect 0 -1 2 -3 4 (virulence-duration-immunity 100 10 15))
(- (duration (virulence-duration-immunity 100 10 15))))
#;(check-expect (infect -1 0 -2 3 -4 (virulence-duration-immunity 20 10 15))
-1)
#;(check-expect (infect 2 0 3 -4 5 (virulence-duration-immunity 20 10 15))
2)
#;(check-expect (infect 0 1 0 2 0 (virulence-duration-immunity 20 10 15))
0)
; Due to the randomness, a check-expect that tests that an infectable subject can be infected
; is a bit tricky to do properly. Here is an approach that should rarely fail.
#;(define (try-to-infect unused-parameter)
(infect 0 -1 2 -3 4 (virulence-duration-immunity 20 10 15)))
#;(check-expect (member? (- (duration (virulence-duration-immunity 20 10 15)))
(map try-to-infect (range 0 10000 1)))
#true)
#;(check-expect (member? 0
(map try-to-infect (range 0 10000 1)))
#true)
; Fix infect.
#;(define (infect subject neighbour-0 neighbour-1 neighbour-2 neighbour-3
some-settings)
subject)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Settings Management and big-bang Functions.
;
; These are all implemented: you can uncomment any commented-out definitions, and the big-bang
; expression that is at the end of the file.
; The width and height of the world.
(define WIDTH 100)
(define HEIGHT 100)
; The current settings and list of statuses are bundled together in a list.
(define settings-and-statuses list)
(define settings first)
(define statuses second)
(require (only-in racket map)) ; Imports a version of map that works with more than two lists.
; Update each persons status, possibly infecting some of them, based on the settings.
; day-tick : list list
#;(define (day-tick the-settings-and-statuses)
(local [(define the-statuses (statuses the-settings-and-statuses))
(define the-settings (settings the-settings-and-statuses))
(define (infector status n-0 n-1 n-2 n-3)
(infect status n-0 n-1 n-2 n-3 the-settings))]
(settings-and-statuses the-settings
(update-statuses (map infector
the-statuses
(left-cycle the-statuses 1)
(right-cycle the-statuses 1)
(left-cycle the-statuses WIDTH)
(right-cycle the-statuses WIDTH))
the-settings))))
; An image showing name and number, separated by a colon and space.
; setting->image : string number image
(define (setting->image name number)
(string->image (string-append name : (number->string number)) 16 black))
; An image of the grid of the statuses, with settings drawn underneath.
; draw-statuses : list image
#;(define (draw-statuses the-settings-and-statuses)
(above (colors->image (map status-colour (statuses the-settings-and-statuses))
WIDTH HEIGHT)
(setting->image virulence (virulence (settings the-settings-and-statuses)))
(setting->image duration (duration (settings the-settings-and-statuses)))
(setting->image immunity (immunity (settings the-settings-and-statuses)))))
; Update the settings and reset the statuses, when a key is pressed.
; change-settings : list string list
#;(define (change-settings the-settings-and-statuses a-key)
(local [(define the-settings (settings the-settings-and-statuses))
(define (with-new-settings virulence-change duration-change immunity-change)
(local [(define new-settings (virulence-duration-immunity
(+ (virulence the-settings) virulence-change)
(+ (duration the-settings) duration-change)
(+ (immunity the-settings) immunity-change)))]
(settings-and-statuses new-settings (initial-statuses WIDTH HEIGHT new-settings))))]
(cond [(equal? a-key 1) (with-new-settings -1 0 0)]
[(equal? a-key 2) (with-new-settings +1 0 0)]
[(equal? a-key 3) (with-new-settings 0 -1 0)]
[(equal? a-key 4) (with-new-settings 0 +1 0)]
[(equal? a-key 5) (with-new-settings 0 0 -1)]
[(equal? a-key 6) (with-new-settings 0 0 +1)]
[else (with-new-settings 0 0 0)])))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Uncomment the big-bang expression and run the file to play with the simulation!
;
; You can adjust the settings by pressing one of the keys: 1, 2, 3, 4, 5, or 6.
; Pressing any other key starts the simulation again, without changing the current settings.
#;(big-bang (settings-and-statuses initial-settings (initial-statuses WIDTH HEIGHT initial-settings))
[on-tick day-tick]
[to-draw draw-statuses]
[on-key change-settings])
Reviews
There are no reviews yet.