进化的生态系统

书名:代码本色:用编程模拟自然系统
作者: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 进化的生态系统(程序略)

  • 尺寸中等的对象,运动速度足够快,寻找食物的能力最强,因此存活时间也最久。
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容