Engee 文档
Notebook

羊和狼的游戏

在这个例子中,我们将考虑一个模型,其模拟的本质是显示捕食者-猎物-植物情景。 这是一个基于代理的模型,模拟具有三个关键组件的生态系统:

  1. 羊(受害者)-它们以植物为食并以充足的能量繁殖
  2. 狼(捕食者)-狩猎羊,需要更多的能量才能生存
  3. 植物-随着时间的推移再生,作为羊的食物

这里的关键机制是营养循环,表示如下狼→羊→植物和种群动态,在达到能量阈值时通过能量消耗(饥饿)和繁殖自动调节,以及药剂的随机移动

该模型展示了生态学的经典原理:

-食物链
-资源竞争
-动态人口均衡
-物种灭绝的瓶颈效应

In [ ]:
Pkg.add("StatsBase")
using Random
using StatsBase
   Resolving package versions...
  No Changes to `~/.project/Project.toml`
  No Changes to `~/.project/Manifest.toml`

现在我们将声明模型对象的主要参数和结构。

  1. 世界参数:

    • WIDTHHEIGHT -二维世界的尺寸(以单元格为单位)
    • MAX_STEPS -模拟迭代的限制
    • SAVE_EVERY -可视化保存状态的频率
  2. 代理:

    -所有代理都有坐标(x,y),并从基类型继承 Agent

    • SheepWolf 包含参数 energy -一个关键指标:
      -生存(在能量<0时,代理死亡)
      -再生(需要足够的能量水平)
    • Bush 有一面旗帜 active -可以吃吗
  3. 型号:

    -包含所有代理的数组(sheep, wolves)
    -矩阵 bushes (植物)的尺寸宽度×高度
    -步进计数器 step
    -字典 params 具有可配置的参数:
    *事件的概率(繁殖,植物的恢复)
    *能源参数(消耗,消耗,阈值)
    *生态系统平衡(生存难度可以调整)

这些结构构成了:

-模拟代理运动
-食物系统(狼→羊→植物)
-繁殖和死亡的机制
-生态系统状态的可视化

In [ ]:
const WIDTH = 50
const HEIGHT = 50
const MAX_STEPS = 2000
const SAVE_EVERY = 100

abstract type Agent end
mutable struct Sheep <: Agent
    x::Int
    y::Int
    energy::Int
end
mutable struct Wolf <: Agent
    x::Int
    y::Int
    energy::Int
end
mutable struct Bush <: Agent
    x::Int
    y::Int
    active::Bool
end
mutable struct Model
    sheep::Vector{Sheep}
    wolves::Vector{Wolf}
    bushes::Matrix{Bush}
    step::Int
    params::Dict{Symbol,Float64}
end

功能 init_model 用三种类型的代理创建生态系统模型的初始状态:羊、狼和植物。

功能做什么:

  1. 初始化世界,创建一个测量宽度×高度的植物矩阵(数字设置在 n_bushes)

  2. 创建代理:羊(n_sheep 件)与启动能量 sheep_energy,狼(n_wolves 件)与启动能量 wolf_energy,随机将它们放置在地图上

  3. 通过字典调整模型参数 params:

    -植物恢复和动物繁殖的概率
    -饥饿期间的能源消耗
    -营养期间的能量增加
    -繁殖的能量阈值

**返回:**对象类型 Model 随着生态系统的初始状态,所有这些功能参数都允许您在启动前灵活调整生态系统平衡。

In [ ]:
function init_model(;
    n_sheep = 50,
    n_wolves = 10,
    n_bushes = 500,
    sheep_energy = 10,
    wolf_energy = 50,
    bush_regrowth = 0.01,
    sheep_reprod = 0.04,
    wolf_reprod = 0.05,
    sheep_hunger = 1,
    wolf_hunger = 2,
    sheep_eat_gain = 5,
    wolf_eat_gain = 20,
    sheep_reprod_thresh = 15,
    wolf_reprod_thresh = 30
)

bushes = Matrix{Bush}(undef, WIDTH, HEIGHT)
for x in 1:WIDTH, y in 1:HEIGHT
    bushes[x,y] = Bush(x, y, false)
end
all_positions = [(x, y) for x in 1:WIDTH, y in 1:HEIGHT]
bush_positions = sample(all_positions, n_bushes, replace=false)
for (x, y) in bush_positions
    bushes[x,y].active = true
end
sheep = Sheep[]
for _ in 1:n_sheep
    x, y = rand(1:WIDTH), rand(1:HEIGHT)
    push!(sheep, Sheep(x, y, sheep_energy))
end
wolves = Wolf[]
for _ in 1:n_wolves
    x, y = rand(1:WIDTH), rand(1:HEIGHT)
    push!(wolves, Wolf(x, y, wolf_energy))
