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; } } } } }