基于遗传算法(GA)进化的小游戏

在这篇文章中,我们模拟了一个包含生物体和食物的环境,生物体为了生存必须尽可能多的消耗食物。在模拟环境中,生物体将由一个简单的、完全连接的神经网络来控制。神经网络的输入是一种标准化值,从-1到+1之间,这表示最近的食物颗粒的方向。这个方向是通过最近的食物颗粒(+/-180度)方向计算出来的。下面是两个生物体和食物颗粒的示例:

 

因为我们的输入范围从-1到+1,所以输出范围应当也从-1到+1,因此tanh函数将会成为理想的激活函数。下面是一个神经网络的图和它的输入、输出以及它的隐藏层:

 

由于神经网络仅仅是简单的矩阵乘法,因此利用NumPy只需要几行代码就可以了。在进化过程中,一些权重会被优化。最后,我将默认的隐藏节点数设置为5,这个可以根据你自己的喜好设置。接下来是编写Python代码模拟整个生态:

一、生物


生物类包含了神经网络以及更新它的速度和位置的函数。当一个生物体被初始化时,它的位置、方向、速度、加速度和神经网络的权重都会随机产生。下面是这个生物类的代码:

class organism():
    def __init__(self, settings, wih=None, who=None, name=None):
        self.x = uniform(settings['x_min'], settings['x_max'])  # position (x)
        self.y = uniform(settings['y_min'], settings['y_max'])  # position (y)
        self.r = uniform(0,360)                 # orientation   [0, 360]
        self.v = uniform(0,settings['v_max'])   # velocity      [0, v_max]
        self.dv = uniform(-settings['dv_max'], settings['dv_max'])   # dv
        self.d_food = 100   # distance to nearest food
        self.r_food = 0     # orientation to nearest food
        self.fitness = 0    # fitness (food count)
        self.wih = wih
        self.who = who
        self.name = name
    # NEURAL NETWORK
    def think(self):
        # SIMPLE MLP
        af = lambda x: np.tanh(x)               # activation function
        h1 = af(np.dot(self.wih, self.r_food))  # hidden layer
        out = af(np.dot(self.who, h1))          # output layer
        # UPDATE dv AND dr WITH MLP RESPONSE
        self.nn_dv = float(out[0])   # [-1, 1]  (accelerate=1, deaccelerate=-1)
        self.nn_dr = float(out[1])   # [-1, 1]  (left=1, right=-1)
    # UPDATE HEADING
    def update_r(self, settings):
        self.r += self.nn_dr * settings['dr_max'] * settings['dt']
        self.r = self.r % 360
    # UPDATE VELOCITY
    def update_vel(self, settings):
        self.v += self.nn_dv * settings['dv_max'] * settings['dt']
        if self.v < 0: self.v = 0
        if self.v > settings['v_max']: self.v = settings['v_max']
    # UPDATE POSITION
    def update_pos(self, settings):
        dx = self.v * cos(radians(self.r)) * settings['dt']
        dy = self.v * sin(radians(self.r)) * settings['dt']
        self.x += dx
        self.y += dy

二、食物


食物类包含坐标位置和能量值,能量值的多少将直接影响生物体的健康。现在,这个能量值保持不变,并设为1,但如果你想要修改它,它可以被随机化或改变为任何值。此外,当食物被生物体消耗后,respawn函数就会被调用,用于重新生成食物颗粒的位置。这使得每个模拟时间内的食物颗粒总数保持不变。

class food():
    def __init__(self, settings):
        self.x = uniform(settings['x_min'], settings['x_max'])
        self.y = uniform(settings['y_min'], settings['y_max'])
        self.energy = 1
    def respawn(self,settings):
        self.x = uniform(settings['x_min'], settings['x_max'])
        self.y = uniform(settings['y_min'], settings['y_max'])
        self.energy = 1

三、进化


生物体将使用遗传算法(GA)进行优化,遗传算法(GA)是属于进化算法(EA)的更大范围。遗传算法模仿自然的生物进化过程,从最初的种群开始,通过选择、交叉和变异产生后代,形成一个最优的解决方案。对于本教程,EA计划如下:

1、选择:简单的选择形式被称为精英主义,即选择最优秀的下一代。

