In this example, we 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.
We will complete the steps below to build this simulation in Ruby.
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.
Sample solution:
def display(matrix)
for row in 0..matrix.length-1 do
for col in 0..matrix[row].length-1 do
person = matrix[row][col]
if person == 0 then
color = "white"
end
if person == 1 then
color = "pink"
end
if person >= 2 and person <= 5 then
color = "red"
end
if person == 6 then
color = "purple"
end
Canvas::Rectangle.new(col*10, row*10, col*10+10, row*10+10,
:fill => color, :outline => "black")
end
end
end
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.
Sample solution:
def immune?(matrix, i, j)
if matrix[i][j] == 6 then
return true
else
return false
end
end
def contagious?(matrix, i, j)
if matrix[i][j] >= 2 and matrix[i][j] <= 5 then
return true
else
return false
end
end
def infected?(matrix, i, j)
if matrix[i][j] == 1 then
return true
else
return false
end
end
def healthy?(matrix, i, j)
if matrix[i][j] == 0 then
return true
else
return false
end
end
def update(matrix)
#create new matrix, initialized to all zeroes
newmatrix = Array.new(20)
for i in 0..19 do
newmatrix[i] = Array.new(20)
for j in 0..19 do
newmatrix[i][j] = 0
end
end
#create next day
for i in 0..19 do
for j in 0..19 do
if immune?(matrix, i, j) then
newmatrix[i][j] = 6
end
if infected?(matrix, i, j) or contagious?(matrix, i, j) then
newmatrix[i][j] = matrix[i][j] + 1
end
if healthy?(matrix, i, j) then
for k in 1..4 do # repeat 4 times
if contagious?(matrix, rand(20), rand(20)) then
newmatrix[i][j] = 1
end
end
end
end
end
return newmatrix
end