コード例 #1
0
ファイル: GoapNode.cs プロジェクト: Hengle/GameDemo
 public GoapNode(GoapNode parent, GoapAction action, GoapStatus status, float cost)
 {
     parentNode    = parent;
     goapAction    = action;
     currentStatus = status;
     this.cost     = cost;
 }
コード例 #2
0
    public List <GoapAction> Plan(Func <string, List <GoapAction> > actionPool, WorldState fromState, WorldState toState)
    {
        GoapNode start = new GoapNode(actionPool, null, fromState, this.npcType);
        GoapNode goal  = new GoapNode(actionPool, null, toState, this.npcType);

        return(astar.GetPath(start, goal, GoapHeuristic, GoapCost).Select(goapNode => goapNode.data as GoapAction).ToList());
    }
コード例 #3
0
 private void Clear()
 {
     this.parent      = null;
     this.runningCost = 0;
     this.state       = null;
     this.action      = null;
 }
コード例 #4
0
ファイル: GoapPlanner.cs プロジェクト: s1lin/CS521_A3
 public GoapNode(GoapNode parent, float runningCost, List <KeyValuePair <string, object> > state, GoapAction action)
 {
     this.parent      = parent;
     this.runningCost = runningCost;
     this.state       = state;
     this.action      = action;
 }
コード例 #5
0
 public GoapNode(GoapNode parent, float runningCost, Dictionary <string, object> state, GoapAction action)
 {
     this.parent      = parent;
     this.runningCost = runningCost;
     this.state       = state;
     this.action      = action;
 }
コード例 #6
0
    private static int GoapHeuristic(AStarNode <GoapAction> a, AStarNode <GoapAction> b)
    {
        GoapNode aGoap = (GoapNode)a;
        GoapNode bGoap = (GoapNode)b;

        return(aGoap.worldState.Diff(bGoap.worldState));
    }
コード例 #7
0
 public void ReInit(GoapNode parent, float runningCost, Dictionary <string, object> state,
                    GoapAction action)
 {
     Clear();
     this.parent      = parent;
     this.runningCost = runningCost;
     this.state       = state;
     this.action      = action;
 }
コード例 #8
0
 public GoapNode(
     GoapNode parent,
     float runningCost,
     Dictionary <string, object> state,
     GoapAction action)
 {
     Parent      = parent;
     RunningCost = runningCost;
     State       = state;
     Action      = action;
 }
コード例 #9
0
ファイル: GoapPlanner.cs プロジェクト: s1lin/CS521_A3
    private bool BuildGOAP(GoapNode parent, List <GoapNode> graph, List <GoapAction> usableActions, KeyValuePair <string, object> goal, int iteration)
    {
        List <KeyValuePair <string, object> > currentState;


        foreach (GoapAction action in usableActions)
        {
            if (IsStateSatisfied(action.preconditions, parent.state))
            {
                if (action.GetType().Name.Equals("InventoryToCar"))
                {
                    currentState = ApplyStateChange(parent.state);
                }
                else if (action.GetType().Name.Equals("CarToInventory"))
                {
                    currentState = ApplyStateChange(parent.state, goal, action);
                }
                else
                {
                    currentState = ApplyStateChange(parent.state, action.effects);
                }

                GoapNode node = new GoapNode(parent, parent.runningCost + action.cost, currentState, action);
                graph.Add(node);

                if (IsStateSatisfied(goal, currentState))
                {
                    return(true);
                }
                else
                {
                    if (iteration >= 20)
                    {
                        iteration = 10;
                        continue;
                    }

                    List <GoapAction> subset = new List <GoapAction>();
                    subset.AddRange(FindUsableActions(currentState, usableActions, goal, parent.runningCost + action.cost));
                    bool succ = BuildGOAP(node, graph, subset, goal, ++iteration);
                    if (!succ)
                    {
                        continue;
                    }
                    else
                    {
                        return(true);
                    }
                }
            }
        }
        return(false);
    }