2、跨界:在精英主义阶段中随机选择个体作为父母,并产生一个新的后代。因此我们要处理神经网络的权重,下面的方程将两个父母之间的性状遗传给后代:

offspring=parent1(a)+parent2(1−a)

a是在0和1之间随机生成的值,而父1和父2表示神经网络的权重。因为有两个正在混合的矩阵(wih和who),因此方程实际上是这样的:

offspring_wih=parent_wih1(a)+parent_wih2(1−a)

offspring_who=parent_who1(a)+parent_who2(1−a)

3、突变:一旦产生新的后代就会产生一个介于0和1之间的随机数。如果这个值低于用户初始化的突变阈值,就会发生突变。在发生突变的情况下,两个神经网络权重矩阵中的一个随机权重将被一个随机值所取代,这个值在初始值的+/-10%之间。这将会在生物体中产生微小的变化,从而有可能产生更健康的生物体。突变效果仅限于原始值的+/-10%,因为我们希望避免在神经网络中造成灾难性的故障而导致整个生物群体瘫痪。

下面的图显示了这个EA方案:

 

 

这个EA代码程序如下所示:

ef evolve(settings, organisms_old, gen):
    elitism_num = int(floor(settings['elitism'] * settings['pop_size']))
    new_orgs = settings['pop_size'] - elitism_num
    #--- GET STATS FROM CURRENT GENERATION ----------------+
    stats = defaultdict(int)
    for org in organisms_old:
        if org.fitness > stats['BEST'] or stats['BEST'] == 0:
            stats['BEST'] = org.fitness
        if org.fitness < stats['WORST'] or stats['WORST'] == 0:
            stats['WORST'] = org.fitness
        stats['SUM'] += org.fitness
        stats['COUNT'] += 1
    stats['AVG'] = stats['SUM'] / stats['COUNT']
    #--- ELITISM (KEEP BEST PERFORMING ORGANISMS) ---------+
    orgs_sorted = sorted(organisms_old, key=operator.attrgetter('fitness'), reverse=True)
    organisms_new = []
    for i in range(0, elitism_num):
        organisms_new.append(organism(settings, wih=orgs_sorted[i].wih, who=orgs_sorted[i].who, name=orgs_sorted[i].name))
    #--- GENERATE NEW ORGANISMS ---------------------------+
    for w in range(0, new_orgs):
        # SELECTION (TRUNCATION SELECTION)
        canidates = range(0, elitism_num)
        random_index = sample(canidates, 2)
        org_1 = orgs_sorted[random_index[0]]
        org_2 = orgs_sorted[random_index[1]]
        # CROSSOVER
        crossover_weight = random()
        wih_new = (crossover_weight * org_1.wih) + ((1 - crossover_weight) * org_2.wih)
        who_new = (crossover_weight * org_1.who) + ((1 - crossover_weight) * org_2.who)
        # MUTATION
        mutate = random()
        if mutate <= settings['mutate']:
            # PICK WHICH WEIGHT MATRIX TO MUTATE
            mat_pick = randint(0,1)
            # MUTATE: WIH WEIGHTS
            if mat_pick == 0:
                index_row = randint(0,settings['hnodes']-1)
                wih_new[index_row] = wih_new[index_row] * uniform(0.9, 1.1)
                if wih_new[index_row] >  1: wih_new[index_row] = 1
                if wih_new[index_row] < -1: wih_new[index_row] = -1
            # MUTATE: WHO WEIGHTS
            if mat_pick == 1:
                index_row = randint(0,settings['onodes']-1)
                index_col = randint(0,settings['hnodes']-1)
                who_new[index_row][index_col] = who_new[index_row][index_col] * uniform(0.9, 1.1)
                if who_new[index_row][index_col] >  1: who_new[index_row][index_col] = 1
                if who_new[index_row][index_col] < -1: who_new[index_row][index_col] = -1
        organisms_new.append(organism(settings, wih=wih_new, who=who_new, name='gen['+str(gen)+']-org['+str(w)+']'))
    return organisms_new, stats

四、模拟


最后是模拟实际运行的关键代码,模拟函数将在每一代调用一次。模拟时间步骤则是通过将总模拟时间除以时间间隔dt来确定的。例如,如果模拟时间设置为100秒,而dt等于1/25秒,那么总共需要模拟2500个时间步骤。在每一个步骤中,将进行以下操作:

