遗传算法的简单使用
1、示例说明
前几天记了一下遗传算法的基本概念,我们知道,遗传算法就是模拟达尔文生物进化论而提出来的算法。这里提供一个遗传算法使用的简单示例,在这个示例中,有一条吃老鼠的蛇,这条蛇只吃体型较小的老鼠,老鼠种群经过N代繁殖,经历了物竞天择、适者生存的自然法则,最后基本都进化成了体型很大的老鼠,蛇吃不了它们,当然也有少数基因突变的老鼠体型还是很小,依然躲不过被蛇吃的命运。下面在unity中简单实现一下它:
2、定义老鼠个体类
//////////////////////////////////////////////////////////////////// // _ooOoo_ // // o8888888o // // 88" . "88 // // (| ^_^ |) // // O\ = /O // // ____/`---'\____ // // .' \\| |// `. // // / \\||| : |||// \ // // / _||||| -:- |||||- \ // // | | \\\ - /// | | // // | \_| ''\---/'' | | // // \ .-\__ `-` ___/-. / // // ___`. .' /--.--\ `. . ___ // // ."" '< `.___\_<|>_/___.' >'"". // // | | : `- \`.;`\ _ /`;.`/ - ` : | | // // \ \ `-. \_ __\ /__ _/ .-` / / // // ========`-.____`-.___\_____/___.-`____.-'======== // // `=---=' // // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ // // 佛祖保佑 永无BUG // //////////////////////////////////////////////////////////////////// using System.Collections; using System.Collections.Generic; using UnityEngine; public class RatItem : MonoBehaviour { public float size = 1;//大小 public float survivalTime = 8;//存活时间 //被蛇吃 public void Dead() { survivalTime = Population.timeCount; gameObject.SetActive(false); } }
3、定义老鼠种群管理类
//////////////////////////////////////////////////////////////////// // _ooOoo_ // // o8888888o // // 88" . "88 // // (| ^_^ |) // // O\ = /O // // ____/`---'\____ // // .' \\| |// `. // // / \\||| : |||// \ // // / _||||| -:- |||||- \ // // | | \\\ - /// | | // // | \_| ''\---/'' | | // // \ .-\__ `-` ___/-. / // // ___`. .' /--.--\ `. . ___ // // ."" '< `.___\_<|>_/___.' >'"". // // | | : `- \`.;`\ _ /`;.`/ - ` : | | // // \ \ `-. \_ __\ /__ _/ .-` / / // // ========`-.____`-.___\_____/___.-`____.-'======== // // `=---=' // // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ // // 佛祖保佑 永无BUG // //////////////////////////////////////////////////////////////////// using System.Collections; using System.Collections.Generic; using System.Linq; using UnityEngine; using UnityEngine.UI; public class Population : MonoBehaviour { public GameObject ratPrefab;//老鼠prefab public int populationSize = 10;//种群大小 public List<GameObject> population = new List<GameObject>();//老鼠种群 static List<GameObject> ratSize; public static float timeCount = 0;//计时 private int trailInterval = 10;//每一代训练间隔 private int count = 1;//第几代老鼠 public float mutation = 0.1f;//基因突变概率 public Text countText;//第几代显示 public Text timeCountText;//时间显示 void Start () { //初始化第一代种群 for (int i = 0; i < populationSize; i++) { Vector3 pos = new Vector3(Random.Range(-3, 3), 0, Random.Range(-3, 3)); GameObject go = Instantiate(ratPrefab, pos, Quaternion.identity); float randomSize= Random.Range(1, 4); go.GetComponent<RatItem>().size = randomSize; go.transform.localScale = new Vector3(randomSize, randomSize, randomSize); population.Add(go); } ratSize = population.OrderByDescending(go => go.GetComponent<RatItem>().size).ToList(); } void Update () { //定时繁衍新一代 timeCount += Time.deltaTime; if (timeCount > trailInterval) { BreedNewPopulation(); timeCount = 0; } countText.text ="繁衍代数:"+ count.ToString(); timeCountText.text = "计时:" + timeCount.ToString(); } //繁衍一代 void BreedNewPopulation() { List<GameObject> newPopulation = new List<GameObject>(); //给上一代个体列表按存活时间降序排序 List<GameObject> sortedList = population.OrderByDescending(go => go.GetComponent<RatItem>().survivalTime).ToList(); //清空上一代列表 population.Clear(); ratSize.Clear(); //选择优良的两个父代(存活时间长)去繁殖新一代 for (int i =0; i < (int)(sortedList.Count / 2); i++) { population.Add(Breed(sortedList[i].GetComponent<RatItem>(), sortedList[i + 1].GetComponent<RatItem>())); population.Add(Breed(sortedList[i + 1].GetComponent<RatItem>(), sortedList[i].GetComponent<RatItem>())); } ratSize = population.OrderByDescending(go => go.GetComponent<RatItem>().size).ToList(); //销毁先前所有的种群 for (int i = 0; i < sortedList.Count; i++) { Destroy(sortedList[i]); } count++; } //两个父代繁殖出新个体 (交叉) GameObject Breed(RatItem item1,RatItem item2) { Vector3 pos = new Vector3(Random.Range(-3, 3), 0, Random.Range(-3, 3)); GameObject go = Instantiate(ratPrefab, pos, Quaternion.identity); RatItem item = go.GetComponent<RatItem>(); //新个体随机继承父亲或母亲的基因 if (Random.Range(0, 100) > mutation * 100) { float random= Random.Range(0, 1) > 0.5f ? item1.size : item2.size; item.size = random; go.transform.localScale = new Vector3(random, random, random); } //基因突变 else { float random = Random.Range(0, 2); item.size = random; go.transform.localScale = new Vector3(random, random, random); } return go; } //得到体型最小的个体 public static GameObject GetSmallRat() { if (ratSize.Count > 0) { GameObject go = ratSize[ratSize.Count - 1]; go.GetComponent<RatItem>().Dead(); ratSize.Remove(go); return go; } else return null; } }
4、定义蛇类
//////////////////////////////////////////////////////////////////// // _ooOoo_ // // o8888888o // // 88" . "88 // // (| ^_^ |) // // O\ = /O // // ____/`---'\____ // // .' \\| |// `. // // / \\||| : |||// \ // // / _||||| -:- |||||- \ // // | | \\\ - /// | | // // | \_| ''\---/'' | | // // \ .-\__ `-` ___/-. / // // ___`. .' /--.--\ `. . ___ // // ."" '< `.___\_<|>_/___.' >'"". // // | | : `- \`.;`\ _ /`;.`/ - ` : | | // // \ \ `-. \_ __\ /__ _/ .-` / / // // ========`-.____`-.___\_____/___.-`____.-'======== // // `=---=' // // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ // // 佛祖保佑 永无BUG // //////////////////////////////////////////////////////////////////// using System.Collections; using System.Collections.Generic; using System.Linq; using UnityEngine; public class Snake : MonoBehaviour { public float interval = 2;//每三秒吃一只老鼠 private float timeCount = 0;//计时 // Update is called once per frame void Update () { timeCount += Time.deltaTime; if (timeCount > interval) { EatRat(); timeCount = 0; } } //吃老鼠 void EatRat() { GameObject go = Population.GetSmallRat(); if (go != null) { if (go.GetComponent<RatItem>().size < 2.5f) { Debug.Log("吃只小老鼠!"); go.GetComponent<RatItem>().Dead(); } else Debug.Log("老鼠都太大了,我吃不下了!"); } } }
5、操作步骤与运行测试
在上述代码中,首先初始化第一代老鼠种群,蛇会吃了淘汰掉体型较小的老鼠,老鼠种群会挑选基因优良(存活时间长)的老鼠父代去繁衍下一代。 在unity中,建好一个场景,并制作老鼠prefab,将RatItem类挂到该prefab上,准备好所有后运行场景:
可以看到,经过5代繁衍,后面的老鼠体型都是很大一个了,蛇已经吃不了它们,但还是偶尔会有基因突变的小老鼠繁衍出来。
如有错误,欢迎指正!