NetLogo和StarLogo都是多主体(multi-agent)模拟平台,后者继承自前者但功能更强大、开发进程也更活跃。它们都采用类Logo的建模编程语言,并引入了大规模并发机制,所以特别适合用于构造由许许多多自主活动但相互影响的简单个体组成的大规模系统(比如蚁群)。通过在电脑平台上模拟每个主体的行为,我们可以探索系统作为整体所表现出的宏观现象和性质。
本文介绍的模型是基于NetLogo的。这个模型有敌对的两方(中国和罗马),每一方的士兵数量是可调参数。士兵只会近战,这意味着只能攻击与自己处于同一格子(NetLogo中叫patch)中的敌人。每个士兵都有血量(blood)和杀伤力(power)参数,血量为0士兵死亡,每个士兵每次攻击打掉对手的血量等于自己的杀伤力。战斗开始时,双发所有的士兵被随机地分布在一个矩形的战场中,随后士兵开始搜寻一个敌对目标,找到一个后就逼近直到足够近,然后开始攻击直到对方或自己死亡。士兵搜寻敌人的策略是:先判断自己所处的格子中有否敌人,如没有且敌人总数大于20就随机地转个角度并往前走1到3步,如果敌人少于20个就挑一个最近的敌人然后朝他逼近(每次随机地前进1到3步),如果逼近过程中敌人死了就重新搜寻离自己最近的敌人。任何一方士兵全部死亡则战斗结束。
模型运行开始时会估算哪方胜利以及剩余的士兵人数,运行结束后会给出实际的胜利方以及剩余的人数。这些信息全都输出在Command Center里。
众所周知,兰彻斯特线性律可以较好地描述冷兵器近距接触战和使用间瞄武器(比如炮)作战的伤亡规律,而平方律则可以描述使用直瞄武器(比如步枪)的作战过程。但是,通过多次用不同参数运行上述模型,发现这种简单的冷兵器近距混战中,双方的伤亡数与兰彻斯特平方律也还是比较吻合的。对于这种现象,我是这么理解的:平方律的前提是双方所有士兵都互相进入攻击距离,每个士兵可以选择任意一个敌人进行直接攻击,这使得火力集中能产生效果,小范围的直瞄武器战斗是满足这个前提的;由于本文讨论的战斗是混战,双方是充分接触,每个士兵的攻击范围内至少有一个敌人的概率是很大的(很少有士兵会无事可干),而且一个格子中双方人数之比大致等于双方总人数之比,根据战斗规则,一个格子内人多一方火力也更集中,所以平方律也基本适用。
[1] StarLogo, http://education.mit.edu/starlogo
[2] NetLogo, http://ccl.northwestern.edu/netlogo
[3] 数理战术学, 沙基昌 著, 科学出版社, 2003
附录:
下面是模型源代码,将它复制粘贴到一个后缀名为nlogo的本地文本文件中,然后从NetLogo中打开,调整好参数后点击"setup"按钮初始化,再点"go"按钮运行。
globals [final-winner final-survivors guess-winner guess-surviors battle-over]
breed [china]
breed [rome]
to setup
ca
create-china china-count
create-rome rome-count
ask-concurrent china [set color green setxy random world-width random world-height]
ask-concurrent rome [set color red setxy random world-width random world-height]
ask-concurrent china [init china-blood china-power]
ask-concurrent rome [init rome-blood rome-power]
let sososo guess
set guess-winner first sososo
set guess-surviors item 1 sososo
show (list "guess" guess-winner guess-surviors)
set battle-over false
end
to-report guess
let winner china
let surviors 0
let china-left-sq (china-count ^ 2 - rome-count ^ 2 * rome-power / china-power)
let rome-left-sq (rome-count ^ 2 - china-count ^ 2 * china-power / rome-power)
ifelse 0 < rome-left-sq [
set winner rome
set surviors sqrt rome-left-sq
]
[
set winner china
set surviors sqrt china-left-sq
]
report (list winner surviors)
end
to go
if battle-over [
show (list "fact" final-winner final-survivors)
stop
]
ask-concurrent turtles [fight]
tick
end
turtles-own [target blood power]
to fight
hunt-for-enemy
attack-enemy power
if not any-enemy [
set final-survivors count-self
set final-winner breed
set battle-over true
stop
]
end
to init [init-blood init-power]
set target nobody
set blood init-blood
set power init-power
end
to hunt-for-enemy
if not (nobody = target) [stop]
let temp-target one-of-enemy-here
if not (nobody = temp-target)
[set target temp-target stop]
ifelse count-enemy > 20
[wiggle]
[
set temp-target nearest-enemy
if nobody = temp-target [stop]
set heading towardsxy [xcor] of temp-target [ycor] of temp-target
fd random 3 + 1
]
end
to wiggle
fd random 3 + 1
rt random 180
lt random 180
end
to-report one-of-enemy-here
ifelse breed = china [report one-of rome-here]
[report one-of china-here]
end
to-report nearest-enemy
let x xcor
let y ycor
ifelse breed = china
[report one-of (rome with-min [distancexy x y])]
[report one-of (china with-min [distancexy x y])]
end
to-report any-enemy
ifelse breed = china [report any? rome] [report any? china]
end
to-report count-enemy
ifelse breed = china [report count rome] [report count china]
end
to-report count-self
本文介绍的模型是基于NetLogo的。这个模型有敌对的两方(中国和罗马),每一方的士兵数量是可调参数。士兵只会近战,这意味着只能攻击与自己处于同一格子(NetLogo中叫patch)中的敌人。每个士兵都有血量(blood)和杀伤力(power)参数,血量为0士兵死亡,每个士兵每次攻击打掉对手的血量等于自己的杀伤力。战斗开始时,双发所有的士兵被随机地分布在一个矩形的战场中,随后士兵开始搜寻一个敌对目标,找到一个后就逼近直到足够近,然后开始攻击直到对方或自己死亡。士兵搜寻敌人的策略是:先判断自己所处的格子中有否敌人,如没有且敌人总数大于20就随机地转个角度并往前走1到3步,如果敌人少于20个就挑一个最近的敌人然后朝他逼近(每次随机地前进1到3步),如果逼近过程中敌人死了就重新搜寻离自己最近的敌人。任何一方士兵全部死亡则战斗结束。
模型运行开始时会估算哪方胜利以及剩余的士兵人数,运行结束后会给出实际的胜利方以及剩余的人数。这些信息全都输出在Command Center里。
众所周知,兰彻斯特线性律可以较好地描述冷兵器近距接触战和使用间瞄武器(比如炮)作战的伤亡规律,而平方律则可以描述使用直瞄武器(比如步枪)的作战过程。但是,通过多次用不同参数运行上述模型,发现这种简单的冷兵器近距混战中,双方的伤亡数与兰彻斯特平方律也还是比较吻合的。对于这种现象,我是这么理解的:平方律的前提是双方所有士兵都互相进入攻击距离,每个士兵可以选择任意一个敌人进行直接攻击,这使得火力集中能产生效果,小范围的直瞄武器战斗是满足这个前提的;由于本文讨论的战斗是混战,双方是充分接触,每个士兵的攻击范围内至少有一个敌人的概率是很大的(很少有士兵会无事可干),而且一个格子中双方人数之比大致等于双方总人数之比,根据战斗规则,一个格子内人多一方火力也更集中,所以平方律也基本适用。
[1] StarLogo, http://education.mit.edu/starlogo
[2] NetLogo, http://ccl.northwestern.edu/netlogo
[3] 数理战术学, 沙基昌 著, 科学出版社, 2003
附录:
下面是模型源代码,将它复制粘贴到一个后缀名为nlogo的本地文本文件中,然后从NetLogo中打开,调整好参数后点击"setup"按钮初始化,再点"go"按钮运行。
globals [final-winner final-survivors guess-winner guess-surviors battle-over]
breed [china]
breed [rome]
to setup
ca
create-china china-count
create-rome rome-count
ask-concurrent china [set color green setxy random world-width random world-height]
ask-concurrent rome [set color red setxy random world-width random world-height]
ask-concurrent china [init china-blood china-power]
ask-concurrent rome [init rome-blood rome-power]
let sososo guess
set guess-winner first sososo
set guess-surviors item 1 sososo
show (list "guess" guess-winner guess-surviors)
set battle-over false
end
to-report guess
let winner china
let surviors 0
let china-left-sq (china-count ^ 2 - rome-count ^ 2 * rome-power / china-power)
let rome-left-sq (rome-count ^ 2 - china-count ^ 2 * china-power / rome-power)
ifelse 0 < rome-left-sq [
set winner rome
set surviors sqrt rome-left-sq
]
[
set winner china
set surviors sqrt china-left-sq
]
report (list winner surviors)
end
to go
if battle-over [
show (list "fact" final-winner final-survivors)
stop
]
ask-concurrent turtles [fight]
tick
end
turtles-own [target blood power]
to fight
hunt-for-enemy
attack-enemy power
if not any-enemy [
set final-survivors count-self
set final-winner breed
set battle-over true
stop
]
end
to init [init-blood init-power]
set target nobody
set blood init-blood
set power init-power
end
to hunt-for-enemy
if not (nobody = target) [stop]
let temp-target one-of-enemy-here
if not (nobody = temp-target)
[set target temp-target stop]
ifelse count-enemy > 20
[wiggle]
[
set temp-target nearest-enemy
if nobody = temp-target [stop]
set heading towardsxy [xcor] of temp-target [ycor] of temp-target
fd random 3 + 1
]
end
to wiggle
fd random 3 + 1
rt random 180
lt random 180
end
to-report one-of-enemy-here
ifelse breed = china [report one-of rome-here]
[report one-of china-here]
end
to-report nearest-enemy
let x xcor
let y ycor
ifelse breed = china
[report one-of (rome with-min [distancexy x y])]
[report one-of (china with-min [distancexy x y])]
end
to-report any-enemy
ifelse breed = china [report any? rome] [report any? china]
end
to-report count-enemy
ifelse breed = china [report count rome] [report count china]
end
to-report count-self