In [2]:
using Bokeh
setupnotebook()
In [3]:
abstract Animal
midrand() = rand() - 0.5
prednames = [:Tiger, :Lion, :Eagle]
type Preditor <: Animal
breed::Symbol
alive::Bool
x::Float64; y::Float64
heading::Float64; speed::Float64
route::Vector{(Float64, Float64)}
eaten::Int
Preditor(breed::Symbol) = new(breed, true, 5midrand(), 5midrand(),
rand()*2pi, 0, Array((Float64, Float64), 0), 0)
end
function Preditor()
Preditor(prednames[rand(1:length(prednames))])
end
preynames = [:Goat, :Sheep, :Horse, :Deer, :Chicken]
type Prey <: Animal
breed::Symbol
alive::Bool
x::Float64; y::Float64
heading::Float64; speed::Float64
route::Vector{(Float64, Float64)}
Prey(breed::Symbol) = new(breed, true, 5midrand(), 5midrand(),
rand()*2pi, 0, Array((Float64, Float64), 0))
end
function Prey()
Prey(preynames[rand(1:length(preynames))])
end
function Base.show(io::IO, an::Animal)
coords = @sprintf "%0.3f, %0.3f" an.x an.y
print(io, "$(an.breed) ($coords)")
end
type Meeting
event::Symbol
x::Float64
y::Float64
end
In [4]:
const area = 6
function move!(an::Animal)
an.heading += midrand()
an.speed += 0.01 + 0.001midrand()
an.x += an.speed * sin(an.heading)
an.y += an.speed * cos(an.heading)
push!(an.route, (an.x, an.y))
if abs(an.x) > area || abs(an.y) > area
an.speed *= 0.1
end
end
function move!(animals::Array{Animal, 1})
for animal in animals
move!(animal)
end
end
distance(a1::Animal, a2::Animal) = sqrt((a1.x-a2.x)^2 + (a1.y-a2.y)^2)
const meetdist = 0.3
function meet!(animals::Array{Animal, 1}, meetings::Array{Meeting, 1})
newanimals = Animal[]
for (i, a1) in enumerate(animals)
!a1.alive && continue
for a2 in animals[(i+1):end]
!a2.alive && continue
distance(a1, a2) > meetdist && continue
if a1.breed == a2.breed && length(animals) < 1000 && rand() > 0.9
println("$a1 breeds with $a2")
isa(a1, Preditor) ? push!(newanimals, Preditor(a1.breed)) :
push!(newanimals, Prey(a1.breed))
push!(meetings, Meeting(:breed, a1.x, a1.y))
elseif isa(a1, Preditor) && isa(a2, Prey)
println("$a1 eats $a2")
a2.alive = false
a1.eaten += 1
push!(meetings, Meeting(:kill, a2.x, a2.y))
elseif isa(a1, Prey) && isa(a2, Preditor)
println("$a2 eats $a1")
a1.alive = false
a2.eaten += 1
push!(meetings, Meeting(:kill, a1.x, a1.y))
end
end
end
# filter!(p -> p.alive, animals)
append!(animals, newanimals)
end
animals = Animal[Preditor() for _ in 1:4]
meetings = Meeting[]
append!(animals, [Prey() for _ in 1:40])
steps = 200
println("starting number of animals:", length(animals))
for step in 1:steps
move!(animals)
meet!(animals, meetings)
end
println("final number of animals:", length(animals))
In [5]:
xs = zeros(steps, length(animals))
ys = zeros(steps, length(animals))
for (i, p) in enumerate(animals)
length(p.route) == 0 && continue
# (steps - length(p.route) + 1)
xs[:, i] = p.route[end][1]
ys[:, i] = p.route[end][2]
xs[1:length(p.route), i] = Float64[r[1] for r in p.route]
ys[1:length(p.route), i] = Float64[r[2] for r in p.route]
end
hold(false)
plot(xs, ys, width=1000, height=800)
hold(true)
killx = Float64[m.x for m in filter(m->m.event == :kill, meetings)]
killy = Float64[m.y for m in filter(m->m.event == :kill, meetings)]
plot(killx, killy, "ok")
breedx = Float64[m.x for m in filter(m->m.event == :breed, meetings)]
breedy = Float64[m.y for m in filter(m->m.event == :breed, meetings)]
plot(breedx, breedy, "ob")
Out[5]: