前言

记得学遗传算法的时候,有个案例大致意思是:

山羊会在山坡不同高度出生,然后朝着不同的方向行走,当低于一定高度的时候山羊会死亡。当N代以后,模拟山羊的属性。

这个案例的最大高度就是山顶,山羊会不停奔走,繁衍会产生后代,是一道比较经典的族群繁衍问题。这里我做下延伸,改编为人口问题。

规则

/// 管理器
/// 规则:
/// 1,管理器控制初始人口的数量,最大寿命区间等初始数值
/// 2,管理器汇总人口的出生,并分配初始位置x/性别
/// 3,管理器汇总人口的死亡,并在代际全部死亡的时候,打印出数值单/// 小人AI
/// 规则:
/// 1,初始性别为true和false,异性相遇会进行判断:双反年龄大于1分钟,则进行繁殖
/// 2,生育有50%的可能关掉触发器,由母诞生1~3个子女
/// 2,子女代际由父母最大代际+1,最大寿命在父母平均寿命正负1分钟区间;运气值继承父母;移速/改变运气时间随机继承父或母
/// 3,繁殖后双方的最大寿命降低0.5到2分钟
/// 3,1~3分钟改变一次运气,改变运气机会的时候有1%可能意外死亡;运气每秒都在移动,移动范围低于管理器最低运气则会立即死亡
/// 4,当前寿命小于0立刻死亡

代码

