For this assignment, you will create a Ruby source file containing a Ruby function(s) implementing each of the problems described below. If you find it useful for any of the problems in this assignment, you may define additional helper functions that your primary function for that problem calls to solve a sub-problem. Definitions for these helper functions should be included in the same Ruby source file as the primary function they help. You should store a source file for each problem in a folder named pa10.
Note: You are responsible for protecting your solutions to these problems from being seen by other students either physically (e.g., by looking over your shoulder) or electronically. (More information can be found in the instructions for Programming Assignment 2.)
In this assignment, you will develop a simple graphical simulation that shows how disease spreads through a population. Each time step of the simulation represents one day. A person starts off as healthy. Each day, a healthy person comes in contact with four random people. If any of those random people is contagious, then the healthy person becomes infected. It takes one day for the infected person to become contagious. After a person has been contagious for 4 days, then the person is non-contagious and cannot spread the virus nor can the person get the virus again due to immunity.
This simulation will show how the virus spreads in a population of 400 people, represented by a square 20 × 20 matrix. On the first day of the simulation, one person becomes infected with the virus.
Here is a sample of what the first eight "days" of the simulation might look like:
Each snapshot above is a time step of the simulation shown in a 200 × 200 window (in pixels). Notice that the window is "divided" up into 10 × 10 squares (in pixels). Each of these 400 squares represents one person in the simulated population.
To perform the simulation, you will need to use the Canvas object in RubyLabs. When you initialize a Canvas, you need to supply the size of the window and a title for the window. For example:
Canvas.init(200, 200, "Virus_Simulation")
creates a window of size 200 × 200 (in pixels) with a title of "Virus_Simulation". The origin of this window is at the top left corner (0,0), with the x coordinate increasing as you go from left to right, and the y coordinate increasing as you go from top to bottom.
To draw a square of size 10 × 10 with a fill color of green and an outline (border) of blue and its top left corner at coordinate (100,100) in the Canvas, we can execute:
Canvas::Rectangle.new(100, 100, 110, 110, :fill=>"green", :outline=>"blue")
The first two parameters are the top left coordinates (x,y) of the rectangle and the next two parameters are the bottom right coordinates (x,y) of the rectangle. The final two parameters specify the fill color and the outline (border) color as strings.
Complete the problems below to build this simulation in Ruby.
[3 points] Write a function display(matrix) (in the file display.rb). The parameter is a 20 X 20 matrix representing the population for the simuation. Each person is a cell of the matrix. Each cell has an integer in the range 0 through 6 (inclusive), which encodes the person's health as follows:
0 healthy, not infected 1 infected 2 contagious (day 1) 3 contagious (day 2) 4 contagious (day 3) 5 contagious (day 4) 6 non-contagious/immune
Your function should go through the entire matrix and display each "person" as a square of size 10 pixels X 10 pixels in one of the following colors:
white healthy, not infected pink infected red contagious purple non-contagious/immune
General algorithm:
Test your function using this Ruby function that creates a matrix of size 20 × 20 and fills each cell with a random integer between 0 and 6:
def test_display() # create a canvas of size 200 X 200 Canvas.init(200, 200, "Testing_Display") # initialize matrix a randomly a = Array.new(20) for i in 0..19 do a[i] = Array.new(20) for j in 0..19 do a[i][j] = rand(7) end end # display the matrix using your display function display(a) end
Sample Usage:
>> load "display.rb" => true >> load "test_display.rb" => true >> test_display()
Your image will differ since we're using a random number generator.
[4 points] Write a function update(matrix) (in the file update.rb). This function takes a 20 × 20 matrix representing our population, as described above, for the current time step of the simulation, and returns a new 20 × 20 matrix representing our population during the next time step (i.e. after one day has passed).
The basic idea here is that we start with the current population in the array matrix and create a new snapshot of the population after one time step in an array new_matrix. Each cell new_matrix[row][column] represents the new status of the person from matrix[row][column].
General Algorithm:
Test your update function using the following function:
def test_update() # create a canvas of size 200 X 200 Canvas.init(200, 200, "Testing_Update") # initialize matrix a to all healthy individuals a = Array.new(20) for i in 0..19 do a[i] = Array.new(20) for j in 0..19 do a[i][j] = 0 end end # infect one random person a[rand(20)][rand(20)] = 1 display(a) sleep(2) # run the simulation for 10 "days" for day in 1..10 do a = update(a) display(a) sleep(2) end end
Sample usage:
>> load "display.rb" => true >> load "update.rb" => true >> load "test_update.rb" => true >> test_update()
NOTE: For this problem, if an individual is healthy and you pick 4 random people to come in contact with, it is ok if you pick the same person twice or if you pick the current individual you are testing.
[2 points] Write a function all_immune(matrix) (in the file all_immune.rb) that takes a 20 × 20 matrix that represents our population of 400 people, and returns true if EVERYONE is immune, and false otherwise.
We will use this function to complete our simulation, having the simulation stop once the entire population has become non-contagious/immune.
Use the following function to test your final simulation:
def run_simulation() # create a canvas of size 200 X 200 Canvas.init(200, 200, "Simulation") # initialize matrix a a = Array.new(20) for i in 0..19 do a[i] = Array.new(20) for j in 0..19 do a[i][j] = 0 end end # infect one random person a[rand(20)][rand(20)] = 1 display(a) sleep(2) # run simulation until everyone is immune while !all_immune(a) do a = update(a) display(a) sleep(2) end end
Sample usage:
>> load "display.rb" => true >> load "update.rb" => true >> load "all_immune.rb" => true >> load "run_simulation.rb" => true >> run_simulation()
[1 point] Create a new version of the simulation function from problem 3, named run_simulation_v2, that starts with n random infected people, where n is given as a parameter to the function. You may assume n is positive and is not greater than 400.
Sample usage (to start with 5 randomly infected people):
>> load "display.rb" => true >> load "update.rb" => true >> load "all_immune.rb" => true >> load "run_simulation_v2.rb" (CORRECTED) => true >> run_simulation_v2(5)
CAUTION: This is trickier than you might think. If you just pick n random positions in the matrix, you might pick the same position more than once! We want n different people in this problem.
You should now have a pa10 directory that contains the required files, display.rb, update.rb, all_immune.rb, and run_simulation_v2.rb, each—in turn—containing the corresponding function(s). Zip up your directory and upload it using the handin system. (The handin system will accept submissions beginning on Friday until the deadline Tuesday night. Submissions after the deadline but before the late deadline will be marked on our system as "late".)