end
params = Dict(
    :bush_regrowth => bush_regrowth,
    :sheep_reprod => sheep_reprod,
    :wolf_reprod => wolf_reprod,
    :sheep_hunger => sheep_hunger,
    :wolf_hunger => wolf_hunger,
    :sheep_eat_gain => sheep_eat_gain,
    :wolf_eat_gain => wolf_eat_gain,
    :sheep_reprod_thresh => sheep_reprod_thresh,
    :wolf_reprod_thresh => wolf_reprod_thresh
)
Model(sheep, wolves, bushes, 0, params)
end
Out[0]:
init_model (generic function with 1 method)

功能 **move_agent!**在地图上随机移动代理(羊或狼)。 它产生一个随机偏移 **dx**及 **dy**取值-1、0或1(任何方向或位置的一个步骤)并计算新坐标, **mod1**提供边界的"包裹"-如果代理超出地图的边缘,则会出现在对面。

In [ ]:
function move_agent!(agent::Agent, model)
    dx, dy = rand(-1:1, 2)
    new_x = mod1(agent.x + dx, WIDTH)
    new_y = mod1(agent.y + dy, HEIGHT)
    agent.x, agent.y = new_x, new_y
end
Out[0]:
move_agent! (generic function with 1 method)

功能 eat!(sheep::Sheep, model) 允许绵羊在当前的笼子里吃植物。 她检查羊下的灌木丛(model.bushes[sheep.x, sheep.y]),如果灌木是活动的(active=true),使灌木不活跃(吃它),并通过以下方式增加绵羊的能量 sheep_eat_gain 从参数中,返回 true (喂食成功),如果灌木不活动,返回 false

功能 reproduce!(agent::Sheep, model),在满足条件时进行绵羊育种。 它检查两个条件:随机数不太可能重现(sheep_reprod)和羊的能量高于阈值(sheep_reprod_thresh),如果满足条件:将羊的能量分成两半,创建一个具有相同坐标和一半能量的新羊,将其添加到模型中,返回 true (复制成功),如果不满足条件,返回 false

In [ ]:
function eat!(sheep::Sheep, model)
    bush = model.bushes[sheep.x, sheep.y]
    if bush.active
        bush.active = false
        sheep.energy += model.params[:sheep_eat_gain]
        return true
    end
    false
end
function reproduce!(agent::Sheep, model)
    if rand() < model.params[:sheep_reprod] && agent.energy > model.params[:sheep_reprod_thresh]
        agent.energy ÷= 2
        new_sheep = Sheep(agent.x, agent.y, agent.energy)
        push!(model.sheep, new_sheep)
        return true
    end
    false
end
Out[0]:
reproduce! (generic function with 2 methods)

然后对于狼也有类似的功能,与羊的关键区别:

*狼猎羊(不是植物)

*使用自己的参数(wolf_eat_gain, **wolf_reprod**等。)

*复制的机制相似,但数值不同

In [ ]:
function eat!(wolf::Wolf, model)
    sheep_idx = findfirst(s -> s.x == wolf.x && s.y == wolf.y, model.sheep)
    if !isnothing(sheep_idx)
        splice!(model.sheep, sheep_idx)
        wolf.energy += model.params[:wolf_eat_gain]
        return true
    end
    false
end
function reproduce!(agent::Wolf, model)
    if rand() < model.params[:wolf_reprod] && agent.energy > model.params[:wolf_reprod_thresh]
        agent.energy ÷= 2
        new_wolf = Wolf(agent.x, agent.y, agent.energy)
        push!(model.wolves, new_wolf)
        return true
    end
    false
end
Out[0]:
reproduce! (generic function with 2 methods)

功能 regenerate_bushes!(model),以一定的概率在地图上恢复被吃掉的植物(灌木丛),该函数贯穿比赛场地的所有单元格(宽度×高度),对于每个不活动的灌木丛(bush.active == false)与概率 bush_regrowth (从模型的参数)使灌木活跃,通过将随机数与 model.params[:bush_regrowth]

In [ ]:
function regenerate_bushes!(model)
    for x in 1:WIDTH, y in 1:HEIGHT
        bush = model.bushes[x,y]
        if !bush.active && rand() < model.params[:bush_regrowth]
            bush.active = true
        end
    end
end
Out[0]:
regenerate_bushes! (generic function with 1 method)

功能 step!(model) 执行生态系统模拟的一个步骤,更新所有代理的状态和验证完成条件.