1、碰撞检测:检查生物和食物颗粒之间的碰撞。当检测到碰撞时,该生物体将得到更新,食物颗粒将在一个新的随机位置上重生。

2、寻找最近的食物颗粒:对于每一个生物体,必须确定最近的食物颗粒。

3、确定最近的食物颗粒的方向:一旦最近的食物颗粒被一个生物体确定,就必须计算出这个颗粒的方向。

4、查询神经网络:由于使用了更新的方向值,因此每个生物的神经网络都将变得不同。

5、更新生物体:基于神经网络的响应,生物体的速度和位置都得到了更新。

下面是模拟函数:

def simulate(settings, organisms, foods, gen):
    total_time_steps = int(settings['gen_time'] / settings['dt'])
    #--- CYCLE THROUGH EACH TIME STEP ---------------------+
    for t_step in range(0, total_time_steps, 1):
        # PLOT SIMULATION FRAME
        #if gen == settings['gens'] - 1 and settings['plot']==True:
        if gen==49:
            plot_frame(settings, organisms, foods, gen, t_step)
        # UPDATE FITNESS FUNCTION
        for food in foods:
            for org in organisms:
                food_org_dist = dist(org.x, org.y, food.x, food.y)
                # UPDATE FITNESS FUNCTION
                if food_org_dist <= 0.075:
                    org.fitness += food.energy
                    food.respawn(settings)
                # RESET DISTANCE AND HEADING TO NEAREST FOOD SOURCE
                org.d_food = 100
                org.r_food = 0
        # CALCULATE HEADING TO NEAREST FOOD SOURCE
        for food in foods:
            for org in organisms:
                # CALCULATE DISTANCE TO SELECTED FOOD PARTICLE
                food_org_dist = dist(org.x, org.y, food.x, food.y)
                # DETERMINE IF THIS IS THE CLOSEST FOOD PARTICLE
                if food_org_dist < org.d_food:
                    org.d_food = food_org_dist
                    org.r_food = calc_heading(org, food)
        # GET ORGANISM RESPONSE
        for org in organisms:
            org.think()
        # UPDATE ORGANISMS POSITION AND VELOCITY
        for org in organisms:
            org.update_r(settings)
            org.update_vel(settings)
            org.update_pos(settings)
return organisms

五、结果


在创建所有的主要组件之后,最终代码就可以组装起来了。注意:在上面的文章中,忽略了一些更小的函数,因为它们太简单了,阅读它们要比直接阅读代码花费更长的时间。所有的代码我都放在GitHub上了,你可以点击这里下载

我使用了matplotlib来显示模拟。当你运行整个代码时,输出应该与此类似:

 

以上为译文

文章原标题《

Evolving Simple Organisms using a Genetic Algorithm and Deep Learning from Scratch with Python

》,作者:Nathan,译者:黄小凡,审校:袁虎。

文章为简译,更为详细的内容,请查看原文

 

时间: 2024-10-31 13:37:27

基于遗传算法(GA)进化的小游戏的相关文章

求助:基于liunx的多线程小游戏

问题描述 求助:基于liunx的多线程小游戏 最近需要做一个基于liunx的多线程小游戏,看了很多都只看到有贪吃蛇.希望各位大神能帮我想一下还有什么多线程的小游戏,最好能给我一个例子(代码和解释).跪谢各位大神!!! 解决方案 老虎棒子鸡小游戏http://download.csdn.net/detail/xiaomeng90/7029713 解决方案二: linux下多线程扑克游戏框架 http://wenku.baidu.com/link?url=Op3X-tugWBIOzy6HK69r4b

基于javascript实现泡泡大冒险网页版小游戏_javascript技巧

本文实例为大家分享了一个很有趣的网页版游戏,有点类似金山打字游戏的青蛙过河,供大家参考,具体内容如下 效果图: 实现思路: 益智类小游戏,主要练习打字能力,基于jq开发. 1.在输入框输入泡泡对应文字,点击enter提交 2.与泡泡文字相对提示分数 3.可以暂停操作 4.每次泡泡着地会减少血量,减少到0结束游戏 5.每过一段时间会加快泡泡下落速度 具体代码: <html> <head> <meta http-equiv="Content-Type" con

