forked from AaltoRSE/julia-introduction
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathepidemic.jl
146 lines (132 loc) · 3.95 KB
/
epidemic.jl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
using Plots
"Enumerate possible states of a single plant"
@enum InfectionStatus uninfected infected dead recovered immune
"Data structure containing the infection status of a plant"
mutable struct Plant
status::InfectionStatus
infection_time::Int8
end
"Parameters for a simulation"
mutable struct Parameters
infection_rate::Float32
death_probability::Float32
recovery_time::Int8
immunity_rate::Float32
end
"Create a map of immune and uninfected plants with 1 infected in the middle."
function make_plants(width::Integer=7, height::Integer=7, immunity_rate::Float64=0.0)
plants = Matrix{Plant}(undef, width, height)
for i in 1:size(plants)[1]
for j in 1:size(plants)[2]
if rand(1)[1] < immunity_rate
plants[i,j] = Plant(immune, 0)
else
plants[i,j] = Plant(uninfected, 0)
end
end
end
plants[width÷2+1,height÷2+1] = Plant(infected, 0)
return plants
end
"Show the plant as an empty or a filled in box for quick viewing"
function Base.show(io::IO, plant::Plant)
if plant.status == infected
print(io, "◼")
else
print(io, "◻")
end
end
"Map the plants to colors for plotting"
function to_colors(plant::Plant)
if plant.status == uninfected
return RGB(0.0,0.8,0.0)
end
if plant.status == infected
return RGB(0.8,0.0,0.0)
end
if plant.status == dead
return RGB(0.1,0.1,0.1)
end
if plant.status == recovered
return RGB(0.0,0.0,0.8)
end
if plant.status == immune
return RGB(0.2,0.2,1.0)
end
end
"""
Simulate the interaction between one plant and a neighbour.
If the neighbour is infected, it infect this plant with the propability parameters.infection_rate.
"""
function interact!(new_plant::Plant, other_plant::Plant, infection_rate)
if new_plant.status == uninfected && other_plant.status == infected
if rand(1)[1] < infection_rate
new_plant.status = infected
new_plant.infection_time = 0
end
end
end
"""
Update a single plant, not accounting for it's interactions with the neighbours.
"""
function update!(new_plant::Plant, recovery_time, death_rate)
if new_plant.status == infected
# Increase the number of time steps since infection
new_plant.infection_time += 1
# Check if the plant recovers
if new_plant.infection_time > recovery_time
new_plant.status = recovered
end
# Check if it dies
if rand(1)[1] < death_rate
new_plant.status = dead
end
end
end
"""
Update the plants in the 2D array of plants, using given parameters.
"""
function update!(plants::Matrix{Plant}, recovery_time, death_rate, infection_rate)
old_plants = deepcopy(plants)
for i in 1:size(plants)[1]
for j in 1:size(plants)[2]
update!(plants[i,j], recovery_time, death_rate)
end
end
for i in 1:size(plants)[1]-1
for j in 1:size(plants)[2]
interact!(plants[i,j], old_plants[i+1,j], infection_rate)
interact!(plants[i+1,j], old_plants[i,j], infection_rate)
end
end
for i in 1:size(plants)[1]
for j in 1:size(plants)[2]-1
interact!(plants[i,j], old_plants[i,j+1], infection_rate)
interact!(plants[i,j+1], old_plants[i,j], infection_rate)
end
end
end
"Count the current number of infections"
function count_infections(plants::Matrix{Plant})
infections = 0
for i in 1:size(plants)[1]
for j in 1:size(plants)[2]
if plants[i,j].status == infected
infections += 1
end
end
end
return infections
end
"Count the number of dead plants"
function count_deaths(plants::Matrix{Plant})
deaths = 0
for i in 1:size(plants)[1]
for j in 1:size(plants)[2]
if plants[i,j].status == dead
deaths += 1
end
end
end
return deaths
end