书名:代码本色:用编程模拟自然系统
作者:Daniel Shiffman
译者:周晗彬
ISBN:978-7-115-36947-5
第9章目录
9.13 生态系统模拟
首先,我们要建立基因型和表现型。
1、基因型和表现型
- bloop的觅食能力和两个变量有关:大小和速度。
bloop的尺寸越大,觅食能力越强,因为越大的bloop越容易和食物相交;bloop的速度越快,觅食能力也越强,因为移动速度越快,单位时间内走过的面积越大,接触的食物也越多。 -
由于尺寸和速度成反比(大尺寸的bloop对象运动快,小尺寸的bloop对象运动慢),因此我们只需要用单个数字表示基因型。
class DNA {
float[] genes;
DNA() { 我们只需要一个变量,但这里却使用了数组,这是出于对后续扩展的考虑
genes = new float[1];
for (int i = 0; i < genes.length; i++) {
genes[i] = random(0,1);
}
}
- 表现型就是bloop本身。bloop类中有一个DNA对象,通过这个对象获取自身的尺寸和速度。
class Bloop {
PVector location;
float health;
DNA dna; bloop对象有DNA
float r;
float maxspeed;
Bloop(DNA dna_) {
location = new PVector(width/2,height/2);
health = 200;
dna = dna_;
maxspeed = map(dna.genes[0], 0, 1, 15, 0); 将DNA中的基因映射为最大速度和半径
r = map(dna.genes[0], 0, 1, 0, 50);
}
- maxspeed的值被映射到15~0,也就说,如果基因值为0,bloop的运动速度就等于15;如果基因值为1,bloop的运动速度就等于0。
2、选择和繁殖
- 有了基因型和表现型之后,我们需要设计一种选择策略,从种群中选出一些bloop对象作为繁殖父本。
之前提到:bloop的生存时间越久,繁殖的机会越大。因此,适应度就是bloop的生存时间。 - 这里有一种实现方式:两个bloop对象一旦接触,它们就会产生一个新的bloop对象。bloop生存时间越久,它们接触对方的几率越大,繁殖机会也越大。(这还会影响进化结果,因为除了食物因素,bloop接触对方的能力也变成了繁殖因素。)
- 更简单的实现方式是“无性”繁殖,也就是说,bloop不需要配偶就能繁殖后代。它可以在任意时间复制自己,副本由完全相同的基因组成。我们可以将该选择算法描述为:
在任意时刻,bloop都有1%的繁殖机会。 - 这样一来,bloop生存时间越久,它至少繁殖1个后代的概率也越高。这和买彩票的原理是一样的:买彩票的次数越多,中奖的概率也越大。
- 为了实现这个选择算法,我们可以在bloop类中加入一个函数。
函数的功能是:在每一帧选择一个随机数,如果随机数小于0.01(1%),就产生新的bloop对象。
Bloop reproduce() { 该函数返回子代bloop对象
if (random(1) < 0.01) { 有1%的概率执行其中的代码,也就是有1%的繁殖机会
// 创建新的bloop对象
}
}
- bloop对象如何繁殖?在之前的例子中,繁殖过程需要调用DNA类的crossover()函数,并根据新的DNA创建对象。
由于本例子代由单个父本生成,因此只需调用对象的copy()函数。
Bloop reproduce() {
if (random(1) < 0.0005) {
DNA childDNA = dna.copy(); 创建DNA的副本
childDNA.mutate(0.01); 1%的突变率
return new Bloop(location, childDNA); 在相同的位置,用新的DNA创建新的bloop对象
} else {
return null; 如果不繁殖新的bloop对象,就返回NULL
}
}
- 我们将繁殖概率从1%降到0.5%,这个值会带来很大的影响。繁殖概率越高,系统就会越快进入个体数量饱和状态;繁殖概率如果过低,系统中的生物就会很快灭绝。
- DNA类的copy()函数很容易实现,因为Processing提供了一个arrayCopy()函数,该函数用于复制数组内容。
class DNA {
DNA copy() { copy()函数代替了之前的crossover()函数
float[] newgenes = new float[genes.length]; 用相同的长度创建新数组,复制内容
arraycopy(genes,newgenes);
return new DNA(newgenes);
}
- 实现完选择和繁殖的特性后,我们就可以终结这个World类了,它的主要功能就是管理bloop对象和食物列表。
3、示例
示例代码9-5 进化的生态系统(程序略)
- 尺寸中等的对象,运动速度足够快,寻找食物的能力最强,因此存活时间也最久。