コード例 #10
0
ファイル: GoapPlanner.cs プロジェクト: ztw312/Unity-Script
    /**
     * Returns true if at least one solution was found.
     * The possible paths are stored in the leaves list. Each leaf has a
     * 'runningCost' value where the lowest Cost will be the best action
     * sequence.
     */

    ///<summary>
    ///如果找到至少一个解,则返回true。
    ///可能的路径存储在叶子列表中。 每个节点都有一个
    ///runningCost 值,其中最低成本将是最佳操作
    ///序列。
    ///</summary>
    private bool BuildGraph(GoapNode parent, List <GoapNode> leaves
                            , HashSet <GoapAction> usableActions, KeyValuePair <string, bool> goal)
    {
        var foundOne = false;

        // go through each action available at this node and see if we can use it here
        //浏览此节点上的每个可用操作,看看我们是否可以在此处使用它
        foreach (var action in usableActions)
        {
            // if the parent state has the conditions for this action's preconditions, we can use it here
            //如果父状态具有此操作的前置条件的条件,我们可以在此处使用它
            if (InState(action.Preconditions, parent.state))
            {
                // apply the action's effects to the parent state
                //将动作的效果应用于父状态
                var currentState = PopulateState(parent.state, action.Effects);
                //Debug.Log(GoapAgent.prettyPrint(currentState));
                var node = NodeManager.GetFreeNode(parent, parent.runningCost + action.GetCost(), parent.weight + action.GetWeight(),
                                                   currentState, action);

                //force child.precondition in parent.effects or child.precondition is empty.
                //在parent.effects中强制child.precondition或child.precondition为空。
                if (action.Preconditions.Count == 0 && parent.action != null ||
                    parent.action != null && !CondRelation(action.Preconditions, parent.action.Effects))
                {
                    continue;
                }

                if (FillGoal(goal, currentState))
                {
                    // we found a solution!
                    //我们找到了解决方案!
                    leaves.Add(node);
                    foundOne = true;
                }
                else
                {
                    // not at a solution yet, so test all the remaining actions and branch out the tree
                    //还没有解决方案,所以测试所有剩余的动作并分支出树
                    var subset = ActionSubset(usableActions, action);
                    var found  = BuildGraph(node, leaves, subset, goal);
                    if (found)
                    {
                        foundOne = true;
                    }
                }
            }
        }

        return(foundOne);
    }
コード例 #11
0
ファイル: GoapNode.cs プロジェクト: ztw312/Unity-Script
    /// <summary>
    ///     compare node
    ///     比较节点
    /// </summary>
    /// <param name="cheapest"></param>
    /// <returns></returns>
    public bool BetterThen(GoapNode rh)
    {
        //            return runningCost < rh.runningCost;
        if (weight > rh.weight && runningCost < rh.runningCost)
        {
            return(true);
        }
        if (weight < rh.weight && runningCost > rh.runningCost)
        {
            return(false);
        }
        //make weight > cost
        var better = (weight / rh.weight - 1) >= (runningCost / rh.runningCost - 1);

        return(better);
    }
