Example #1
0
 public PlannerNode(PlannerNode copyOf)
 {
     Parent      = copyOf.Parent;
     RunningCost = copyOf.RunningCost;
     RunningData = copyOf.RunningData;
     Action      = copyOf.Action;
 }
Example #2
0
            public void Execute()
            {
                Leaves = new List <PlannerNode>();

                PlannerNode startNode = new PlannerNode(null, ApplyBeatToWorldState(State, StartBeat), StartBeat);

                if (Beats.Contains(StartBeat))
                {
                    Beats = BeatSubset(Beats, StartBeat);
                }

                if (BuildGraph(startNode, Beats))
                {
                    PlannerNode bestPlan = Leaves[0];
                    foreach (PlannerNode leaf in Leaves)
                    {
                        if (leaf.Cost < bestPlan.Cost)
                        {
                            bestPlan = leaf;
                        }
                    }

                    NarrativePlan = new Plan(bestPlan, TargetBeat, Archetype);
                }
            }
Example #3
0
 public PlannerNode(PlannerNode parent, float runningCost, HashSet <KeyValuePair <string, object> > state, GOAPAction action)
 {
     Parent      = parent;
     RunningCost = runningCost;
     _state      = state;
     Action      = action;
 }
Example #4
0
    private Path GeneratePath()
    {
        PlannerNode node = m_nodes[m_goal.Id];

        if (node == null)
        {
            return(null);
        }

        Path         path = new Path(node.G);
        List <INode> list = new List <INode>()
        {
            node.OriginNode
        };

        while (node.Parent != null)
        {
            node = node.Parent;
            list.Add(node.OriginNode);

            if (node.OriginNode.Id == m_start.Id)
            {
                break;
            }
        }

        list.Reverse();

        path.Nodes = list;
        return(path);
    }
Example #5
0
            private bool BuildGraph(PlannerNode parent, List <Beat> availableActions)
            {
                bool foundSolution = false;

                foreach (Beat beat in availableActions)
                {
                    if (parent.State.IsInState(beat.Preconditions))
                    {
                        PlannerNode node = new PlannerNode(parent, ApplyBeatToWorldState(parent.State, beat), beat);

                        if (node.State.IsInState(TargetBeat.Preconditions))
                        {
                            Leaves.Add(node);
                            foundSolution = true;
                        }
                        else
                        {
                            if (BuildGraph(node, BeatSubset(availableActions, beat)))
                            {
                                foundSolution = true;
                            }
                        }
                    }
                }

                return(foundSolution);
            }
Example #6
0
            private bool BuildGraph(PlannerNode parent, HashSet <PlannerNode> leaves, HashSet <GOAPAction> usableActions, HashSet <KeyValuePair <string, object> > goal)
            {
                bool foundOne = false;

                //  go through each action available at this node and see if we can use it here
                foreach (GOAPAction action in usableActions)
                {
                    //  if the parent state has conditions for this action's preconditions, use it here
                    if (InState(action.Preconditions, parent._state))
                    {
                        //  apply action's effects to parent state
                        HashSet <KeyValuePair <string, object> > currentState = PopulateState(parent._state, action.Effects);
                        PlannerNode node = new PlannerNode(parent, parent.RunningCost + action.Cost, currentState, action);

                        if (InState(goal, currentState))
                        {
                            //  found solution!
                            leaves.Add(node);
                            foundOne = true;
                        }
                        else
                        {
                            //  not at a solution yet, so test all remaining actions and branch out the tree
                            HashSet <GOAPAction> subset = ActionSubset(usableActions, action);
                            bool found = BuildGraph(node, leaves, subset, goal);
                            if (found)
                            {
                                foundOne = true;
                            }
                        }
                    }
                }

                return(foundOne);
            }
Example #7
0
        public static Stack <BaseAction> ConstructActionPlan(Actor actor, Goal goal, List <BaseAction> performableActions)
        {
            List <PlannerNode> treeGraph = new List <PlannerNode>();

            PlannerNode start = new PlannerNode()
            {
                RunningData = actor.Data
            };

            bool success = BuildGraph(start, treeGraph, goal, performableActions);

            if (!success)
            {
                //  Plan was not created -- sad.
                UnityEngine.Debug.Log("Plan failed");
                return(new Stack <BaseAction>());
            }

            PlannerNode cheapest = null;

            foreach (var rootNode in treeGraph)
            {
                if (cheapest == null)
                {
                    cheapest = rootNode;
                }
                else
                {
                    if (rootNode.RunningCost < cheapest.RunningCost)
                    {
                        cheapest = rootNode;
                    }
                }
            }

            //  Get the cheapest node and work back through parents to construct action plan
            var         actionPlan = new Stack <BaseAction>();
            PlannerNode n          = cheapest;

            while (n != null)
            {
                if (n.Action != null)
                {
                    actionPlan.Push(n.Action);
                }
                n = n.Parent;
            }

            //Debug
            var debugString = "I made a plan! ";

            foreach (var action in actionPlan)
            {
                debugString += action.name + " - ";
            }
            UnityEngine.Debug.Log(debugString);

            return(actionPlan);
        }
