private void Clear() { this.parent = null; this.runningCost = 0; this.weight = 0; this.state = null; this.resources = null; this.action = null; }
public void ReInit(GoapNode parent, float runningCost, float weight, Dictionary <string, object> state, Dictionary <Int64, Int64> resources, GoapAction action) { Clear(); this.parent = parent; this.runningCost = runningCost; this.weight = weight; this.state = state; this.resources = resources; this.action = action; }
/// <summary> /// compare node /// </summary> /// <param name="cheapest"></param> /// <returns></returns> public bool BetterThan(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; }
/** * 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, Dictionary <Int64, Int64> resourceGoal) { 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); Dictionary <Int64, Int64> currentResources = populateResource(parent.resources, action.Resources); // Console.WriteLine(GoapAgent.PrettyPrint(currentState)); GoapNode node = new GoapNode(parent, parent.runningCost + action.GetCost(), parent.weight + action.GetWeight(), currentState, currentResources, action); if (inState(goal, currentState) && inResources(resourceGoal, currentResources)) { // 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, resourceGoal); if (found) { foundOne = true; } } } } return(foundOne); }
/** * 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(object agent, HashSet <GoapAction> availableActions, Dictionary <string, object> worldState, Dictionary <Int64, Int64> resourceState, Dictionary <string, object> goal, Dictionary <Int64, Int64> resourceGoal) { // 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 = 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 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, 0, worldState, resourceState, null); bool success = buildGraph(start, leaves, usableActions, goal, resourceGoal); if (!success) { // oh no, we didn't get a plan // Console.WriteLine("NO PLAN"); return(null); } // get the cheapest leaf GoapNode cheapest = null; foreach (GoapNode leaf in leaves) { if (cheapest == null) { cheapest = leaf; } else { if (leaf.BetterThan(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; } // 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); }
public GoapNode(GoapNode parent, float runningCost, float weight, Dictionary <string, object> state, Dictionary <Int64, Int64> resources, GoapAction action) { ID = MaxID++; ReInit(parent, runningCost, weight, state, resources, action); }