public void AddPreconditions(WorldGoal preconditions, bool returnPreconditions = true) { foreach (var stateful in preconditions.Keys) { if (!ContainsKey(stateful)) { Add(stateful, new Goal()); } foreach (var goalString in preconditions[stateful].Keys) { if (this[stateful].ContainsKey(goalString)) { this[stateful][goalString] = preconditions[stateful][goalString].Refine(this[stateful][goalString]); } else { this[stateful].Add(goalString, preconditions[stateful][goalString]); } } } if (returnPreconditions) { preconditions.ReturnSelf(); } }
public void Init(Node parent, float runningCost, WorldGoal goal, GoapAction action, IStateful target) { this.parent = parent; this.runningCost = runningCost; this.goal = goal; this.action.Init(target, action); }
/// <summary> /// A* forward search for a plan that satisfies the given goal. /// </summary> /// <returns>Returns null if a plan could not be found, or a list of the /// actions that must be performed, in order.</returns> public static Queue <ITransition> Plan( GoapAgent agent, WorldGoal goal) { var worldState = WorldState.Borrow(); worldState[agent] = agent.GetState(); var regressiveSearchGoal = RegressiveSearchWorldGoal.Borrow(goal); DebugUtils.Assert(worldState[agent].ContainsKey("x") && worldState[agent].ContainsKey("y") && worldState[agent].ContainsKey("z"), "Agent's state must contain his position as 'x' and 'y' keys"); var path = AStarSearch.Search(agent, regressiveSearchGoal, worldState, true); worldState.ReturnSelf(); GoapAction.WithContext.ReportLeaks(); State.ReportLeaks(); WorldState.ReportLeaks(); WorldGoal.ReportLeaks(); RegressiveSearchWorldGoal.ReportLeaks(); WorldEffects.ReportLeaks(); return(path); }
public WorldGoal(WorldGoal other) : base() { foreach (KeyValuePair <IStateful, Goal> kvp in other) { Goal goalCopy = new Goal(kvp.Value); // For deep copy this.Add(kvp.Key, goalCopy); } }
/// <summary> /// Returns a WorldGoal that contains all the preconditions that the target /// of the action must satisfy. /// </summary> public virtual WorldGoal GetDependentPreconditions(IStateful agent, IStateful target) { var worldPreconditions = WorldGoal.Borrow(); if (targetPreconditions.Count > 0) { worldPreconditions[target] = targetPreconditions; } return(worldPreconditions); }
/// <summary> /// Returns a WorldGoal that contains all the preconditions that the agent /// must satisfy. /// </summary> public virtual WorldGoal GetIndependentPreconditions(IStateful agent) { var worldPreconditions = WorldGoal.Borrow(); if (preconditions.Count > 0) { worldPreconditions[agent] = preconditions; } return(worldPreconditions); }
public static RegressiveSearchWorldGoal Borrow(WorldGoal parent) { var obj = Borrow(); foreach (var item in parent) { obj[item.Key] = item.Value; } return(obj); }
public float CalculateHeuristicCost(WorldGoal goal, bool useCachedValue = true) { if (useCachedValue && cachedHeuristicCost >= 0f) { return(cachedHeuristicCost); } cachedHeuristicCost = 0f; // TODO: Calculate heuristic for A*. return(cachedHeuristicCost); }
public static string PrettyPrint(WorldGoal state) { var s = new StringBuilder(); foreach (var kvp in state) { var target = kvp.Key as Component; s.Append(target.name).Append(": ").Append(PrettyPrint(kvp.Value)).Append('\n'); } return(s.ToString()); }
/// <summary> /// Check that all items in 'test' are in 'state'. If just one does not /// match or is not there then this returns false. /// </summary> public static bool DoConditionsApplyToWorld(WorldGoal test, WorldState state) { foreach (var targetGoal in test) { if (!state.ContainsKey(targetGoal.Key)) { state [targetGoal.Key] = targetGoal.Key.GetState(); } var targetState = state [targetGoal.Key]; if (!DoConditionsApply(targetGoal.Value, targetState)) { return(false); } } return(true); }
// Create possible previous goal (before this actionwas made) public WorldGoal reverseApplyToWorldGoal(WorldGoal goal) { WorldGoal newGoal = new WorldGoal(goal); //this is deep copied, see c'tor foreach (KeyValuePair <IStateful, Goal> agentGoal in goal) { GoapAgent currAgent = (GoapAgent)agentGoal.Key; Goal currGoal = agentGoal.Value; Goal updatedGoal = this.effects.reverseApplyEffectsToGoal(currGoal); List <string> keys = new List <string> (updatedGoal.Keys); foreach (string k in keys) { if (updatedGoal [k] == null) { updatedGoal.Remove(k); } } if (newGoal.ContainsKey(currAgent)) { newGoal [currAgent] = updatedGoal; } else { newGoal.Add(currAgent, updatedGoal); } // Add target preconditions to new goal foreach (KeyValuePair <string, Condition> kvp in this.preconditions) { if (!newGoal [currAgent].ContainsKey(kvp.Key)) { newGoal [currAgent].Add(kvp.Key, new Condition(kvp.Value.comparison, kvp.Value.value)); } } } return(newGoal); }
/// <summary> /// A plan was found for the given goal. /// The plan is a queue of actions that should be performed in order to /// fulfill the goal. /// </summary> public abstract void PlanFound(WorldGoal goal, Queue <ITransition> actions);
/// <summary> /// No sequence of actions could be found for the supplied goal. /// Can be used to select another goal for next time. /// </summary> public abstract void PlanFailed(WorldGoal failedGoal);
public bool isGoalCloser(WorldGoal currentGoal, WorldGoal possibleGoal) { bool res = false; foreach (KeyValuePair <IStateful, Goal> agentGoal in possibleGoal) { Goal possible = agentGoal.Value; // TODO: what if possible goal doesnt contain this person if (!currentGoal.ContainsKey(agentGoal.Key)) { continue; } else { Goal current = currentGoal [agentGoal.Key]; //go through parent node's conditions foreach (KeyValuePair <string, Condition> kvp in current) { // If initial state without this parameter, irrelevant and continue if (this.ContainsKey(kvp.Key)) { // If child node doesnt contain this goal, it is satisfied! if (!possible.ContainsKey(kvp.Key)) { res = true; } // Else - check if child goal is closer to inital state else { StateValue sv = this [kvp.Key]; Condition currCond = kvp.Value; Condition possCond = possible [kvp.Key]; //if int check if new closer to wanted if (sv.value.GetType() == typeof(int)) { if (sv.CheckCondition(currCond) && sv.CheckCondition(possCond)) { continue; } if (sv.CheckCondition(currCond) && !sv.CheckCondition(possCond)) { return(false); } if (!sv.CheckCondition(currCond) && sv.CheckCondition(possCond)) { res = true; continue; } //now both conditions dont hold, check if possCond improves //assume both goals have same compare type switch (currCond.comparison) { case CompareType.Equal: res = (Mathf.Abs((int)sv.value - (int)currCond.value)) < (Mathf.Abs((int)sv.value - (int)possCond.value)); break; case CompareType.LessThan: res = ((int)possCond.value - (int)sv.value) > ((int)currCond.value - (int)sv.value); break; case CompareType.LessThanOrEqual: res = ((int)possCond.value - (int)sv.value) > ((int)currCond.value - (int)sv.value); break; case CompareType.MoreThan: res = ((int)possCond.value - (int)sv.value) < ((int)currCond.value - (int)sv.value); break; case CompareType.MoreThanOrEqual: res = ((int)possCond.value - (int)sv.value) < ((int)currCond.value - (int)sv.value); break; case CompareType.NotEqual: res = (Mathf.Abs((int)sv.value - (int)currCond.value)) > (Mathf.Abs((int)sv.value - (int)possCond.value)); break; } //if bool check if new matches while old doesnt } else if (sv.value.GetType() == typeof(bool)) { //assuming booleans will only get ModificationType.Set res = (sv.value != currCond.value && sv.value == possCond.value); } //if new cond worse - return false if (res == false) { //Debug.Log ("this Goal isnt any better! abort!"); return(false); } } } } } } if (res == false) { //Debug.Log ("this Goal isnt any better! abort!"); } else { //Debug.Log ("this Goal is better!"); } return(res); }
/// <summary> /// A plan was found for the given goal. /// The plan is a queue of actions that should be performed in order to /// fulfill the goal. /// </summary> public abstract void PlanFound(WorldGoal goal, Queue <GoapAction.WithContext> actions);
/// <summary> /// A* forward search for a plan that satisfies the given goal. /// </summary> /// <returns>Returns null if a plan could not be found, or a list of the /// actions that must be performed, in order.</returns> public static Queue <GoapAction.WithContext> Plan( GoapAgent agent, List <GoapAction> availableActions, WorldGoal goal) { var exploredNodes = new Dictionary <WorldState, Node> (WorldStateComparer.instance); var closedSet = new HashSet <WorldState> (WorldStateComparer.instance); var openSet = new FastPriorityQueue <Node> (MAX_FRINGE_NODES); var currentNode = Node.pool.Borrow(); currentNode.Init(null, 0f, goal, null, null); // currentNode.position = Vector2.zero; currentNode.position = (agent as Component).transform.position; openSet.Enqueue(currentNode, 0f); int iterations = 0; while (openSet.Count > 0 && iterations < MAX_FRINGE_NODES - 10) { iterations++; currentNode = openSet.Dequeue(); //TODO: delete print //Debug.Log ("current world goal: " + GoapAgent.PrettyPrint(currentNode.goal)); if (DoConditionsApply(currentNode.goal[agent], agent.GetState())) { DebugUtils.Log("Selected plan with cost: " + currentNode.Score); var plan = UnwrapPlan(currentNode); //DebugUtils.Log("the plan: " + GoapAgent.PrettyPrint(plan)); // Return all nodes. Node.pool.ReturnAll(); // Check for leaks in the pools: //DebugUtils.LogError("Nodes: " + Node.pool.Count); //DebugUtils.LogError("WithContext: " + GoapAction.WithContext.pool.Count); //DebugUtils.LogError("WorldState: " + WorldState.pool.Count); return(plan); } foreach (GoapAction action in availableActions) { //TODO: delete print //Debug.Log("considering " + action.name); WorldGoal possibleChildGoal = action.reverseApplyToWorldGoal(currentNode.goal); //Debug.Log ("new goal will be: " + GoapAgent.PrettyPrint(possibleChildGoal)); if (agent.GetState().isGoalCloser(currentNode.goal, possibleChildGoal)) { List <IStateful> targets = action.GetAllTargets(agent); // No targets, move to next action if (targets.Count == 0) { continue; } float minCost = 99999f; float tempCost = 0f; IStateful closestTarget = null; Vector2 newPosition = currentNode.position; foreach (var target in targets) { //DebugUtils.Log ("targets..."); //TODO: check target preconds, make sure this works if (goal.ContainsKey(target)) { if (!DoConditionsApply(goal [target], target.GetPerceivedState())) { continue; } } if (action.RequiresInRange()) { tempCost = action.CalculateCost(currentNode.position, target); if (tempCost < minCost) { minCost = tempCost; closestTarget = target; newPosition = (target as Component).transform.position; DebugUtils.Log("minCost: " + minCost); DebugUtils.Log("closestTarget: " + closestTarget); } //DebugUtils.Log ("calculating tempCost"); } else { closestTarget = target; tempCost = 9999; DebugUtils.Log("+++ closestTarget: " + closestTarget); break; } } float cost = currentNode.runningCost + action.workDuration + tempCost; Node newChiledNode = Node.pool.Borrow(); DebugUtils.Log("*** closestTarget: " + closestTarget); newChiledNode.Init(currentNode, cost, possibleChildGoal, action, closestTarget); newChiledNode.position = newPosition; openSet.Enqueue(newChiledNode, newChiledNode.runningCost); } //TODO: delete 'else' scope else { //DebugUtils.Log (action.name + " doesnt improve goal"); } } } //TODO: return plan failed #yoel return(null); }