Example #8
0
    IEnumerator ProcessList(SearchNode _start, SearchNode _goal)
    {
        // Prioritize the tile with the lowest cost
        int         lowestIndex = getLowestFinal(stepOpen);
        PlannerNode current     = stepOpen[lowestIndex];

        // Remove it from the stepOpen list
        stepOpen.Remove(stepOpen[lowestIndex]);
        // If this is where we want to be
        if (current.vertex == _goal)
        {
            while (current.parent != null)
            {
                // Add every node along this path to the list
                path.Add(current.vertex.t);
                yield return(new WaitForSeconds(1));

                current.vertex.t.setTemporaryColor(Color.yellow);
                current = current.parent;
            }
            // Return the list
            yield return("success");
        }
        // If this isn't the goal, get its neighbors
        foreach (Edge e in current.vertex.edges)
        {
            SearchNode successor = e.node;
            // Calculate cost
            float tempGiven = current.givenCost + e.cost;
            // If we've been here before
            if (stepVisited.ContainsKey(successor))
            {
                // If this previously stepVisited tile is now a better choice based on our current path
                if (tempGiven < stepVisited[successor].givenCost)
                {
                    // Remove the old reference, update costs, and return to the list with new priority.
                    PlannerNode successorNode = new PlannerNode(successor);
                    stepOpen.Remove(successorNode);
                    successorNode.givenCost = tempGiven;
                    successorNode.finalCost = successorNode.givenCost + successorNode.heuristicCost * heuristicWeight;
                    successorNode.parent    = current;
                    stepOpen.Add(successorNode);
                }
            }
            else
            {
                // If we haven't been here before, add it to the stepVisited list
                PlannerNode successorNode = new PlannerNode(successor);
                successorNode.givenCost     = tempGiven;
                successorNode.heuristicCost = calculateCost(successor, _goal);
                successorNode.finalCost     = successorNode.givenCost + successorNode.heuristicCost * heuristicWeight;
                successorNode.parent        = current;
                stepVisited[successor]      = successorNode;

                stepOpen.Add(successorNode);
            }
        }
    }
Example #9
0
    public Path Search(INode start, INode goal)
    {
        m_start = start;
        m_goal  = goal;

        PlannerNode startNode = new PlannerNode(start, 0, m_map.CalcHeuristic(start, goal), NodeStatus.Open);

        m_nodes[start.Id] = startNode;
        m_open.Enqueue(startNode, startNode.F);

        while (m_open.Count > 0)
        {
            PlannerNode curtNode = m_open.Dequeue();
            if (curtNode.OriginNode.Id == m_goal.Id)
            {
                break;
            }

            curtNode.Status = NodeStatus.Close;

            List <INode> successors = m_map.GetSuccessors(curtNode.OriginNode);
            for (int i = 0; i < successors.Count; i++)
            {
                INode successor = successors[i];
                if (m_limitRect != null && !m_limitRect.Value.Contains(successor.Pos))
                {
                    continue;
                }

                PlannerNode node = m_nodes[successor.Id];
                if (node != null)
                {
                    if (node.Status != NodeStatus.Close)
                    {
                        float oldG = node.G;
                        float newG = curtNode.G + m_map.CalcHeuristic(curtNode.OriginNode, successor);
                        if (newG < node.G)
                        {
                            node.G      = newG;
                            node.Parent = curtNode;
                        }
                    }
                }
                else
                {
                    float g = curtNode.G + m_map.CalcHeuristic(curtNode.OriginNode, successor);
                    float h = m_map.CalcHeuristic(successor, m_goal);
                    node                  = new PlannerNode(successor, g, h, NodeStatus.Open);
                    node.Parent           = curtNode;
                    m_nodes[successor.Id] = node;
                    m_open.Enqueue(node, node.F);
                }
            }
        }

        return(GeneratePath());
    }
