/// <summary> /// Attempt to add a network to this species /// </summary> /// <param name="other">The network to add</param> /// <returns>True if the network is added to this species, false if the network is not part of the same species</returns> public bool AttemptAdd(NeatNetwork other) { if (!IsCompatible(other)) { return(false); } population.Add(other); other.assignedSpecies = this; return(true); }
public NeatNode(int ID, NodeType type, NeatNetwork network) { this.ID = ID; this.type = type; this.network = network; this.inputGenes = new List <NeatGene>(); this.outputGenes = new List <NeatGene>(); workingValue = 0.0f; }
public NeatSpecies(NeatController controller, NeatNetwork representative) { this.controller = controller; this.representative = representative; colour = Color.HSVToRGB(Random.value, Random.Range(0.5f, 1.0f), Random.Range(0.5f, 1.0f)); generationsLived = 0; guid = System.Guid.NewGuid(); population = new List <NeatNetwork>(); population.Add(representative); representative.assignedSpecies = this; }
public void AssignNetwork(NeatNetwork network) { if (character == null) { character = GetComponent <Character>(); } this.network = network; if (network != null) { character.SetColour(network.assignedSpecies.colour); } else { character.SetColour(Color.black); } }
/// <summary> /// Create the next generation of networks from this species /// </summary> /// <param name="allocation">How many networks this species has been allocated</param> /// <param name="newPopulation">Where to store new networks</param> public void NextGeneration(int allocation, List <NeatNetwork> newPopulation) { // Sort population from highest fitness to lowest population.Sort(); population.Reverse(); int breedRange = (int)(population.Count * representative.controller.breedConsideration); // Only consider the top x% for breeding int retainedCount = (int)(allocation * representative.controller.breedRetention); // Retain x% of top scorers into the next generation // Select a new represetative from current members representative = population[Random.Range(0, breedRange)]; representative.assignedSpecies = null; // Generate children for (int i = 0; i < allocation; ++i) { // Take the previous best scorers for the new generation if (i <= retainedCount && i < population.Count && population[i].fitness != 0.0f) { NeatNetwork clone = new NeatNetwork(population[i]); newPopulation.Add(clone); } // Breed an mutate a new network else { NeatNetwork A = population[Random.Range(0, breedRange)]; NeatNetwork B = population[Random.Range(0, breedRange)]; NeatNetwork child = NeatNetwork.Breed(A, B); child.CreateMutations(); newPopulation.Add(child); } } // Update (Population will be reassigned if this species is going to survive) population.Clear(); generationsLived++; }
/// <summary> /// Calculate the average adjusted fitness for this network /// </summary> /// <returns></returns> public float CalulateAverageAdjustedFitness() { float totalAdjustedFitness = 0.0f; foreach (NeatNetwork network in population) { // Count how many networks in this species align to this individual int matches = 0; foreach (NeatNetwork other in controller.population) { if (network == other || NeatNetwork.AreSameSpecies(network, other)) { matches++; } } totalAdjustedFitness += network.fitness / matches; } return(totalAdjustedFitness / population.Count); }
/// <summary> /// Read in the xml for a specfic generation /// </summary> /// <param name="writer"></param> public void ReadXML(XmlElement entry) { colour = new Color( float.Parse(entry.GetAttribute("ColourR")), float.Parse(entry.GetAttribute("ColourG")), float.Parse(entry.GetAttribute("ColourB")) ); guid = new System.Guid(entry.GetAttribute("Guid")); generationsLived = int.Parse(entry.GetAttribute("generationsLived")); population.Clear(); foreach (XmlElement child in entry.ChildNodes) { if (child.Name == "Representative") { representative = new NeatNetwork(controller, child); break; } } }
/// <summary> /// Generate a starting population /// </summary> public NeatNetwork[] GenerateBasePopulation(int count, int inputCount, int outputCount, int initialMutations = 1, bool attemptLoad = true) { if (attemptLoad) { population = new NeatNetwork[count]; if (LoadXML()) { Debug.Log("Loaded NEAT collection '" + collectionName + "' from generation " + generationCounter); return(BreedNextGeneration(count)); // Can only load that generation as a starting point } else { Debug.Log("Starting NEAT collection '" + collectionName + "' from scratch"); } } generationCounter = 1; population = new NeatNetwork[count]; activeSpecies = new List <NeatSpecies>(); for (int i = 0; i < count; ++i) { population[i] = new NeatNetwork(this, inputCount, outputCount); for (int m = 0; m < initialMutations; ++m) { population[i].CreateMutations(); } } AssignPopulationToSpecies(); Debug.Log("Generation " + generationCounter + " with " + activeSpecies.Count + " species"); return(population); }
/// <summary> /// Is this network compatible with this species /// </summary> /// <returns>True if the network is part of this species</returns> public bool IsCompatible(NeatNetwork other) { return(NeatNetwork.AreSameSpecies(representative, other)); }
/// <summary> /// Read in the xml for a specfic generation /// </summary> /// <param name="generation">The desired generation to load (Will load highest found, if -1)</param> public bool LoadXML(int generation = -1) { if (!System.IO.Directory.Exists(dataFolder + collectionName)) { return(false); } // Attempt to find highest generation if (generation == -1) { generation = 0; while (true) { if (!System.IO.File.Exists(dataFolder + collectionName + "/gen_" + (generation + 1) + ".xml")) { break; } else { generation++; } } } string path = dataFolder + collectionName + "/gen_" + generation + ".xml"; if (!System.IO.File.Exists(path)) { return(false); } XmlDocument document = new XmlDocument(); document.Load(path); // Read document XmlElement root = document.DocumentElement; foreach (XmlElement child in root.ChildNodes) { if (child.Name == "innovationCounter") { innovationCounter = System.Int32.Parse(child.InnerText); } else if (child.Name == "generationCounter") { generationCounter = System.Int32.Parse(child.InnerText); } else if (child.Name == "runTime") { runTime = System.Int32.Parse(child.InnerText); } // Read genes else if (child.Name == "Generation") { innovationIds = new Dictionary <Vector2Int, int>(); foreach (XmlElement gene in child.ChildNodes) { if (gene.Name != "gene") { continue; } int fromId = System.Int32.Parse(child.GetAttribute("from")); int toId = System.Int32.Parse(child.GetAttribute("to")); int inno = System.Int32.Parse(child.GetAttribute("inno")); innovationIds[new Vector2Int(fromId, toId)] = inno; } } // Read species (Need to read it before networks) else if (child.Name == "ActiveSpecies") { activeSpecies = new List <NeatSpecies>(); foreach (XmlElement entry in child.ChildNodes) { if (entry.Name != "Species") { continue; } activeSpecies.Add(new NeatSpecies(this, entry)); } } // Read networks else if (child.Name == "Population") { List <NeatNetwork> newPopulation = new List <NeatNetwork>(); foreach (XmlElement entry in child.ChildNodes) { if (entry.Name != "Network") { continue; } NeatNetwork network = new NeatNetwork(this, entry); newPopulation.Add(network); } population = newPopulation.ToArray(); } } Debug.Log("Read from '" + path + "'"); return(true); }