// Randomize a new BT using given defined subtrees and definitions. protected Genome RandomGenome() { N_Root root = new N_Root(); Genome randomGenome = new Genome(); // First, randomize starting composition. N_CompositionNode firstComp = RandomComp(); N_CompositionNode currentComp = firstComp; bool nestled = false; // Generate random subtrees for (int i = 0; i < genomeSubtrees; i++) { // Calculate random chance for adding a new composition as well // as ending it. float randomChance = UnityEngine.Random.Range(0.0f, 1.0f); if (randomChance < additionalCompChance && !nestled) { nestled = true; N_CompositionNode subComp = RandomComp(); // Attach new composition and add a subtree to it. currentComp.AddLast(subComp); currentComp = subComp; } else if (randomChance < (additionalCompChance + 0.2f) && nestled) { nestled = false; currentComp = firstComp; } // Lastly, add a random subtree to the current composition as // well as to the list of subtree roots. Node subTree = RandomSubtree(); randomGenome.SubRoots.Add(subTree); currentComp.AddLast(subTree); } root.Child = firstComp; randomGenome.RootNode = root; return(randomGenome); }
public static List <Node> RetrieveNodesOfType(N_Root tree, Type nodeType) { Queue <Node> itQ = new Queue <Node>(); List <Node> found = new List <Node>(); itQ.Enqueue(tree.Child); // Do a breadth-first search to retrieve all nodes of the given type. while (itQ.Count > 0) { Node current = itQ.Dequeue(); // If the current node ís the same as the search type // or a subclass of it, add it to found. if (current.GetType().IsSubclassOf(nodeType) || current.GetType() == nodeType) { found.Add(current); } // If node is a composition or decorator, enqueue its child(ren). if (current.GetType().IsSubclassOf(typeof(N_CompositionNode))) { N_CompositionNode comp = current as N_CompositionNode; foreach (Node n in comp.GetChildren()) { itQ.Enqueue(n); } } else if (current.GetType().IsSubclassOf(typeof(N_Decorator))) { N_Decorator dec = current as N_Decorator; itQ.Enqueue(dec.Child); } } // Lastly, return the found children. return(found); }
// Return a list of all nodes that act as roots for a randomized subtree. public static List <Node> RetrieveSubtreeNodes(N_Root tree) { Queue <Node> itQ = new Queue <Node>(); List <Node> found = new List <Node>(); itQ.Enqueue(tree.Child); while (itQ.Count > 0) { Node current = itQ.Dequeue(); // If current node is flagged as subtree, add it to found if (current.IsSubtree) { found.Add(current); } // If node is a composition or decorator, enqueue its child(ren). if (current.GetType().IsSubclassOf(typeof(N_CompositionNode))) { N_CompositionNode comp = current as N_CompositionNode; foreach (Node n in comp.GetChildren()) { itQ.Enqueue(n); } } else if (current.GetType().IsSubclassOf(typeof(N_Decorator))) { N_Decorator dec = current as N_Decorator; itQ.Enqueue(dec.Child); } } // Return all nodes found with the subtree flag return(found); }
// 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; }