Example #10
0
        public List <PlannerNode <TKey, TValue> > GetNeighbours(PlannerNode <TKey, TValue> _baseNode)
        {
            m_NeighbourNodes.Clear();

            WorldStateModifier <TKey, TValue> basePreconditions    = _baseNode.Action?.GetPreconditions();
            WorldState <TKey, TValue>         worldStateAtBaseNode = _baseNode.GetWorldStateAtNode();
            Goal <TKey, TValue> goalWorldStateAtBaseNode           = _baseNode.GetGoalWorldStateAtNode();

            WorldState <TKey, TValue> remainingGoals = goalWorldStateAtBaseNode - worldStateAtBaseNode;

            // We implement regressive A* for GOAP by chaining action preconditions to action effects until all preconditions are fulfilled.
            // For this planner, neighbours are nodes that fulfil any of the remaining goals of the base node without conflicting with any of its preconditions.

            foreach (IAction <TKey, TValue> possibleAction in m_CurrentAgent.GetActionSet())
            {
                var effects = possibleAction.GetEffects();

                if (!effects.ContainsAny(remainingGoals))
                {
                    continue;
                }

                if (effects.ConflictsAny(basePreconditions))
                {
                    continue;
                }

                PlannerNode <TKey, TValue> plannerNode = GetAvailablePlannerNode();
                plannerNode.Init(possibleAction);

                plannerNode.CalculateWorldStateAtNode(worldStateAtBaseNode);
                plannerNode.CalculateGoalWorldStateAtNode(goalWorldStateAtBaseNode);

                bool foundInUsed = false;
                foreach (PlannerNode <TKey, TValue> usedNode in m_UsedNodes)
                {
                    if (usedNode.Equals(plannerNode))
                    {
                        plannerNode = usedNode;
                        foundInUsed = true;
                        break;
                    }
                }

                m_NeighbourNodes.Add(plannerNode);

                if (!foundInUsed)
                {
                    m_UsedNodes.Add(plannerNode);
                }
            }

            return(m_NeighbourNodes);
        }
Example #11
0
        public GoalPlanPair <TKey, TValue> GenerateGoalPlanPairForAgent(IAgent <TKey, TValue> _agent)
        {
            m_CurrentAgent = _agent;

            Stack <PlannerNode <TKey, TValue> > foundPath = null;
            bool newGoalBetterThanActiveGoal = false;

            m_GoalPlanPair.GoalInstance = null;
            m_GoalPlanPair.PlanInstance = null;

            for (var goalQueue = m_CurrentAgent.CalculateSortedGoals(); goalQueue.Count > 0;)
            {
                SortableGoal <TKey, TValue> goal = goalQueue.Dequeue();

                PlannerNode <TKey, TValue> agentNode = new PlannerNode <TKey, TValue>();
                agentNode.CalculateWorldStateAtNode(_agent.GetWorkingMemory());
                agentNode.CalculateGoalWorldStateAtNode(goal);

                foundPath = m_Pathfinder.FindPath(agentNode, null);
                if (foundPath != null && foundPath.Count > 0)
                {
                    newGoalBetterThanActiveGoal = _agent.IsGoalBetterThanActiveGoal(goal);
                    if (newGoalBetterThanActiveGoal)
                    {
                        m_GoalPlanPair.GoalInstance = goal;
#if UNITY_EDITOR
                        _agent.CreatePlanHierarchy(foundPath.Last(), m_Pathfinder.GetOpenNodes(), m_Pathfinder.GetClosedNodes());
#endif
                    }
                    break;
                }
            }

            m_GoalPlanPair.PlanInstance = new Plan <TKey, TValue>();
            if (newGoalBetterThanActiveGoal && foundPath != null)
            {
                foreach (PlannerNode <TKey, TValue> pathNode in foundPath)
                {
                    if (pathNode.Action != null)
                    {
                        m_GoalPlanPair.PlanInstance.Push(pathNode.Action);
                    }
                }
            }

            m_UsedNodes.Clear();
            RecycleUsedNodes();

            return(m_GoalPlanPair);
        }
        public static void CreateNodePairForLastOpenNode <TKey, TValue>(ref PlannerNode <TKey, TValue> _lastPlannerNode, ref List <PlannerHierarchyNodePair <TKey, TValue> > _nodePairs)
        {
            var lastHierarchyNode = new HierarchyNode <TKey, TValue>(
                _isPartOfFoundPath: true,
                _executableAction: _lastPlannerNode.Action as ExecutableAction <TKey, TValue>,
                _goalWorldStateAtNode: _lastPlannerNode.GetGoalWorldStateAtNode(),
                _worldStateAtNode: _lastPlannerNode.GetWorldStateAtNode(),
                _isFinalNode: true,
                _isClosed: false);

            _nodePairs.Add(new PlannerHierarchyNodePair <TKey, TValue>()
            {
                PlannerNodeInstance = _lastPlannerNode, HierarchyNodeInstance = lastHierarchyNode
            });
        }