using System.Collections;
using System.Collections.Generic;
using UnityEngine;/// <summary>
/// 管理器
/// 规则:
/// 1,管理器控制初始人口的数量,最大寿命区间等初始数值
/// 2,管理器汇总人口的出生,并分配初始位置x/性别
/// 3,管理器汇总人口的死亡,并在代际全部死亡的时候,打印出数值单
/// </summary>
public class AIManager : MonoBehaviour
{/// <summary>/// 代际清单/// </summary>public class Repertoire{public List<AIMan> aiList = new List<AIMan>();public int bornNum;//出生人数public float allDieLife;//所有死亡岁数public float allDieLuck;//所有死亡运气public float allDieMoveSpeed;//所有死亡移速public float allDieChange;//所有死亡改变时间public int accDie;//意外死亡public int dy;//难产死亡}/// <summary>/// 人口总管理器/// </summary>private Dictionary<int, Repertoire> aiManDic = new Dictionary<int, Repertoire>();/// <summary>/// 最差运气/// </summary>public float minLuck = -150f;/// <summary>/// 上报并出生人口,自主激活触发器/// </summary>public GameObject SentAIMan(float _maxLife, int _inter, float _changMoveTime,float _moveSpeed){var _sex = Random.Range(0, 1f) > 0.5f ? true : false;GameObject _obj = GameObject.Instantiate( Resources.Load<GameObject>(_sex? "man1":"man2"));_obj.transform.position = new Vector3(Random.Range(-12, 12), 0, 0);if (!aiManDic.ContainsKey(_inter)){Debug.Log("代际" + _inter + "出生时间" + Time.time);aiManDic.Add(_inter, new Repertoire());} var _ai = _obj.AddComponent<AIMan>();_ai.Born(this , _sex, _maxLife, _inter, _changMoveTime,_moveSpeed);var _get = aiManDic[_inter];_get.aiList.Add(_ai);_get.bornNum++;return _obj;}/// <summary>/// 人口死亡/// </summary>public void RemoveAIMan(AIMan _ai,int _dieState){if (aiManDic.ContainsKey(_ai.inter)){var _get = aiManDic[_ai.inter];_get.allDieLife += _ai.currentLife / 60;_get.allDieLuck += _ai.transform.position.y;_get.allDieMoveSpeed += _ai.moveSpeed;_get.allDieChange += _ai.changeMoveTime;if (_dieState == 1) _get.dy++;if (_dieState == 2) _get.accDie++;_get.aiList.Remove(_ai);if (_get.aiList.Count == 0){Debug.Log("代际" + _ai.inter + "消亡,出生人数:" + _get.bornNum + "平均生活时间:" + _get.allDieLife / _get.bornNum + "平均运气:" + _get.allDieLuck / _get.bornNum+ "平均改变时间:" + _get.allDieChange / _get.bornNum + "平均速度:" + _get.allDieMoveSpeed / _get.bornNum+ "难产死亡人数"+_get.dy+"意外死亡人数"+_get.accDie+"消亡时间:"+Time.time);//aiManDic.Remove(_ai.inter);} }else{Debug.LogError("代际为空" + _ai.inter);}}// Start is called before the first frame updatevoid Start(){//初始2000人,随机寿命在3到5分钟,改变运气时间在0.1~1分钟之间,移速在0.03~0.5之间,随机运气在正负100以内for (var _i = 0; _i < 2000; _i++){var _child = SentAIMan(Random.Range(3f, 5f) * 60 ,0, Random.Range(0.03f,0.5f)*60,Random.Range(0.3f,1));_child.transform.position = new Vector3(_child.transform.position.x, Random.Range(-100f,100f), 0);}}  // Update is called once per framevoid Update(){}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;/// <summary>
/// 小人AI
/// 规则:
/// 1,初始性别为true和false,异性相遇会进行判断:双反年龄大于1分钟,则进行繁殖
/// 2,生育有50%的可能关掉触发器,由母诞生1~3个子女
/// 2,子女代际由父母最大代际+1,最大寿命在父母平均寿命正负1分钟区间;运气值继承父母;移速/改变运气时间随机继承父或母
/// 3,繁殖后双方的最大寿命降低0.5到2分钟
/// 3,1~3分钟改变一次运气,改变运气机会的时候有1%可能意外死亡;运气每秒都在移动,移动范围低于管理器最低运气则会立即死亡
/// 4,当前寿命小于0立刻死亡
/// </summary>
public class AIMan : MonoBehaviour
{/// <summary>/// 性别/// </summary>public bool sex;/// <summary>/// 最大寿命/// </summary>public float maxLife;/// <summary>/// 年龄/// </summary>public float currentLife;/// <summary>/// 代际/// </summary>public int inter;/// <summary>/// 移速/// </summary>public float moveSpeed;/// <summary>/// 改变命运时间/// </summary>public float changeMoveTime;/// <summary>/// 运气时间/// </summary>public float luckTime;   /// <summary>/// 运气方向/// </summary>public bool luck;/// <summary>/// AI管理器/// </summary>private AIManager aiManager;/// <summary>/// 出生/// </summary>public void Born(AIManager _aiManager, bool _sex,float _maxLife,int _inter,float _changMoveTime,float _moveSpeed){aiManager = _aiManager;sex = _sex;maxLife = _maxLife;inter = _inter;changeMoveTime = _changMoveTime;moveSpeed = _moveSpeed;GetComponent<SphereCollider>().enabled = true;currentLife = 0;//出生时候有一次改变运气的机会ChangerLuck(true);       }/// <summary>/// 行为器/// </summary>void Update(){currentLife += Time.deltaTime;if (Time.time - luckTime > changeMoveTime) ChangerLuck(false);transform.position += Vector3.up * (luck ? 1 : -1) * moveSpeed;if (currentLife > maxLife || transform.position.y<aiManager.minLuck) Die(0);}/// <summary>/// 改变运气/// 运气回落、否极泰来/// </summary>void ChangerLuck(bool _isBorn){luckTime = Time.time;      luck = Random.Range(0, 1f) < 0.5f ? false:true;if (transform.position.y > 300) luck = false;if (transform.position.y < 100 && Random.Range(0, 1f) < 0.7f) luck = true;if (!_isBorn && Random.Range(0, 1f) < 0.01f) Die(2);//意外死亡}/// <summary>/// 繁殖/// </summary>public void Bear(AIMan _father){var _remove = Random.Range(0.5f, 3) * 60;if (currentLife > maxLife - _remove){//难产Die(1);return;}var _bornNum = Random.Range(1,3);for (var _i = 0; _i < _bornNum; _i++){var _child = aiManager.SentAIMan(Random.Range(-1f, 1f) * 60 + (maxLife + _father.maxLife) / 2, 1 + (inter > _father.inter ? inter : _father.inter), Random.Range(0, 1f) > 0.5f ? changeMoveTime : _father.changeMoveTime,Random.Range(0,1f)>0.5f?moveSpeed:_father.moveSpeed);_child.transform.position = new Vector3(_child.transform.position.x, transform.position.y, 0);}//消减父母最大寿命maxLife -= _remove;if (Random.Range(0, 1f) > 0.5f) GetComponent<SphereCollider>().enabled = false;_father.maxLife -= _remove;if (Random.Range(0, 1f) > 0.5f) _father.gameObject.GetComponent<SphereCollider>().enabled = false;}/// <summary>/// 触发器/// </summary>private void OnTriggerEnter(Collider _col){var _ai = _col.gameObject.GetComponent<AIMan>();if (_ai != null){//同性无法繁殖if (_ai.sex == sex) return;if (_ai.currentLife < 60 || currentLife < 60) return;if (!sex) Bear(_ai);}else{Debug.LogError("产生程序异常并销毁对方");Destroy(_ai.gameObject);}}/// <summary>/// 死亡:0,正常死亡;1,难产;2,意外/// </summary>public void Die(int _state){GetComponent<SphereCollider>().enabled = false;aiManager.RemoveAIMan(this,_state);Destroy(gameObject);}
}

运行结果

第一次每次最大出生人数为3,运行结果如下:

第一次只繁衍到第七代就结束了,其中平均运气和平均改变时间、平均移速都在降低。

第二次我将每次最大出生人数设置为4,运行结果如下:

这次繁衍到第14代,族群才完全消亡。但值得注意的是,平均运气有所反复。

第三次我将每次最大出生人数设置为5,运行结果如下:

相比于前两次,这次的代际相隔基本趋于稳定,不是逐渐减缓。

消亡截图如下:

相比于前两次实验结果,这次的族群基本处于稳定上升阶段;平均运气和平均改变时间、平均移速也都在一定提升之后趋于稳定;平均寿命略有延长最终趋于比较稳定。

模拟测试截图

意义和反思

族群最大的问题,在于代际的延续,所以处于一个有序增长,是比较健康的状态。

前两次的实验结果,都由于单次繁衍最大个数过少而失败。

通过最后一次结果,我们可以看到,当族群稳定增长的时候,族群的基因会稳定在一个平均值。

当然这只是一次比较简单的模拟,如果考虑到现实情况,还应该更详细的考虑到个体差异,不过就不在此做出延伸。

最后,感兴趣的朋友,可以下载demo自己试玩。

遗传算法入门:族群繁衍问题相关推荐

