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);
    }
Exemple #3
0
    // 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;
                    }
                }
            }
        }
    }