Example #13
0
            public PlannerNode(PlannerNode parent, WorldState state, Beat beat)
            {
                Parent = parent;

                if (parent != null)
                {
                    Cost = parent.Cost + beat.Cost;
                }
                else
                {
                    Cost = beat.Cost;
                }

                State    = state;
                NodeBeat = beat;
            }
Example #14
0
            public Plan(PlannerNode plan, Beat TargetBeat, PlayerArchetype archetype)
            {
                Archetype = archetype;

                Beats = new List <Beat>();
                while (plan != null)
                {
                    Beats.Add(plan.NodeBeat);
                    plan = plan.Parent;
                }

                //Doesn't get added during the planning process, so add it here
                Beats.Add(TargetBeat);

                CalculateScore();
            }
Example #15
0
        public void CreatePlanHierarchy(PlannerNode <TKey, TValue> _finalPathNode, IEnumerable <PlannerNode <TKey, TValue> > _openNodes, IEnumerable <PlannerNode <TKey, TValue> > _closedNodes)
        {
            List <PlannerHierarchyNodePair <TKey, TValue> > nodePairs = new List <PlannerHierarchyNodePair <TKey, TValue> >();

            PuppeteerRuntimeHelper.CreateNodePairsForClosedNodes(_closedNodes, ref nodePairs);

            var goalNodePair = nodePairs.Find(_entry => _entry.PlannerNodeInstance.GetParent() == null);

            m_RootHierarchyNode = goalNodePair?.HierarchyNodeInstance;

            PuppeteerRuntimeHelper.CreateNodePairsForOpenNodes(_openNodes, ref nodePairs);

            PuppeteerRuntimeHelper.CreateNodePairForLastOpenNode(ref _finalPathNode, ref nodePairs);
            var lastHierarchyNode = nodePairs.Last().HierarchyNodeInstance;

            PuppeteerRuntimeHelper.ConstructHierarchy(ref nodePairs);

            PuppeteerRuntimeHelper.SetPartOfFoundPathRecursive(lastHierarchyNode);
        }
Example #16
0
        /// <summary>
        /// Based on the given parent, we construct a graph branching from it.
        /// Returns true if ANY plan was found.
        /// </summary>
        /// <param name="parent"></param>
        /// <param name="graphRef"></param>
        /// <param name="goal"></param>
        /// <param name="performableActions"></param>
        /// <returns></returns>
        private static bool BuildGraph(PlannerNode parent, List <PlannerNode> graphRef, Goal goal, List <BaseAction> performableActions)
        {
            bool planFound = false;

            foreach (var action in performableActions)
            {
                PlannerNode actualBatman = new PlannerNode(parent);

                if (IsConditionsMet(action.Conditions, actualBatman.RunningData))
                {
                    //  Apply the results of the action as if completed successfully.
                    SubjectData resultantData = CopyActionResults(actualBatman.RunningData, action.Results);
                    PlannerNode node          = new PlannerNode()
                    {
                        Parent      = actualBatman,
                        RunningCost = actualBatman.RunningCost + (int)action.Difficulty,
                        RunningData = resultantData,
                        Action      = action
                    };

                    if (IsConditionsMet(goal.DesiredConditions, resultantData))
                    {
                        //  A solution has been constructed;
                        graphRef.Add(node);
                        planFound = true;
                    }
                    else
                    {
                        //  Solution not yet found, test remaining actions
                        List <BaseAction> subsetActions = CreateActionSubset(performableActions, action);
                        planFound = BuildGraph(node, graphRef, goal, subsetActions);
                    }
                }
            }

            return(planFound);
        }