コード例 #12
0
ファイル: GoapPlanner.cs プロジェクト: zzq889527/goap
    /**
     * Returns true if at least one solution was found.
     * The possible paths are stored in the leaves list. Each leaf has a
     * 'runningCost' value where the lowest Cost will be the best action
     * sequence.
     */

    private bool buildGraph(GoapNode parent, List <GoapNode> leaves
                            , HashSet <GoapAction> usableActions, KeyValuePair <string, bool> goal)
    {
        var foundOne = false;

        // go through each action available at this node and see if we can use it here
        foreach (var action in usableActions)
        {
            // if the parent state has the conditions for this action's preconditions, we can use it here
            if (inState(action.Preconditions, parent.state))
            {
                // apply the action's effects to the parent state
                var currentState = populateState(parent.state, action.Effects);
                //Debug.Log(GoapAgent.prettyPrint(currentState));
                var node = NodeManager.GetFreeNode(parent, parent.runningCost + action.GetCost(), parent.weight + action.GetWeight(),
                                                   currentState, action);

                //force child.precondition in parent.effects or child.precondition is empty.
                if (action.Preconditions.Count == 0 && parent.action != null ||
                    parent.action != null && !CondRelation(action.Preconditions, parent.action.Effects))
                {
                    continue;
                }

                if (FillGoal(goal, currentState))
                {
                    // we found a solution!
                    leaves.Add(node);
                    foundOne = true;
                }
                else
                {
                    // not at a solution yet, so test all the remaining actions and branch out the tree
                    var subset = actionSubset(usableActions, action);
                    var found  = buildGraph(node, leaves, subset, goal);
                    if (found)
                    {
                        foundOne = true;
                    }
                }
            }
        }

        return(foundOne);
    }
コード例 #13
0
    public static GoapNode GetFreeNode(GoapNode parent, float runningCost,
                                       Dictionary <string, object> state, GoapAction action)
    {
        GoapNode free = null;

        if (_freeNodes.Count <= 0)
        {
            free = new GoapNode(parent, runningCost, state, action);
        }
        else
        {
            free = _freeNodes.Pop();
            free.ReInit(parent, runningCost, state, action);
        }

        _usedNodes.Push(free);
        return(free);
    }
コード例 #14
0
    override public List <AStarNode <GoapAction> > GetNeighbours()
    {
        List <AStarNode <GoapAction> > neighbours = new List <AStarNode <GoapAction> >();

        foreach (GoapAction action in this.actionPool(npcType))
        {
            if (action.IsValid(this.worldState))
            {
                WorldState neighbourWorldState = this.worldState.ApplyAction(action);
                if (this.worldState.Diff(neighbourWorldState) > 0)
                {
                    GoapNode neighbour = new GoapNode(actionPool, action, neighbourWorldState, npcType);
                    neighbours.Add(neighbour);
                }
            }
        }

        return(neighbours);
    }
