1、制作setup按钮
创建一个button-setup
在代码页定义例程:
to setup
clear-all
create-turtles 100
ask turtles [ setxy random-xcor random-ycor ]
end
例程以to开始,以end结束。所有的例程都要用这两个词开始和结束。
• to setup 开始定义一个名为"setup"的例程
• clear-all 将世界重设为初始、全空状态。所有瓦片变黑,你已经创建的海龟消失。
基本上是将过去一笔勾销,为新模型运行做好准备。
• create-turtles 100 创建 100 个海龟。这些海龟都在原点,即瓦片 0,0 的中心。
• ask turtles [ … ] 告诉每个海龟独立地去运行方括号中的命令 (NetLogo中每条命令都是由某些主体执行的。ask 也是一条命令。在这里是observer运行这条ask 命
令,这条命令又引起海龟运行命令)
• setxy random-xcor random-ycor 是一条用"reporters"的命令。reporter与命令不同,它只报告一个结果。首先每个turtle 运行reporter random-xcor,它返回 X坐标范围内的一个随机数,然后每个turtle运行 reporter random-ycor, 返回Y坐标范围的一个随机数。最后每个turtle 使用前面的两个数做输入参数运行setxy 命令,这使得turtle移动到相应的坐标处。
• end 结束"setup" 例程的定义。
2、制作go按钮
步骤与 setup 按钮的一样, 除了下面几点:
• 在命令部分输入 go,而非setup.
• 在编辑对话框里勾选 “forever”(持续执行)
在代码页添加go例程:
to go
move-turtles
end
move-turtles不是一个像clear-all那样的原语(NetLogo内嵌的),是一个需要你添加的例程。
至今你已经有两个自己添加的例程了:setup 和go
在go例程后面增加move-turtles 例程:
to go
move-turtles
end
to move-turtles
ask turtles [
right random 360
forward 1
]
end
• ask turtles [ … ] 每个turtle运行[ ]中的命令
• right random 360 是使用reporter的命令。首先每个turtle 在 0 和 359 之间随机选一个整数 (random 不会返回你给它的数) ,然后turtle 右转这个度数。
• forward 1 让turtle前进 1 步。
3、瓦片和变量
现在我们有 100 个海龟,它们漫无目的的移动,对周围的事物毫无知觉。下面我们给海龟一个好点的背景,让模型稍微有趣一些。
修改setup例程:
to setup
clear-all
setup-patches
setup-turtles
end
新的 setup引用了两个新例程,定义 setup-patches :
to setup-patches
ask patches [ set pcolor green ]
end
例程setup-patches将开始时所有瓦片颜色定义为绿色。
定义setup-turtles:
to setup-turtles
create-turtles 100
ask turtles [ setxy random-xcor random-ycor ]
end
5、海龟变量
目前海龟在可以地表上移动,但什么都不做。现在在海龟和瓦片之间加上一些交互。
我们让海龟吃“草”(绿色瓦片),繁殖、死亡。草被吃掉后要逐渐恢复。
我们需要一种控制海龟繁殖和死亡的方式。我们通过跟踪海龟有多大能量(energy)来
决定。要这样的话需要增加一个新的海龟变量。
你已经见过一些内置的海龟变量,如color。要添加新的海龟变量,需要在例程页的顶
部加上turtles-own 声明,这个声明必须在所有例程之前,变量名为energy:
turtles-own [energy]
to go
move-turtles
eat-grass
end
to eat-grass
ask turtles [
if pcolor = green [
set pcolor black
set energy (energy + 10)
]
]
end
如果瓦片是绿色则返回true,这时才执行[ ]中的命令(否则跳过)。这些命令让海龟将瓦片改为黑色,海龟能量值增加 10。瓦片变黑表明该处的草被吃掉,因为吃了草,海龟能量增加。
下面,让海龟移动时消耗一些能量:
重写move-turtles如下:
to move-turtles
ask turtles [
right random 360
forward 1
set energy energy - 1
]
end
6、监视器
现在有两个监视器报告有多少海龟,有多少绿色瓦片,帮助我们跟踪模型运行。模型运行时,监视器中的数字自动变化。
7、开关和标签
海龟不仅是将瓦片变黑,它们还获得、损失能量。模型运行时试试使用海龟监视器查看一个海龟的能量变化。
如果能在任何时候看到所有海龟的能量就更好了。现在就这样做,并且增加一个开关能控制这些额外信息显示与否。
重写eat-grass例程:
to eat-grass
ask turtles [
if pcolor = green [
set pcolor black
set energy (energy + 10)
]
ifelse show-energy?
[ set label energy ]
[ set label "" ]
]
end
例程 eat-grass用了ifelse命令,仔细看代码。每个海龟当运行这些新命令时检查show-energy?的值(由开关决定)。
如果开关打开,比较结果为true,海龟执行第一个[ ]中的命令。这时将能量值赋给海龟标签。
如果比较结果为false(开关关闭),海龟执行第二个[ ]中的命令,这时移去文本标签(通过将海龟标签设为空)。
当开关打开时,能看到海龟的能量因吃草而增加,移动时减小:
8、更多例程
现在海龟在吃草,再让它们繁殖和死亡,也让草能恢复。现在增加三个例程,分别负责这三种行为。
to go
move-turtles
eat-grass
reproduce
check-death
regrow-grass
end
to reproduce
ask turtles [
if energy > 50 [
set energy energy - 50
hatch 1 [ set energy 50 ]
]
]
end
to check-death
ask turtles [
if energy <= 0 [ die ]
]
end
to regrow-grass
ask patches [
if random 100 < 3 [ set pcolor green ]
]
end
当繁殖时,每个海龟检查它的energy值,如果大于 50 执行第一个[ ]中的命令。在这里energy减少 50,然后孵出(hatches)一个energy为 50 的新海龟。
hatch命令是NetLogo的一个原语,形如hatch number [commands ],海龟创建number个新海龟,每个都与母体相同,并且请求这些新海龟执行commands,你可以使用commands让这些新海龟有不同的颜色、方向等。这里运行一条命令,将新海龟的energy设为 50。
当每个海龟运行check-death时,它检查energy是否小于等于 0。如果是真,则海龟被告知去死die(这是NetLogo的一个原语)。
当每个海龟运行regrow-grass 时,它检查随机产生的 0-99 之间的整数是否小于 3。如果是,瓦片颜色设为绿。对每个瓦片来说,发生的次数(平均)是 3%,因为在 100 个可能的数中,有三个数(0,1,2)小于 3。
此时,go模型,看模型的监视器,会发现 count turtles 和 green patches 监视器都有振荡。
如果有更容易的跟踪模型行为的方式就更好了。NetLogo 可以为我们画图。
9、画图
添加do-plots例程:
to setup
clear-all
setup-patches
setup-turtles
do-plots
end
to go
move-turtles
eat-grass
reproduce
check-death
regrow-grass
do-plots
end
to do-plots
set-current-plot "Totals"
set-current-plot-pen "turtles"
plot count turtles
set-current-plot-pen "grass"
plot count patches with [pcolor = green]
end
注意使用plot命令在图上增加新点。然而在这样做之前,需要告诉NetLogo两件事。
第一,需要指明要使用哪个图(因为后面的模型有多个图)。
第二,要指定使用哪支笔(pen)画图(本图使用两支笔)。
plot命令告诉画笔移动到新点,新点的X 坐标是先前的X坐标加 1,Y坐标就是plot命令中给定的值(第一种情况是海龟数量,第二种情况是绿瓦片数量)。当画笔移动时就画出线。
为了让set-current-plot "Totals"工作,必须在界面页中为你的模型增加一个图(plot),然后进行编辑,让它的名字与例程中用到的相同。即使名字中多个空格也会出错—两处必须完全相同。
10、时钟计数器
修改go例程:
to go
if ticks >= 500 [ stop ]
move-turtles
eat-grass
reproduce
check-death
regrow-grass
tick
do-plots
end
注意:
在中文手册4.0里面只说了在go例程里加tick。但这样会报错:
时间步计数器尚未启动,使用 RESET-TICKS.
error while observer running TICKS
called by procedure GO
called by 按钮 ‘go’
解决方法:
不仅仅要在"go"程序中加tick,同时你需要在setup程序的clear-up语句后面加一条reset-ticks,因为每一次你setup,你把ticks中的记录被clear-up清除了
setup例程:
to setup
clear-all
reset-ticks
setup-patches
setup-turtles
do-plots
end
当界面页工具条上的时钟计数器达到 500 时,模型自动
停止。
11、更多细节
可以有可变数量的海龟,而非总是 100 个。
增加一个滑动条改变海龟数量:
to setup-turtles
create-turtles number
ask turtles [ setxy random-xcor random-ycor ]
end
增加滑动条energy-from-grass.
增加滑动条birth-energy
to eat-grass
ask turtles [
if pcolor = green [
set pcolor black
set energy (energy + energy-from-grass)
]
ifelse show-energy?
[ set label energy ]
[ set label "" ]
]
end
to reproduce
ask turtles [
if energy > birth-energy [
set energy energy - birth-energy
hatch 1 [ set energy birth-energy ]
]
]
end
完整代码:
turtles-own [energy]
to setup
clear-all
reset-ticks
setup-patches
setup-turtles
do-plots
end
to setup-patches
ask patches [ set pcolor green ]
end
to setup-turtles
create-turtles number
ask turtles [ setxy random-xcor random-ycor ]
end
to go
if ticks >= 500 [ stop ]
move-turtles
eat-grass
reproduce
check-death
regrow-grass
tick
do-plots
end
to move-turtles
ask turtles [
right random 360
forward 1
set energy energy - 1
]
end
to eat-grass
ask turtles [
if pcolor = green [
set pcolor black
set energy (energy + energy-from-grass)
]
ifelse show-energy?
[ set label energy ]
[ set label "" ]
]
end
to reproduce
ask turtles [
if energy > birth-energy [
set energy energy - birth-energy
hatch 1 [ set energy birth-energy ]
]
]
end
to check-death
ask turtles [
if energy <= 0 [ die ]
]
end
to regrow-grass
ask patches [
if random 100 < 3 [ set pcolor green ]
]
end
to do-plots
set-current-plot "Totals"
set-current-plot-pen "turtles"
plot count turtles
set-current-plot-pen "grass"
plot count patches with [pcolor = green]
end