主要工作阶段:

  1. 步进计数器的增量 model.step += 1

  2. 绵羊处理(循环):

    -移动(move_agent!)
    -营养(如果你不能吃,减少能量 sheep_hunger)
    -复制的尝试(reproduce!)

  3. 狼治疗(在一个周期):

    -移动(move_agent!)
    -狩猎(如果失败,减少能量 wolf_hunger)
    -复制的尝试(reproduce!)

  4. 过滤已故代理人:

    -清除能量小于0的绵羊
    -清除能量小于0的狼

  5. 植物修复:

    • regenerate_bushes! -食用灌木的更新
  6. 检查完成条件:

    -所有羊或所有狼的灭绝
    -达到最大步数(MAX_STEPS)
    -相关消息的输出

  7. 进度记录:每个 SAVE_EVERY 步骤显示当前统计信息

  8. 返回值:

  • false -如果模拟要结束
  • true -如果模拟继续
In [ ]:
function step!(model)
    model.step += 1
    for sheep in model.sheep
        move_agent!(sheep, model)
        if !eat!(sheep, model)
            sheep.energy -= model.params[:sheep_hunger]
        end
        reproduce!(sheep, model)
    end
    for wolf in model.wolves
        move_agent!(wolf, model)
        if !eat!(wolf, model)
            wolf.energy -= model.params[:wolf_hunger]
        end
        reproduce!(wolf, model)
    end
    filter!(s -> s.energy > 0, model.sheep)
    filter!(w -> w.energy > 0, model.wolves)
    regenerate_bushes!(model)
    if isempty(model.sheep) || isempty(model.wolves)
        if isempty(model.sheep)
            println("Симуляция остановлена на шаге $(model.step): все овцы вымерли.")
        else
            println("Симуляция остановлена на шаге $(model.step): все волки вымерли.")
        end
        return false
    end
    if model.step >= MAX_STEPS
        println("Симуляция завершена: достигнуто максимальное количество шагов ($MAX_STEPS).")
        return false
    end
    if model.step % SAVE_EVERY == 0
        println("Прогресс: завершен шаг $(model.step). Овец: $(length(model.sheep)), волков: $(length(model.wolves))")
    end
    true
end
Out[0]:
step! (generic function with 285 methods)

功能 plot_model(model) в它以彩色地图的形式可视化生态系统的当前状态,显示所有药剂和植物的位置。

-每个代理在地图上正好占据一个正方形
-显示优先级:狼>羊>植物(如果它们在同一个笼子里)
-颜色选择直观的解释:
-红色-危险(掠食者)
-白色-中性(猎物)
-绿色-植物

In [ ]:
function plot_model(model)
    grid = zeros(Int, WIDTH, HEIGHT)
    for x in 1:WIDTH, y in 1:HEIGHT
        if model.bushes[x,y].active
            grid[x,y] = 3
        end
    end
    for sheep in model.sheep
        grid[sheep.x, sheep.y] = 2
    end
    for wolf in model.wolves
        grid[wolf.x, wolf.y] = 1
    end
    
    colors = [colorant"black", colorant"red", colorant"white", colorant"green"]
    heatmap(grid, 
        c=colors, 
        clim=(0,3),
        title="Шаг: $(model.step) | Овцы: $(length(model.sheep)) | Волки: $(length(model.wolves))",
        axis=false,
        legend=false
    )
end
Out[0]:
plot_model (generic function with 1 method)

功能 run_simulation 运行和管理整个生态系统模拟的主要功能。

它包括以下步骤::

  1. 初始化:

  2. 主仿真周期包括当前状态的逐步可视化(plot_model),执行仿真步骤(step!),保存当前人口数据,并在满足停止条件时中断。

  3. 创建动画并将模拟过程保存到GIF文件"wolf_sheep_sim。gif"

  4. 结果的输出。

In [ ]:
function run_simulation(;
    n_sheep = 50,
    n_wolves = 10,
    n_bushes = 500,
    sheep_energy = 10,
    wolf_energy = 50,
    bush_regrowth = 0.01,
    sheep_reprod = 0.04,
    wolf_reprod = 0.05,
    sheep_hunger = 1,
    wolf_hunger = 2,
    sheep_eat_gain = 5,
    wolf_eat_gain = 20,
    sheep_reprod_thresh = 15,
    wolf_reprod_thresh = 30
)

model = init_model(
    n_sheep = n_sheep,
    n_wolves = n_wolves,
    n_bushes = n_bushes,
    sheep_energy = sheep_energy,
    wolf_energy = wolf_energy,
    bush_regrowth = bush_regrowth,
    sheep_reprod = sheep_reprod,
    wolf_reprod = wolf_reprod,
    sheep_hunger = sheep_hunger,
    wolf_hunger = wolf_hunger,
    sheep_eat_gain = sheep_eat_gain,
    wolf_eat_gain = wolf_eat_gain,
    sheep_reprod_thresh = sheep_reprod_thresh,
    wolf_reprod_thresh = wolf_reprod_thresh
)
sheep_history = Int[]
wolf_history = Int[]
bush_history = Int[]
step_history = Int[]

