// Assign random mutations to the given tree. protected void Mutate(N_Root child) { // First, check if there'll be any mutation at all. float random = UnityEngine.Random.Range(0.0f, 1.0f); if (random < mutationRate) { List <Node> thresholds = TreeOperations.RetrieveNodesOfType(child, typeof(N_Threshold)); List <Node> probNodes = TreeOperations.RetrieveNodesOfType(child, typeof(N_ProbabilitySelector)); // Randomise between whether to change thresholds or probabilities random = UnityEngine.Random.Range(0.0f, 1.0f); // If no probnode exists, change condition if there are any instead if ((random <= 0.25f && thresholds.Count > 0)) { //Debug.Log("Changing threshold!"); // Get random index within range of list int index = UnityEngine.Random.Range(0, thresholds.Count); N_Threshold thresh = thresholds[index] as N_Threshold; // Mutate threshold by random offset int offset = UnityEngine.Random.Range(minThresholdOffset, maxTresholdOffset); thresh.SetThreshold(thresh.Threshold + offset); } else if (random > 0.25f && random <= 0.5f && probNodes.Count > 0) // Adjust relative probabilities on a probability selector. { //Debug.Log("Changing prob!"); // Get random index within range of list int index = UnityEngine.Random.Range(0, probNodes.Count); N_ProbabilitySelector probSelect = probNodes[index] as N_ProbabilitySelector; // Check so that the probablitySelector has any children. if (probSelect.GetChildren().Count <= 0) { return; } // Calculate total probability and retrieve a relative offset based on it. float totalProb = 0.0f; foreach (Node n in probSelect.GetChildren()) { totalProb += probSelect.GetProbabilityWeight(n); } float offset = totalProb * (relativeProbabilityMutation / 100.0f); // Also, get a random sign to decide whether to substract or add offset // and a random index for which child to be changed. float randomSign = Mathf.Sign(UnityEngine.Random.Range(-1.0f, 1.0f)); int randomChildIndex = UnityEngine.Random.Range(0, probSelect.GetChildren().Count); // Finally, offset the given childs probability by the random amount. probSelect.OffsetProbabilityWeight(probSelect.GetChildren()[randomChildIndex] , offset * randomSign); } else if (random > 0.5f && random <= 0.75f) // Change subtree { //Debug.Log("Changing subtree!"); List <Node> subtrees = TreeOperations.RetrieveSubtreeNodes(child); int randomIndex = UnityEngine.Random.Range(0, subtrees.Count); Node subtree = subtrees[randomIndex]; N_CompositionNode parentComp = subtree.Parent as N_CompositionNode; // Get a random subtree index and replace its position in the tree with // a new randomized subtree instead. parentComp.ReplaceChild(subtree, RandomSubtree()); } else if (random > 0.75f) // Change composition { //Debug.Log("Changing composition!"); List <Node> comps = TreeOperations.RetrieveNodesOfType(child, typeof(N_CompositionNode)); int randomIndex = UnityEngine.Random.Range(0, comps.Count); N_CompositionNode replaceComp = comps[randomIndex] as N_CompositionNode; // If parent is null, this comp is the initial comp. if (replaceComp.Parent != null) { Node compParent = replaceComp.Parent; List <Node> children = replaceComp.GetChildren(); // Attach old comps children to the new one. N_CompositionNode newComp = RandomComp(); // Make sure to keep structure of subtrees if (replaceComp.IsSubtree) { newComp.IsSubtree = true; } foreach (Node c in children) { c.Parent = newComp; newComp.AddLast(c); } // Reattach parent to the new comp if (compParent.GetType().IsSubclassOf(typeof(N_CompositionNode))) { N_CompositionNode compParent_comp = compParent as N_CompositionNode; compParent_comp.ReplaceChild(replaceComp, newComp); } else if (compParent.GetType().IsSubclassOf(typeof(N_Decorator))) { N_Decorator compParent_dec = compParent as N_Decorator; compParent_dec.Child = newComp; } } } } }
// Combine parents and create two new children based on them protected void Combine(out Genome child0, out Genome child1, Genome parent0, Genome parent1) { Node subtree0, subtree1 = null; // First, check if there'll be any combination/crossover. float random = UnityEngine.Random.Range(0.0f, 1.0f); if (random < combinationRate) { List <Node> subtrees0 = TreeOperations.RetrieveSubtreeNodes(parent0.RootNode); List <Node> subtrees1 = TreeOperations.RetrieveSubtreeNodes(parent1.RootNode); // Select to random subtrees... int randomIndex = UnityEngine.Random.Range(0, subtrees0.Count); subtree0 = subtrees0[randomIndex]; randomIndex = UnityEngine.Random.Range(0, subtrees1.Count); subtree1 = subtrees1[randomIndex]; // Swap subtrees between 0 and 1. if (subtree0.Parent.GetType().IsSubclassOf(typeof(N_CompositionNode))) { N_CompositionNode comp0 = subtree0.Parent as N_CompositionNode; comp0.ReplaceChild(subtree0, StaticMethods.DeepCopy <Node>(subtree1)); } // Swap subtrees between 1 and 0. if (subtree1.Parent.GetType().IsSubclassOf(typeof(N_CompositionNode))) { N_CompositionNode comp1 = subtree1.Parent as N_CompositionNode; comp1.ReplaceChild(subtree1, StaticMethods.DeepCopy <Node>(subtree0)); } #region Old Combination //// Get initial comp of parent 0 //N_CompositionNode comp0 = parent0.RootNode.Child as N_CompositionNode; //// Fetch a random subtree from the parent's subtrees //int randomIndex = UnityEngine.Random.Range(0, comp0.GetChildren().Count); //subtree0 = comp0.GetChildren()[randomIndex]; //// Get initial comp of parent 1 //N_CompositionNode comp1 = parent1.RootNode.Child as N_CompositionNode; //// Fetch a random subtree from the parent's subtrees //randomIndex = UnityEngine.Random.Range(0, comp1.GetChildren().Count); //subtree1 = comp1.GetChildren()[randomIndex]; //// Swap subtrees between 0 and 1. //if (subtree0.Parent.GetType().IsSubclassOf(typeof(N_CompositionNode))) //{ // comp0.ReplaceChild(subtree0, StaticMethods.DeepCopy<Node>(subtree1)); //} //// Swap subtrees between 1 and 0. //if (subtree1.Parent.GetType().IsSubclassOf(typeof(N_CompositionNode))) //{ // comp1.ReplaceChild(subtree1, StaticMethods.DeepCopy<Node>(subtree0)); //} #endregion } // Regardless of combination, assign the children to be the parents. (combined or not) child0 = parent0; child1 = parent1; }