遗传算法初探-unity
引子 :茫茫宇宙中存在着一个神级文明,尽管他们有着领先的科技,但文明的进程却因为种种因素逐步走向灭亡。为了防止自身文明的覆灭,神级文明想要通过模拟自身文明形成和发展来寻求解救自身的办法。于是他们用自己的科技创造了数以万计的小宇宙,并为其播种下生命起源的种子,让文明得以演化。他们为这些创造的世界中潜移默化的植入超越文明自身进化的技术,加速文明的进程。他们观测着这些文明的走向,无数文明兴衰起落。尽管如此,仍然有着很多文明走向更远的未来,甚至由于神级文明不断注入超越他们时代的技术,他们也已经是接近神级文明的小宇宙。神级文明也从中寻找到了自身的影子,并吸取这些能存活文明的经验,摆脱自身灭亡的命运。
简介
遗传算法(Genetic Algorithm)是模拟达尔文生物进化论的自然选择和遗传学机理的生物进化过程的计算模型,是一种通过模拟自然进化过程搜索最优解的方法。遗传算法可以算是计算机领域的仿生学。它摆脱多数解决问题的思路,把通过问题找到一组解的思路,转化为通过各种解来尝试最优的解决问题的思路,是一种像是“依赖倒转”的办法。
比如我们想到在灰色地面上最容易隐藏的猫,而猫的毛发颜色是由基因控制。我们通过一只褐色和一只白色的猫的父代,让他们繁殖并不断从繁殖后的世代中选取最容易在灰色地面隐藏的样本,让他们不断重复这一选择过程。经过数代的选择,个体中甚至突变产生了眼睛颜色也是灰色的个人体,我们会发现基因是灰色毛发,眼睛颜色也是灰色的个体不断存活下来,并得以生存。遗传算法模拟出了这种毛色(表达),繁殖后代(传递),眼睛变灰(突变),存活死亡(自然选择)的过程。
简易的遗传算法(Unity)
这里我们使用unity2d来模拟遗传算法的实现,创建一个2d角色为预制体,并为其添加2dcollider和DNA脚本。然后创建空物体,为其添加populationmanager脚本并添加预制体到参数,用来生成不同的角色。我们通过DNA来控制2d角色的材质颜色,再通过点击角色来挑出最接近某种颜色的角色肤色,然后不断重复这一过程。慢慢的,角色的肤色不断的接近我们所期望的某种肤色
DNA——决定角色的材质颜色即肤色
using UnityEngine;
namespace PeopleColor
{
//基因,用来控制人的表现,肤色,大小等
public class DNA : MonoBehaviour
{
//gene for colour
public float r;
public float g;
public float b;
public float s;
bool dead = false;
public float timeToDie = 0;
SpriteRenderer sRenderer;
Collider2D sCollider;
//当鼠标点击的时候角色死亡,手动模拟遗传选择
void OnMouseDown()
{
dead = true;
timeToDie = PopulationManager.elapsed;
sRenderer.enabled = false;
sCollider.enabled = false;
}
// Use this for initialization
void Start()
{
sRenderer = GetComponent<SpriteRenderer>();
sCollider = GetComponent<Collider2D>();
sRenderer.color = new Color(r, b, g);
}
}
}
PopulationManager——控制世代的繁衍
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Linq;
namespace PeopleColor
{
public class PopulationManager : MonoBehaviour
{
public GameObject personPrefab;
public int populationSize = 10;
List<GameObject> population = new List<GameObject>();
public static float elapsed = 0;
/// <summary>
/// 训练间隔
/// </summary>
int trialTime = 10;
/// <summary>
/// 第几代人
/// </summary>
int generation = 1;
GUIStyle guiStyle = new GUIStyle();
void OnGUI()
{
guiStyle.fontSize = 50;
guiStyle.normal.textColor = Color.white;
GUI.Label(new Rect(10, 10, 100, 20), "Generation: " + generation, guiStyle);
GUI.Label(new Rect(10, 65, 100, 20), "Trial Time: " + (int)elapsed, guiStyle);
}
// Use this for initialization
void Start()
{
//初始化:随机产生不同肤色和大小的人
for (int i = 0; i < populationSize; i++)
{
Vector3 pos = new Vector3(Random.Range(-9, 9), Random.Range(-4.5f, 4.5f), 0);
GameObject go = Instantiate(personPrefab, pos, Quaternion.identity);
go.GetComponent<DNA>().r = Random.Range(0.0f, 1.0f);
go.GetComponent<DNA>().g = Random.Range(0.0f, 1.0f);
go.GetComponent<DNA>().b = Random.Range(0.0f, 1.0f);
go.GetComponent<DNA>().s = Random.Range(0.1f, 0.3f);
population.Add(go);
}
}
/// <summary>
/// 繁殖后代:模拟基因选择,二者择其一,或突变
/// </summary>
/// <param name="parent1">父代1</param>
/// <param name="parent2">父代2</param>
/// <returns></returns>
GameObject Breed(GameObject parent1, GameObject parent2)
{
Vector3 pos = new Vector3(Random.Range(-9, 9), Random.Range(-4.5f, 4.5f), 0);
GameObject offspring = Instantiate(personPrefab, pos, Quaternion.identity);
DNA dna1 = parent1.GetComponent<DNA>();
DNA dna2 = parent2.GetComponent<DNA>();
//swap parent dna
if (Random.Range(0, 1000) > 5)//5‰的概率产生突变
{
offspring.GetComponent<DNA>().r = Random.Range(0, 10) < 5 ? dna1.r : dna2.r;
offspring.GetComponent<DNA>().g = Random.Range(0, 10) < 5 ? dna1.g : dna2.g;
offspring.GetComponent<DNA>().b = Random.Range(0, 10) < 5 ? dna1.b : dna2.b;
offspring.GetComponent<DNA>().b = Random.Range(0, 10) < 5 ? dna1.s : dna2.s;
}
else//变异
{
offspring.GetComponent<DNA>().r = Random.Range(0.0f, 1.0f);
offspring.GetComponent<DNA>().g = Random.Range(0.0f, 1.0f);
offspring.GetComponent<DNA>().b = Random.Range(0.0f, 1.0f);
offspring.GetComponent<DNA>().s = Random.Range(0.1f, 0.3f);
}
return offspring;
}
/// <summary>
///
/// </summary>
void BreedNewPopulation()
{
List<GameObject> newPopulation = new List<GameObject>();
//get rid of unfit individuals
//淘汰不合适的个体
List<GameObject> sortedList = population.OrderByDescending(o => o.GetComponent<DNA>().timeToDie).ToList();
foreach (var o in sortedList)
{
Debug.Log("time2Die: " + o.GetComponent<DNA>().timeToDie);
}
population.Clear();
//breed upper half of sorted list
//繁殖已排序列表中的
for (int i = (int)(sortedList.Count / 2.0f) - 1; i < sortedList.Count - 1; i++)
{
population.Add(Breed(sortedList[i], sortedList[i + 1]));
population.Add(Breed(sortedList[i + 1], sortedList[i]));
}
//destroy all parents and previous population
//销毁先前所有的种群
for (int i = 0; i < sortedList.Count; i++)
{
Destroy(sortedList[i]);
}
generation++;
}
// Update is called once per frame
void Update()
{
elapsed += Time.deltaTime;
if (elapsed > trialTime)
{
BreedNewPopulation();
elapsed = 0;
}
}
}
}