  1. 遗传算法入门(连载1-10)

    注:整合by Leytton     原文:http://blog.csdn.net/zzwu/article/category/243066 . (连载之一) . 扎自<游戏编程中的人工智能技 ...

  2. 遗传算法入门到掌握(一)

    遗传算法入门到掌握(一) 心得:把解决方案做染色体 遗传算法的有趣应用很多,诸如寻路问题,8数码问题,囚犯困境,动作控制,找圆心问题(这是一个国外网友的建议:在一个不规则的多边形 中,寻找一个包含在该 ...

  3. GA遗传算法入门到掌握

    遗传算法的有趣应用很多,诸如寻路问题,8数码问题,囚犯困境,动作控制,找圆心问题(这是一个国外网友的建议:在一个不规则的多边形 中,寻找一个包含在该多边形内的最大圆圈的圆心.),TSP问题(在以后的章 ...

  4. 遗传算法入门(连载之十) 神经网络入门(连载预告)

    .游戏编程中的人工智能技术 . (连载之10) .. 这是<遗传算法入门>连载的最后一篇,将对连载来源进行一些说明. 0.本连载来自<游戏编程中的人工智能技术>一书,是该书第三 ...

  5. 大白话解析模拟退火算法、遗传算法入门

    优化算法入门系列文章目录(更新中): 1. 模拟退火算法 2. 遗传算法 一. 爬山算法 ( Hill Climbing ) 介绍模拟退火前,先介绍爬山算法.爬山算法是一种简单的贪心搜索算法,该算法每 ...

  6. 遗传算法入门(一)编码

    参考文章 遗传算法(Genetic Algorithm)详解与实现 遗传算法详解 附python代码实现python遗传算法重学CS的博客-CSDN博客 遗传算法 遗传算法 是模仿自然选择和繁殖的过程 ...

  7. 遗传算法入门到掌握(二)

     遗传算法引擎――GenAlg           [cpp] view plaincopy <span style="font-size:16px;">/遗传算法 c ...

  8. 遗传算法 python 简书_遗传算法入门

    遗传算法简介: 遗传算法(Genetic algorithm)属于演化计算( evolutionary computing),是随着人工智能领域发展而来的一种智能算法.正如它的名字所示,遗传算法是受达 ...

  9. python路线寻优_基于DEAP库的Python进化算法从入门到入土 --(四)遗传算法的改进...

    前言 前面一节我们尝试了用GA求解TSP问题,简单遗传算法总是不能很好收敛到一个较优的解,在用时和求解精度上都被贪心算法吊打.在末尾我们总结了三个可能的改进方向,这次我们想要沿着这三个方向试着改进简单 ...

最新文章

  1. java dateformat类_JAVA--常量池,Date类,SimpleDateFormat类与Calendar类
  2. 【转】每天一个linux命令(44):top命令
  3. Unity3D For Android 开发教程【转http://game.ceeger.com/Unity/Doc/2011/Unity3D_For_Android.html】...
  4. Xampp配置本地域名及常见错误解决
  5. Android本地应用程序应用方式介绍
  6. 《高翔视觉slam十四讲》学习笔记 第六讲 非线性优化
  7. springcloud整合sentinel
  8. 计算机usb端口没反应,usb接口没反应,小编教你电脑usb接口没反应怎么解决
  9. 语音识别 卷积神经网络,卷积神经网络字符识别
  10. 小学教资——教育教学口诀
  11. Quicker | 便捷的截屏软件 | 截图 | 截图OCR(图片编辑及文字识别)(二)
  12. 博弈论:零和博弈与常和博弈的区别
  13. font-size:字号大小
  14. 现代服务业行业税收筹划,信息技术公司节税方案
  15. v-text与v-html,v-text,v-html等区别
  16. 会声会影2022试用版 智能、快速、简单的视频剪辑软件
  17. 【Qt+FFmpeg】鼠标滚轮放大、缩小、移动——解码播放本地视频(三)
  18. (一)Shell的条件判断符及特殊变量
  19. python列表推导式[x for x in range(n)]
  20. 个人C语言的一次综合运用程序

热门文章

  1. 怎么样组建一个合格有技术含量的SEO团队?
  2. 命令行启动nginx、停止nginx 、重启nginx详细教程
  3. 基于FPGA的火焰识别系统开发——详细版
  4. 基于复杂网络的软件网络研究
  5. 第三方QQ登录时,获取unionID的问题
  6. android+仿最新网易云音乐底面栏,安卓仿网易云音乐通知栏控制音乐,默认显示Notification bigView...
  7. KVM虚拟机CPU Pinning(CPU 钉选)实践
  8. Oracle数据库(五)日期和时间的处理
  9. YOLOV5识别成语点选验证码
  10. 汇编:解决Win2k无法安装vm-tools、以及安装MASM汇编器连接器