コード例 #15
0
    /**
     * Returns true if at least one solution was found.
     * The possible paths are stored in the leaves list. Each leaf has a
     * 'runningCost' value where the lowest cost will be the best action
     * sequence.
     */
    private bool BuildGraph(GoapNode parent, List <GoapNode> leaves, HashSet <GoapAction> usableActions, Dictionary <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 the conditions for this action's preconditions, we can use it here
            if (InState(action.preconditions, parent.state))
            {
                // apply the action's effects to the parent state
                Dictionary <string, object> currentState = PopulateState(parent.state, action.effects);
                //Debug.Log(GoapAgent.prettyPrint(currentState));
                GoapNode node = new GoapNode(parent, parent.runningCost + action.cost, currentState, action);

                if (InState(goal, currentState))
                {
                    // we found a solution!
                    leaves.Add(node);
                    foundOne = true;
                }
                else
                {
                    // not at a solution yet, so test all the 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);
    }
コード例 #16
0
ファイル: GoapPlanner.cs プロジェクト: s1lin/CS521_A3
    private List <GoapNode> DoPlan(List <GoapNode> leaves, List <GoapAction> actions, List <KeyValuePair <string, object> > worldState, KeyValuePair <string, object> goal)
    {
        foreach (GoapAction a in actions)
        {
            actionList.Add(a);
            a.DoReset();
        }

        Debug.Log("Start World:" + GoapAgent.Display(worldState));

        List <GoapAction> usableActions = FindUsableActions(worldState, new List <GoapAction>(), goal, 0);

        // build graph
        GoapNode start = new GoapNode(null, 0, worldState, null);

        bool success = BuildGOAP(start, leaves, usableActions, goal, 0);

        if (!success)
        {
            return(new List <GoapNode>());
        }

        return(leaves);
    }
コード例 #17
0
ファイル: GoapPlanner.cs プロジェクト: Over42/uGOAP
    /**
     * Plan what sequence of actions can fulfill the goal.
     * Returns null if a plan could not be found, or a list of the actions
     * that must be performed, in order, to fulfill the goal.
     */
    public Queue <GoapAction> Plan(GameObject agent,
                                   HashSet <GoapAction> availableActions,
                                   Dictionary <string, object> worldState,
                                   KeyValuePair <string, object> goal,
                                   IGoap goap)
    {
        // reset the actions so we can start fresh with them
        foreach (GoapAction a in availableActions)
        {
            a.DoReset();
        }

        // check what actions can run using their checkProceduralPrecondition
        HashSet <GoapAction> usableActions = NodeManager.GetFreeActionSet();

        foreach (GoapAction a in availableActions)
        {
            if (a.CheckProceduralPrecondition(agent, goap.GetMemory()))
            {
                usableActions.Add(a);
            }
        }

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

        // build up the tree and record the leaf nodes that provide a solution to the goal.
        List <GoapNode> leaves = new List <GoapNode>();

        // build graph
        GoapNode start   = NodeManager.GetFreeNode(null, 0, worldState, null);
        bool     success = BuildGraph(start, leaves, usableActions, goal);

        if (!success)
        {
            // oh no, we didn't get a plan
            Debug.Log("[" + agent.name + "] " + "NO PLAN");
            return(null);
        }

        // get the cheapest leaf
        GoapNode cheapest = null;

        foreach (GoapNode leaf in leaves)
        {
            if (cheapest == null)
            {
                cheapest = leaf;
            }
            else
            {
                if (leaf.BetterThen(cheapest))
                {
                    cheapest = leaf;
                }
            }
        }

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

        while (n != null)
        {
            if (n.action != null)
            {
                result.Insert(0, n.action); // insert the action in the front
            }
            n = n.parent;
        }
        NodeManager.Release();
        // we now have this action list in correct order

        Queue <GoapAction> queue = new Queue <GoapAction>();

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

        // Builds a shortest way for many actions
        //for (int i = 1; i < result.Count; i++)
        //{
        //    GoapAction a = result[i];
        //    a.CheckDistance(result[i-1].target, goap.GetMemory());
        //}

        // hooray we have a plan!
        return(queue);
    }
コード例 #18
0
ファイル: GoapPlanner.cs プロジェクト: zzq889527/goap
    /**
     * Plan what sequence of actions can fulfill the goal.
     * Returns null if a plan could not be found, or a list of the actions
     * that must be performed, in order, to fulfill the goal.
     */

    public Queue <GoapAction> plan(GameObject agent,
                                   HashSet <GoapAction> availableActions,
                                   Dictionary <string, bool> worldState,
                                   KeyValuePair <string, bool> goal,
                                   IGoap goap)
    {
        // reset the actions so we can start fresh with them
        foreach (var a in availableActions)
        {
            a.doReset();
        }

        // check what actions can run using their checkProceduralPrecondition
        var usableActions = NodeManager.GetFreeActionSet();

        foreach (var a in availableActions)
        {
            if (a.checkProceduralPrecondition(agent, goap.GetBlackBoard()))
            {
                usableActions.Add(a);
            }
        }

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

        // build up the tree and record the leaf nodes that provide a solution to the goal.
        var leaves = new List <GoapNode>();

        // build graph
        var start   = NodeManager.GetFreeNode(null, 0, 0, worldState, null);
        var success = buildGraph(start, leaves, usableActions, goal);

        if (!success)
        {
            // oh no, we didn't get a plan
//            Debug.Log("NO PLAN");
            return(null);
        }

        // get the cheapest leaf
        GoapNode cheapest = null;

        foreach (var leaf in leaves)
        {
            if (cheapest == null)
            {
                cheapest = leaf;
            }
            else
            {
                if (leaf.BetterThen(cheapest))
                {
                    cheapest = leaf;
                }
            }
        }

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

        while (n != null)
        {
            if (n.action != null)
            {
                result.Insert(0, n.action); // insert the action in the front
            }
            n = n.parent;
        }

        NodeManager.Release();
        // we now have this action list in correct order

        var queue = new Queue <GoapAction>();

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

        // hooray we have a plan!
        return(queue);
    }
コード例 #19
0
 // Compares the cost of 2 nodes
 public bool BetterThen(GoapNode other)
 {
     return(runningCost < other.runningCost);
 }
コード例 #20
0
    /// <summary>
    /// Creates an action plan based on a set of inital conditions
    /// and available actions
    /// </summary>
    /// <param name="initialConditions">
    /// The initial world state to use for the planning.
    /// </param>
    /// <param name="goal">
    /// The conditions that must be met at the end of the plan execution.
    /// </param>
    /// <param name="actions">
    /// The actions that are available for use in the planning.
    /// </param>
    /// <returns>
    /// A list of GoapActions ready to be performed.
    /// </returns>
    public static List <GoapAction> CreatePlan(
        Dictionary <string, object> initialConditions,
        Dictionary <string, object> goal,
        GoapAction[] actions)
    {
        // Actions which are possible given the initial conditions
        HashSet <GoapAction> usableActions = new HashSet <GoapAction>();

        // Reset all actions and get the
        // actions which are possible to
        // perform with the inital conditions
        foreach (GoapAction action in actions)
        {
            action.DoReset();

            /*
             * foreach (var precondition in action.Preconditions)
             * {
             *  if (initialConditions.ContainsKey(precondition.Key) &&
             *      initialConditions[precondition.Key]
             *          .Equals(precondition.Value))
             *  {
             *      usableActions.Add(action);
             *  }
             * }
             */
            usableActions.Add(action);
        }

        // Create a tree of possible plans.
        // Leaves represent the first action in a plan.
        List <GoapNode> leaves = new List <GoapNode>();

        // Build the planning tree.
        GoapNode start   = new GoapNode(null, 0, initialConditions, null);
        bool     success = CreatePlanningTree(start, leaves, usableActions, goal);

        if (success)
        {
            // We successfully built a planning tree, now we need to
            // find the cheapest plan
            GoapNode cheapest = null;
            foreach (GoapNode leaf in leaves)
            {
                if (cheapest == null ||
                    leaf.RunningCost < cheapest.RunningCost)
                {
                    cheapest = leaf;
                }
            }

            // Work back through the leaf's parents and reconstruct the path
            List <GoapAction> plan        = new List <GoapAction>();
            GoapNode          currentNode = cheapest;
            while (currentNode != null)
            {
                if (currentNode.Action != null)
                {
                    plan.Insert(0, currentNode.Action);
                }
                currentNode = currentNode.Parent;
            }

            return(plan);
        }
        else
        {
            // No plan
            return(null);
        }
    }
コード例 #21
0
ファイル: GoapPlanner.cs プロジェクト: ztw312/Unity-Script
    /**
     * Plan what sequence of actions can fulfill the goal.
     * Returns null if a plan could not be found, or a list of the actions
     * that must be performed, in order, to fulfill the goal.
     * 计划可以实现目标的行动顺序。
     * 如果找不到计划,或者操作列表,则返回null
     * 必须按顺序执行才能实现目标。
     */

    ///<summary>
    ///计划
    ///</summary>
    public Queue <GoapAction> Plan(GameObject agent,
                                   HashSet <GoapAction> availableActions,
                                   Dictionary <string, bool> worldState,
                                   KeyValuePair <string, bool> goal,
                                   IGoap goap)
    {
        // reset the actions so we can start fresh with them
        //重置动作,以便我们可以重新开始
        foreach (var a in availableActions)
        {
            a.doReset();
        }

        // check what actions can run using their checkProceduralPrecondition
        //使用检查程序前置条件检查可以运行的操作
        var usableActions = NodeManager.GetFreeActionSet();

        foreach (var a in availableActions)
        {
            if (a.CheckProceduralPrecondition(agent, goap.GetBlackBoard()))
            {
                usableActions.Add(a);
            }
        }

        // we now have all actions that can run, stored in usableActions
        //我们现在拥有可以运行的所有操作,存储在usefulActions中
        // build up the tree and record the leaf nodes that provide a solution to the goal.
        //构建树并记录提供目标解决方案的节点。
        var leaves = new List <GoapNode>();

        // build graph
        //构建图表
        var start = NodeManager.GetFreeNode(null, 0, 0, worldState, null);
        //构建图
        var success = BuildGraph(start, leaves, usableActions, goal);

        if (!success)
        {
            // oh no, we didn't get a plan
            //不,我们没有得到一个计划
            //            Debug.Log("NO PLAN");
            return(null);
        }

        // get the cheapest leaf
        //得到最便宜的节点
        GoapNode cheapest = null;

        foreach (var leaf in leaves)
        {
            if (cheapest == null)
            {
                cheapest = leaf;
            }
            else
            {
                if (leaf.BetterThen(cheapest))
                {
                    cheapest = leaf;
                }
            }
        }

        // get its node and work back through the parents
        //获取其节点并通过父节点返回
        var result = new List <GoapAction>();
        var n      = cheapest;

        while (n != null)
        {
            if (n.action != null)
            {
                //在前面插入动作
                result.Insert(0, n.action); // insert the action in the front
            }
            n = n.parent;
        }

        NodeManager.Release();
        // we now have this action list in correct order
        //我们现在按正确的顺序拥有此操作列表
        var queue = new Queue <GoapAction>();

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

        // hooray we have a plan!
        //万岁,我们有一个计划!
        return(queue);
    }
コード例 #22
0
    /**
     * Plan what sequence of actions can fulfill the goal.
     * Returns null if a plan could not be found, or a list of the actions
     * that must be performed, in order, to fulfill the goal.
     */
    public Queue <GoapAction> Plan(HashSet <GoapAction> availableActions,
                                   Dictionary <string, object> worldState,
                                   Dictionary <string, object> goal)
    {
        // reset the actions so we can start fresh with them
        foreach (GoapAction a in availableActions)
        {
            a.Reset();
        }

        // check what actions can run using their checkProceduralPrecondition
        HashSet <GoapAction> usableActions = new HashSet <GoapAction> ();

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

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

        // build up the tree and record the leaf nodes that provide a solution to the goal.
        List <GoapNode> leaves = new List <GoapNode> ();

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

        if (!success)
        {
            // oh no, we didn't get a plan
            return(null);
        }

        // get the cheapest leaf
        GoapNode cheapest = null;

        foreach (GoapNode leaf in leaves)
        {
            if (cheapest == null)
            {
                cheapest = leaf;
            }
            else
            {
                if (leaf.runningCost < cheapest.runningCost)
                {
                    cheapest = leaf;
                }
            }
        }

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

        while (n != null)
        {
            if (n.action != null)
            {
                result.Insert(0, n.action);                  // insert the action in the front
            }
            n = n.parent;
        }
        // we now have this action list in correct order

        Queue <GoapAction> queue = new Queue <GoapAction> ();

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

        // hooray we have a plan!
        return(queue);
    }
コード例 #23
0
 public GoapNode(GoapNode parent, float runningCost, Dictionary <string, object> state,
                 GoapAction action)
 {
     ID = MaxID++;
     ReInit(parent, runningCost, state, action);
 }
コード例 #24
0
    /// <summary>
    /// Creates a goap planning tree.
    /// </summary>
    /// <param name="parent">The node we're working down from.</param>
    /// <param name="leaves"></param>
    /// <param name="usableActions"></param>
    /// <param name="Dictionary<string"></param>
    /// <param name="goalState"></param>
    /// <returns>True if success, false otherwise.</returns>
    private static bool CreatePlanningTree(
        GoapNode parent,
        List <GoapNode> leaves,
        HashSet <GoapAction> usableActions,
        Dictionary <string, object> goalState)
    {
        bool success = false;

        // Go through each action and see if it can be used
        foreach (GoapAction action in usableActions)
        {
            if (_debugEnabled)
            {
                // Check if the action us usable given the parent's state
                if (parent.Action != null)
                {
                    Debug.Log(parent.Action.GetType().Name);
                }
                else
                {
                    Debug.Log("No parent action.");
                }
                Debug.Log("\t->" + action.GetType().Name);
            }
            bool canUseAction = true;
            foreach (var precondition in action.Preconditions)
            {
                if (_debugEnabled)
                {
                    Debug.Log("\t\t" + precondition.Key + " must be " +
                              precondition.Value);
                }
                if (parent.State.ContainsKey(precondition.Key))
                {
                    object parentValue = parent.State[precondition.Key];
                    if (!parentValue.Equals(precondition.Value))
                    {
                        canUseAction = false;
                    }
                    if (_debugEnabled)
                    {
                        Debug.Log("\t\t" + precondition.Key +
                                  " was " + parentValue);
                    }
                }
                else
                {
                    if (_debugEnabled)
                    {
                        Debug.Log(
                            "\t\t" + precondition.Key + " was not present."
                            );
                    }
                    canUseAction = false;
                }
            }

            if (_debugEnabled)
            {
                Debug.Log("\t\tCan use " + canUseAction);
            }

            if (canUseAction)
            {
                // Set current state to be
                // parent's state + the action's effects
                var currentState = new Dictionary <string, object>();
                foreach (var key in parent.State.Keys)
                {
                    currentState[key] = parent.State[key];
                }
                foreach (var effect in action.Effects)
                {
                    currentState[effect.Key] = effect.Value;
                    if (_debugEnabled)
                    {
                        Debug.Log("\t\tEffect: " + effect.Key + " " +
                                  currentState[effect.Key]);
                    }
                }

                GoapNode node = new GoapNode(
                    parent,
                    parent.RunningCost + action.Cost,
                    currentState,
                    action
                    );

                bool isDone = true;
                foreach (var goal in goalState)
                {
                    if (currentState.ContainsKey(goal.Key))
                    {
                        if (!currentState[goal.Key].Equals(goal.Value))
                        {
                            isDone = false;
                        }
                    }
                    else
                    {
                        isDone = false;
                    }
                }

                if (isDone)
                {
                    if (_debugEnabled)
                    {
                        Debug.Log("--------- Done! ---------");
                    }
                    leaves.Add(node);
                    success = true;
                }
                else
                {
                    var subsetActions = new HashSet <GoapAction>();
                    if (_debugEnabled)
                    {
                        Debug.Log("\t\t\tSubset actions");
                    }
                    foreach (var subsetAction in usableActions)
                    {
                        if (subsetAction != action)
                        {
                            subsetActions.Add(subsetAction);
                            if (_debugEnabled)
                            {
                                Debug.Log("\t\t\t\tAdded " +
                                          subsetAction.GetType().Name);
                            }
                        }
                    }
                    if (_debugEnabled)
                    {
                        foreach (var subsetAction in subsetActions)
                        {
                            Debug.Log("\t\t\t\tContains " +
                                      subsetAction.GetType().Name);
                        }
                        Debug.Log("\t\t\tCreate subset");
                    }
                    bool subsetSuccess = CreatePlanningTree(
                        node,
                        leaves,
                        subsetActions,
                        goalState
                        );
                    if (_debugEnabled)
                    {
                        Debug.Log("\t\t\t\t\t\t" + subsetSuccess);
                    }
                    if (subsetSuccess)
                    {
                        success = true;
                    }
                }
            }
        }

        return(success);
    }