anim = @animate for _ in 1:MAX_STEPS
    plot_model(model)
    should_continue = step!(model)
    push!(sheep_history, length(model.sheep))
    push!(wolf_history, length(model.wolves))
    push!(bush_history, sum(b.active for b in model.bushes))
    push!(step_history, model.step)
    
    should_continue || break
end

println("\nРезультаты симуляции:")
println("Финальный шаг: $(model.step)")
println("Количество овец: $(length(model.sheep))")
println("Количество волков: $(length(model.wolves))")
println("Количество растений: $(sum(b.active for b in model.bushes))")

plt = plot(step_history, [sheep_history, wolf_history, bush_history],
     label = ["Овцы" "Волки" "Растения"],
     xlabel = "Шаги симуляции",
     ylabel = "Количество",
     title = "Динамика популяций",
     linewidth = 2)
display(plt)
display(gif(anim, "wolf_sheep_sim.gif", fps=10))
end
Out[0]:
run_simulation (generic function with 1 method)

接下来,我们运行它,为了您的方便,已经应用了代码单元格的掩码,按照下面的示例,您可以使用滑块控制整个模型。

run_simulation(
    #基本人口
参数n_sheep=100,#羊的初始个数
    n_wolves=5,#初始狼数
n_bushes=70,#初始草量
    
    #能量参数
    sheep_energy=100,#羊的初始能量
    wolf_energy=1000,#狼的初始能量
    
    #资源恢复选项
    bush_regrowth=0.005,#每步复草概率
    
    #养殖参数
    sheep_reprod=0.02,#羊每步繁殖概率
    wolf_reprod=0.1,#每步一只狼的繁殖概率
    
    #禁食参数
    sheep_hunger=1,#羊在没有食物的情况下每步的能量损失
    wolf_hunger=3,#没有食物的情况下每步损失狼的能量
    
    #功率参数
    sheep_eat_gain=8,#羊吃草时能量增益
    wolf_eat_gain=25,#狼吃羊时的能量增益
    
    #繁殖门槛
    sheep_reprod_thresh=20,#绵羊繁殖的最小能量
    wolf_reprod_thresh=35#狼繁殖的最小能量
)
In [ ]:
run_simulation(
n_sheep = 100 # @param {type:"slider",min:0,max:1000,step:1}
,
n_wolves = 24 # @param {type:"slider",min:0,max:1000,step:1}
,
n_bushes = 70 # @param {type:"slider",min:0,max:1000,step:1}
,
sheep_energy = 100 # @param {type:"slider",min:0,max:1000,step:1}
,
wolf_energy = 79 # @param {type:"slider",min:0,max:1000,step:1}
,
bush_regrowth = 0.005 # @param {type:"slider",min:0,max:1,step:0.001}
,
sheep_reprod = 0.02 # @param {type:"slider",min:0,max:1,step:0.01}
,
wolf_reprod = 0.01 # @param {type:"slider",min:0,max:1,step:0.01}
,
sheep_hunger = 1 # @param {type:"slider",min:0,max:1000,step:1}
,
wolf_hunger = 3 # @param {type:"slider",min:0,max:1000,step:1}
,
sheep_eat_gain = 8 # @param {type:"slider",min:0,max:1000,step:1}
,
wolf_eat_gain = 25 # @param {type:"slider",min:0,max:1000,step:1}
,
sheep_reprod_thresh = 20 # @param {type:"slider",min:0,max:1000,step:1}
,
wolf_reprod_thresh = 35 # @param {type:"slider",min:0,max:1000,step:1}
)
Прогресс: завершен шаг 100. Овец: 113, волков: 1
Симуляция остановлена на шаге 101: все волки вымерли.

Результаты симуляции:
Финальный шаг: 101
Количество овец: 113
Количество волков: 0
Количество растений: 371
[ Info: Saved animation to /user/my_projects/Demo/Work/wolf_sheep_sim.gif
No description has been provided for this image

结论

总之,我想考虑这种模式对社区的积极影响。:

  1. 这个模型对学习很有用–它完美地展示了基础知识:

    -生态系统(食物链,人口动态)
    -基于代理的建模(自主对象的行为)
    -模拟中的平衡参数

  2. 研究–让你学习:

    -生态系统适应变化的能力
    -物种灭绝的影响
    -初始条件对系统发展的影响

  3. 对于发展,建设的一个例子:

    -离散模拟
    -实时数据可视化
    -过程动画