11# Homework 2: Predator-Prey Agents
22
33In this lab you will continue working on your agent simulation. If you did not
4- manage to finish the homework, do not worry, you can use the code below which
5- contains all the functionality we developed in the lab.
6-
7- ``` @raw html
8- <details class = "solution-body">
9- <summary class = "solution-header">Solution of Lab 2:</summary><p>
4+ manage to finish the homework, do not worry, you can use [ this
5+ script ] ( https://github.com/JuliaTeachingCTU/Scientific-Programming-in-Julia/blob/master/src/Lab02Ecosystem.jl )
6+ which contains all the functionality we developed in the lab.
7+ ``` @setup hw02
8+ projdir = dirname(Base.active_project())
9+ include(joinpath(projdir,"..","src","Lab02Ecosystem.jl"))
1010```
11- ``` @example hw02
12- using StatsBase
1311
14- abstract type Agent end
15- abstract type Animal <: Agent end
16- abstract type Plant <: Agent end
12+ ## How to submit?
1713
18- mutable struct World{A<:Agent}
19- agents::Dict{Int,A}
20- max_id::Int
21- end
22- function World(agents::Vector{<:Agent})
23- World(Dict(id(a)=>a for a in agents), maximum(id.(agents)))
24- end
14+ Put all your code (including your or the provided solution of lab 2) in a
15+ script named ` hw.jl ` alongside with the ` Project.toml ` and ` Manifest.toml ` of
16+ the environment. Please only include packages in the environment that are
17+ necessary for the homework. Create a ` .zip ` archive of the three files and
18+ send it to the lab instructor, who has assigned the task, via email (contact
19+ emails are located on the [ homepage] (@ref emails) of the course).
2520
26- # optional: you can overload the `show` method to get custom
27- # printing of your World
28- function Base.show(io::IO, w::World)
29- println(io, typeof(w))
30- for (_,a) in w.agents
31- println(io," $a")
32- end
33- end
34-
35- function world_step!(world::World)
36- # make sure that we only iterate over IDs that already exist in the
37- # current timestep this lets us safely add agents
38- ids = deepcopy(keys(world.agents))
39-
40- for id in ids
41- # agents can be killed by other agents, so make sure that we are
42- # not stepping dead agents forward
43- !haskey(world.agents,id) && continue
44-
45- a = world.agents[id]
46- agent_step!(a,world)
47- end
48- end
49-
50- function agent_step!(a::Plant, w::World)
51- if size(a) != max_size(a)
52- grow!(a)
53- end
54- end
55-
56- function agent_step!(a::Animal, w::World)
57- incr_energy!(a,-1)
58- if rand() <= foodprob(a)
59- dinner = find_food(a,w)
60- eat!(a, dinner, w)
61- end
62- if energy(a) <= 0
63- kill_agent!(a,w)
64- return
65- end
66- if rand() <= reprprob(a)
67- reproduce!(a,w)
68- end
69- return a
70- end
71-
72- mutable struct Grass <: Plant
73- id::Int
74- size::Int
75- max_size::Int
76- end
77-
78- mutable struct Sheep <: Animal
79- id::Int
80- energy::Float64
81- Δenergy::Float64
82- reprprob::Float64
83- foodprob::Float64
84- end
85-
86- mutable struct Wolf <: Animal
87- id::Int
88- energy::Float64
89- Δenergy::Float64
90- reprprob::Float64
91- foodprob::Float64
92- end
93-
94- id(a::Agent) = a.id # every agent has an ID so we can just define id for Agent here
95-
96- Base.size(a::Plant) = a.size
97- max_size(a::Plant) = a.max_size
98- grow!(a::Plant) = a.size += 1
99-
100- # get field values
101- energy(a::Animal) = a.energy
102- Δenergy(a::Animal) = a.Δenergy
103- reprprob(a::Animal) = a.reprprob
104- foodprob(a::Animal) = a.foodprob
105-
106- # set field values
107- energy!(a::Animal, e) = a.energy = e
108- incr_energy!(a::Animal, Δe) = energy!(a, energy(a)+Δe)
109-
110- function eat!(a::Sheep, b::Grass, w::World)
111- incr_energy!(a, size(b)*Δenergy(a))
112- kill_agent!(b,w)
113- end
114- function eat!(wolf::Wolf, sheep::Sheep, w::World)
115- incr_energy!(wolf, energy(sheep)*Δenergy(wolf))
116- kill_agent!(sheep,w)
117- end
118- eat!(a::Animal,b::Nothing,w::World) = nothing
119-
120- kill_agent!(a::Plant, w::World) = a.size = 0
121- kill_agent!(a::Animal, w::World) = delete!(w.agents, id(a))
122-
123- function find_food(a::Animal, w::World)
124- as = filter(x->eats(a,x), w.agents |> values |> collect)
125- isempty(as) ? nothing : sample(as)
126- end
127-
128- eats(::Sheep,::Grass) = true
129- eats(::Wolf,::Sheep) = true
130- eats(::Agent,::Agent) = false
131-
132- function reproduce!(a::A, w::World) where A<:Animal
133- energy!(a, energy(a)/2)
134- a_vals = [getproperty(a,n) for n in fieldnames(A) if n!=:id]
135- new_id = w.max_id + 1
136- â = A(new_id, a_vals...)
137- w.agents[id(â)] = â
138- w.max_id = new_id
139- end
140- nothing # hide
141- ```
142- ``` @raw html
143- </p></details>
144- ```
14521
14622## Counting Agents
14723
@@ -153,7 +29,7 @@ quantity.
15329
15430``` @raw html
15531<div class="admonition is-category-homework">
156- <header class="admonition-header">Homework (2 points)</header>
32+ <header class="admonition-header">Compulsory Homework (2 points)</header>
15733<div class="admonition-body">
15834```
159351 . Implement a function ` agent_count ` that can be called on a single
18763
18864``` @repl hw02
18965grass1 = Grass(1,5,5);
66+ agent_count(grass1)
67+
19068grass2 = Grass(2,1,5);
69+ agent_count([grass1,grass2]) # one grass is fully grown; the other only 20% => 1.2
70+
19171sheep = Sheep(3,10.0,5.0,1.0,1.0);
19272wolf = Wolf(4,20.0,10.0,1.0,1.0);
19373world = World([grass1, grass2, sheep, wolf]);
194-
195- agent_count(world) # one grass is fully grown; the other only 20% => 1.2
74+ agent_count(world)
19675```
19776
19877Hint: You can get the * name* of a type by using the ` nameof ` function:
@@ -208,7 +87,7 @@ Use as much dispatch as you can! ;)
20887
20988``` @raw html
21089<div class="admonition is-category-exercise">
211- <header class="admonition-header">Exercise (voluntary)</header>
90+ <header class="admonition-header">Voluntary Exercise (voluntary)</header>
21291<div class="admonition-body">
21392```
21493Using the world below, run few ` world_step! ` s. Plot trajectories of the agents
0 commit comments