private static List <Action> FindSolution(IGoap igoap, List <Action> actions, Goal goal, DebugPlanning debug) { // Create the closed/ open list and add the goal state to the latter List <Node> closedList = new List <Node>(); List <Node> openList = new List <Node>(); openList.Add(new Node(null, null, goal.succes)); DebugText(debug, DebugPlanning.Everything, "Starting state is {0}.", ConditionsToText(goal.succes)); // As long as there are nodes in the open list, we continue while (true) { Node p = GetCheapestNode(openList); if (p.action != null) { DebugText(debug, DebugPlanning.Everything, "Picked open node with action {0} from the open list.", p.action.GetType()); } // Look for each action if it gives the desired effects foreach (Action action in actions) { Action a = action.OnClone(); DebugText(debug, DebugPlanning.Basics | DebugPlanning.Everything, "Trying to add action {0} to the current state. Calling action {0}'s OnActionSetup.", a.GetType()); a.OnActionSetup(igoap, p.state); // Make sure the effects add to the state if (MatchesState(a.effects, p.state)) { // Make sure the action is actually viable if (!a.isViable) { DebugText(debug, DebugPlanning.Basics | DebugPlanning.Everything, "Action {0} could not be added because it's not viable.", a.GetType()); continue; } DebugText(debug, DebugPlanning.Basics | DebugPlanning.Everything, "Action {0} is viable, the state will now be altered with the effects and preconditions.", a.GetType()); // Add the actions preconditions List <Condition> state = AddToState(p.state, a.preconditions); DebugText(debug, DebugPlanning.Everything, "Current state after adding action {0}'s preconditions: {1}.", a.GetType(), ConditionsToText(state)); // Remove actions effects state = RemoveFromState(state, a.effects); DebugText(debug, DebugPlanning.Everything, "Current state after removing action {0}'s effects: {1}.", a.GetType(), ConditionsToText(state)); // Remove preconditions which our current state already fullfills state = RemoveFromState(state, igoap.state); DebugText(debug, DebugPlanning.Everything, "Current state after removing iGoap's state: {0}.", ConditionsToText(state)); // Create a new node Node n = new Node(p, a, state); // If the state hasn't changed, the action will be futile if (MatchesState(n.state, p.state)) { DebugText(debug, DebugPlanning.Basics | DebugPlanning.Everything, "Action {0} effects did not alter the state. Since this action is futile it will not be added.", a.GetType()); continue; } // See if we've reached the solution if (n.state.Count == 0) { closedList.Add(n); continue; } DebugText(debug, DebugPlanning.Basics | DebugPlanning.Everything, "Action {0} succesfully added to the open list. Current open list count: {1}.", a.GetType(), openList.Count); // Otherwise we add it to the open list openList.Add(n); } else { DebugText(debug, DebugPlanning.Basics | DebugPlanning.Everything, "Action {0} is not viable.", a.GetType()); } } // We're done with this node, so we remove it from the list openList.Remove(p); // Check to see if a solution has been found if (openList.Count == 0 && closedList.Count != 0) { return(NodesToActions(GetCheapestNode(closedList))); } if (openList.Count == 0) { break; } } DebugText(debug, DebugPlanning.Basics | DebugPlanning.Everything, "Ran out of viable path options for goal {0}.", goal.GetType()); return(null); }
/// <summary> /// Formulates a plan based on the given actions and goal /// </summary> /// <param name="actions">List of available actions</param> /// <param name="goals">Available goal</param> /// <param name="currentGoal">If a plan is found, this will be the current goal</param> /// <returns>If a plan was found, a list of actions. Otherwise null</returns> public static List <Action> FormulatePlan(IGoap igoap, List <Action> actions, Goal goal, out Goal currentGoal, DebugPlanning debug = DebugPlanning.None) { currentGoal = goal; if (igoap == null || actions == null || actions.Count == 0 || goal == null) { if (igoap == null) { DebugText(debug, DebugPlanning.Basics | DebugPlanning.Everything, "Can't formulate a plan because no suitable iGoap was found."); } if (actions == null || actions.Count == 0) { DebugText(debug, DebugPlanning.Basics | DebugPlanning.Everything, "Can't formulate a plan because no suitable actions for iGoap were found."); } if (goal) { DebugText(debug, DebugPlanning.Basics | DebugPlanning.Everything, "Can't formulate a plan because no suitable goal for iGoap was found."); } } DebugText(debug, DebugPlanning.Basics | DebugPlanning.Everything, "Formulating a plan for goal {0}.", goal.GetType()); goal.OnGoalSetup(); if (!goal.IsGoalRelevant()) { DebugText(debug, DebugPlanning.Basics | DebugPlanning.Everything, "Goal {0} is not relevant.", goal.GetType()); return(null); } List <Action> plan = FindSolution(igoap, actions, goal, debug); if (plan == null) { DebugText(debug, DebugPlanning.Basics | DebugPlanning.Everything, "Couldn't find a plan for goal {0}, returning null.", goal.GetType()); } else { DebugText(debug, DebugPlanning.Basics | DebugPlanning.Everything, "Found a plan for goal {0} and returning it.", goal.GetType()); } return(plan); }
public int GetGoalChange(Goal goal) { var name = goal.Name; return(_goalChanges.ContainsKey(name) ? _goalChanges[name] : 0); }
/// <summary> /// Formulates a plan based on the given actions and goals /// </summary> /// <param name="actions">List of available actions</param> /// <param name="goals">List of available goals, these will be sorted by priority</param> /// <param name="currentGoal">If a plan is found, this will be the current goal</param> /// <returns>If a plan was found, a list of actions. Otherwise null</returns> public static List <Action> FormulatePlan(IGoap igoap, List <Action> actions, List <Goal> goals, out Goal currentGoal, DebugPlanning debug = DebugPlanning.None) { currentGoal = null; if (igoap == null || actions == null || actions.Count == 0 || goals == null || goals.Count == 0) { if (igoap == null) { DebugText(debug, DebugPlanning.Basics | DebugPlanning.Everything, "Can't formulate a plan because no suitable iGoap was found."); } if (actions == null || actions.Count == 0) { DebugText(debug, DebugPlanning.Basics | DebugPlanning.Everything, "Can't formulate a plan because no suitable actions for iGoap were found."); } if (goals == null || goals.Count == 0) { DebugText(debug, DebugPlanning.Basics | DebugPlanning.Everything, "Can't formulate a plan because no suitable goals for iGoap were found."); } return(null); } foreach (Goal goal in goals.OrderByDescending(g => g.priority).ToList()) { List <Action> plan = FormulatePlan(igoap, actions, goal, out currentGoal, debug); if (plan != null) { return(plan); } } return(null); }
/// <summary> /// IDA* iteration /// </summary> /// <param name="worldModel"></param> /// <param name="goal"></param> /// <param name="transpositionTable"></param> /// <param name="maxDepth"></param> /// <returns></returns> static List <Action> doDepthFirst(WorldModel worldModel, Goal goal, TranspositionTable transpositionTable, int maxDepth) { //storage for models at each depth ans corresponding actions and their cost WorldModel[] models = new WorldModel[maxDepth + 1]; Action[] actions = new Action[maxDepth]; float[] costs = new float[maxDepth]; //initialize models[0] = worldModel.copy(); int curDepth = 0; //keep track of minimal cutoff for optimization int smallestCutoff = int.MaxValue; //iterate until there's no more possibilities at depth 0 while (curDepth >= 0) { if (curDepth == 0) { smallestCutoff = int.MaxValue; } //check wether goal is reached if (goal.isFulfilled(models[curDepth])) { List <Action> ret = new List <Action>(); for (int i = 0; i < actions.Length; ++i) { if (actions[i] == null) { break; } ret.Add(actions[i]); } return(ret); //return current plan } //if maximum depth is reached if (curDepth >= maxDepth) { //continue in lower depth --curDepth; continue; } //calculate total cost of current plan float cost = models[curDepth].estimateHeuristic(goal) + costs[curDepth]; //check if we need to prune based on cost if (cost > cutoff) { // if (cutoff < smallestCutoff) { smallestCutoff = cutoff; } //drop back --curDepth; continue; } //otherwise try the next action Action nextAction = models[curDepth].nextAction(); if (nextAction != null) { //copy current model models[curDepth + 1] = models[curDepth].copy(); //apply action actions[curDepth] = nextAction; models[curDepth + 1].applyAction(nextAction); costs[curDepth + 1] = costs[curDepth] + nextAction.cost; if (!transpositionTable.has(models[curDepth + 1])) { ++curDepth; transpositionTable.add(models[curDepth], curDepth - 1); } else { transpositionTable.add(models[curDepth + 1], curDepth); } } else { --curDepth; } } cutoff = smallestCutoff; return(null); }