C++基于控制台实现的贪吃蛇小游戏_C 语言

本文实例讲述了C++基于控制台实现的贪吃蛇小游戏.分享给大家供大家参考.具体实现方法如下: #include <windows.h> #include <time.h> #include <stdio.h> #define MAX 100 #define UP 1 #define DOWN 2 #define LEFT 3 #define RIGHT 4 #define MOVING 5 #define STOP 0 HANDLE hMain_Out = NULL; H

百度本周推基于贴吧产品推出社区化小游戏平台

1月18日下午消息,百度本周即将基于贴吧产品推出社区化小游戏平台,目前首批小游戏产品已经在试运行.其中"打豆豆"上线两个多月,已累计被玩近2.5亿人次. 据悉,百度将小游戏被植入到了对应的贴吧讨论区,玩游戏的同时,还可结交玩伴,更具趣味和挑战.以"黄金矿工"贴吧为例,其顶部即是该游戏的操作界面, 网友可以"即点即玩".游戏右侧还有一个排行榜,展示着该款游戏的高手排名.用户和好友排名. 百度贴吧方面表示,小游戏平台运营以来累计超5000万人次参与.

百度将基于贴吧推出小游戏平台 部分产品已上线

中介交易 http://www.aliyun.com/zixun/aggregation/6858.html">SEO诊断 淘宝客 云主机 技术大厅 据百度内部人士透露,百度近日即将基于其贴吧产品推出小游戏平台.这是百度继推出网页游戏后在网游领域的最大动作. 小游戏通常指用Flash技术制作的简单.趣味的休闲类网上游戏.国内盛大.腾讯等公司均有自己的小游戏平台,这一领域还有独立公司如4399等网站. 据百度内部人士透露,百度本周将推出的小游戏平台将依托于百度贴吧,其竞争优势指向现成的数千万

基于javascript实现句子翻牌网页版小游戏_javascript技巧

本文实例为大家分享了js实现句子翻牌网页版小游戏,供大家参考,具体内容如下 效果图: 实现思路: 考察打字能力和记忆能力的益智小游戏. 1.会先把一段文字显示 2.一小段时间后显示背面 3.输入框输入文字与文字全部对应显示正面 具体代码: <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>

HTML5小游戏,能借微信做出个4399吗?

中介交易 SEO诊断 淘宝客 云主机 技术大厅 文/王聪佶(我的自媒体:企鹅生态) 继<围住神经猫>后,又一款基于HTML5技术的小游戏<看你有多色>大火于朋友圈,据其背后开发商博雅互动提供的资料,<看你有多色>在一天内取得了1013万的独立IP访问,成为又一个经典的微信"病毒式"传播案例. 当然,所有人都知道,<神经猫>.<看你有多色>及各种山寨版都是"短命"货,短则两天.长则一周,这些小游戏就将消失在人

WEBJX收集12个非常有创意的JavaScript小游戏

JavaScript 在Web开发过程中已经是必不可少的重要分子,他推动着Web的交互性往越来越高的层次发展,现在的很多Web游戏也基于这类语言开发. 这里是12个非常有创意的JavaScript小游戏,希望在给我们带来趣味的同时也能更进一步地了解更深层次的JavaScript语言,原来它可以这样的. Browser Pong Twitch Browser Ball Crystal Galazy Video & Picture Puzzle Apophis 2029 Bing-Bong Bomb

Cocos2d-x 版本小游戏 《是男人就下100层》 项目开源

原文:Cocos2d-x 版本小游戏 <是男人就下100层> 项目开源 这个是很久就开始动手写的一个小游戏了,直到最近才把它收尾了,拖拖拉拉的毛病总是很难改啊.  项目是基于 cocos2d-x v2.2 版本 ,目前只编译到了 Win8 平台上,并且已经上传到了商店,支持 ARM 以及 X86,其它平台的可以自己动手术去编译. 下载试玩:点这里  项目介绍 这毕竟是个小游戏,本身其实没有什么技术难点,主要在于项目的设计,分为如下几个小模块   1.玩家 (Player) 玩家类我用了单例模式