public async Task RunActionsAsync(CancellationToken token = default) { while (!token.IsCancellationRequested) { CurrentAction = null; var state = GetWorldState(); if (_actionQueue.Count == 0) { _logger.Trace("ActionQueue of agent is empty. Replanning."); state = await ReplanAsync(state, token); CurrentState = state; } var action = _actionQueue.Dequeue(); if (action.HasUnsatisfiedPreconditions(state)) { OnActionHasUnsatisfiedPreconditions(action, state); continue; } if (action is IAsyncExecutableAction executableAction) { await ExecuteAction(executableAction, state, token); } } _logger.Trace("Quitting, because cancellation was requested"); }
private static bool TryApplyEffects(IDomainAction action, DomainState goalState, out DomainState newState) { newState = goalState; foreach (var pair in action.Effects) { var worldVar = pair.Key; // Preconditions aren't violated, so we just ignore this if (!goalState.TryGet(worldVar, out object value)) { continue; } // If any effect clashes with the goal state, the plan node is invalid if (!Equals(value, pair.Value)) { return(false); } // If the goal is fulfilled, we can remove it from the search newState = newState.Remove(worldVar); } return(true); }
public PlanNode(DomainState state, IDomainAction selectedAction, IPlanNode parent, float estimate) { State = state ?? throw new ArgumentNullException(nameof(state)); SelectedAction = selectedAction; Parent = parent; Estimate = estimate; RunningCost = (parent?.RunningCost ?? 0) + (selectedAction?.GetCost(parent?.State) ?? 0); Level = (parent?.Level ?? -1) + 1; }
protected virtual void OnActionHasUnsatisfiedPreconditions(IDomainAction action, DomainState state) { var unsatisfiedConditions = action.Preconditions .Where(cond => !state.Fulfills(cond.Key, cond.Value)) .Select(cond => $"({cond.Key}, {cond.Value} != {state.GetValueOrDefault<object>(cond.Key)})"); var conditionString = string.Join(", ", unsatisfiedConditions); _logger.Warn("Action `{0}` has unsatisfied preconditions [{1}]. Flushing ActionQueue.", action.ActionName, conditionString); _actionQueue.Clear(); }
private async Task ExecuteAction(IAsyncExecutableAction action, DomainState currentState, CancellationToken token) { OnActionStarting(action); CurrentAction = action; try { var actionSucceeded = await action.ExecuteAsync(currentState, token); if (actionSucceeded) { OnActionCompleted(action); } else { OnActionFailed(action); } } catch (OperationCanceledException) { CurrentAction = null; } }
public void AddAction(IDomainAction action) { _actions.Add(action); }
protected virtual void OnActionFailed(IDomainAction action) { _logger.Debug("Execution of action `{0}` failed. Flushing ActionQueue.", action.ActionName); _actionQueue.Clear(); }
protected virtual void OnActionCompleted(IDomainAction action) { _logger.Trace("Execution of action `{0}` was successful.", action.ActionName); CurrentState = CurrentState.Apply(action.Effects); }
protected virtual void OnActionStarting(IDomainAction action) { _logger.Trace("Executing action `{0}`", action.ActionName); }
public static bool HasUnsatisfiedPreconditions(this IDomainAction action, DomainState state) { return(!action.Preconditions.All(pair => state.Fulfills(pair.Key, pair.Value))); }