Example #17
0
    // TODO: Needs to be refactored to work only on the tiles returned by moveRange.
    void Astar(SearchNode _start, SearchNode _goal)
    {
        // Start fresh
        deselectPath();

        List <PlannerNode> open = new List <PlannerNode>();
        Dictionary <SearchNode, PlannerNode> visited = new Dictionary <SearchNode, PlannerNode>();

        // Start the list with the start node
        open.Add(new PlannerNode(_start));
        // We've been to the start node
        visited[_start] = open[0];
        // TODO: Figure out which costs are being used and how. Currently functional, but slightly blackboxed.
        visited[_start].givenCost     = 0;
        visited[_start].heuristicCost = calculateCost(_start, _goal);
        visited[_start].finalCost     = visited[_start].givenCost + visited[_start].heuristicCost * heuristicWeight;

        // While there are tiles left to explore
        while (open.Count != 0)
        {
            // Prioritize the tile with the lowest cost
            int         lowestIndex = getLowestFinal(open);
            PlannerNode current     = open[lowestIndex];
            // Remove it from the open list
            open.Remove(open[lowestIndex]);
            // If this is where we want to be
            if (current.vertex == _goal)
            {
                while (current.parent != null)
                {
                    // Add every node along this path to the list
                    path.Add(current.vertex.t);
                    current = current.parent;
                }
                // Return the list
                return;
            }
            // If this isn't the goal, get its neighbors
            foreach (Edge e in current.vertex.edges)
            {
                SearchNode successor = e.node;
                // Calculate cost
                float tempGiven = current.givenCost + e.cost;
                // If we've been here before
                if (visited.ContainsKey(successor))
                {
                    // If this previously visited tile is now a better choice based on our current path
                    if (tempGiven < visited[successor].givenCost)
                    {
                        // Remove the old reference, update costs, and return to the list with new priority.
                        PlannerNode successorNode = new PlannerNode(successor);
                        open.Remove(successorNode);
                        successorNode.givenCost = tempGiven;
                        successorNode.finalCost = successorNode.givenCost + successorNode.heuristicCost * heuristicWeight;
                        successorNode.parent    = current;
                        open.Add(successorNode);
                    }
                }
                else
                {
                    // If we haven't been here before, add it to the visited list
                    PlannerNode successorNode = new PlannerNode(successor);
                    successorNode.givenCost     = tempGiven;
                    successorNode.heuristicCost = calculateCost(successor, _goal);
                    successorNode.finalCost     = successorNode.givenCost + successorNode.heuristicCost * heuristicWeight;
                    successorNode.parent        = current;
                    visited[successor]          = successorNode;

                    open.Add(successorNode);
                }
            }
        }
        // The list is empty, return from procedure.
        return;
    }
Example #18
0
            public Queue <GOAPAction> Plan(GameObject agent, HashSet <GOAPAction> availableActions, HashSet <KeyValuePair <string, object> > worldState, HashSet <KeyValuePair <string, object> > goal)
            {
                foreach (GOAPAction a in availableActions)
                {
                    a.DoReset();
                }

                //  check which actions can run
                var usableActions = new HashSet <GOAPAction>();

                foreach (GOAPAction a in availableActions)
                {
                    if (a.CheckProceduralPrecondition(agent))
                    {
                        usableActions.Add(a);
                    }
                }

                //  we now have all actions that can run, stored in usableActions

                //  build tree and record leaf nodes that provide solution to goal
                HashSet <PlannerNode> leaves = new HashSet <PlannerNode>();

                //  build tree
                PlannerNode start   = new PlannerNode(null, 0, worldState, null);
                bool        success = BuildGraph(start, leaves, usableActions, goal);

                if (!success)
                {
                    //  no plan created
                    return(null);
                }

                //  get cheapest leaf
                PlannerNode cheapest = null;

                foreach (PlannerNode l in leaves)
                {
                    if (cheapest == null)
                    {
                        cheapest = l;
                    }
                    else
                    {
                        if (l.RunningCost < cheapest.RunningCost)
                        {
                            cheapest = l;
                        }
                    }
                }

                //  get its node and work back through parents
                List <GOAPAction> result = new List <GOAPAction>();
                PlannerNode       n      = cheapest;

                while (n != null)
                {
                    if (n.Action != null)
                    {
                        //  slide action in the front
                        result.Insert(0, n.Action);
                    }
                    n = n.Parent;
                }
                //  we now have this action HashSet in correct order
                Queue <GOAPAction> queue = new Queue <GOAPAction>();

                foreach (GOAPAction a in result)
                {
                    queue.Enqueue(a);
                }

                return(queue);
            }
Example #19
0
 public float GetDistance(PlannerNode <TKey, TValue> _base, PlannerNode <TKey, TValue> _end)
 {
     /// GetNeighbours for this planner already filters out all the nodes that
     /// don't get us closer to the end so we simply return the heuristic cost of the node
     return(_base.GetHeuristicCost());
 }