Skip to content

Commit

Permalink
feat: add generic parameter TBeliefSet to aplib components (#31)
Browse files Browse the repository at this point in the history
* feat: add IAction and ITactic

* feat: refactor aplib to use generic TBeliefSet

* fix: change local variable type to generic type

* refactor: use System.Collections.Generic using directive

* chore: remove parameterless constructors

* test: use moq for more tests

* refactor: put where keyword on new line and change summary to remark

* fix: improve mocking in tests
  • Loading branch information
JensSteenmetz authored Apr 3, 2024
1 parent b4571e5 commit e421288
Show file tree
Hide file tree
Showing 31 changed files with 456 additions and 453 deletions.
11 changes: 5 additions & 6 deletions Aplib.Core/BdiAgent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,16 +51,15 @@ public void Update()

// Desire
_desireSet.UpdateStatus(_beliefSet);
if (Status != CompletionStatus.Unfinished)
return;
IGoal goal = _desireSet.GetCurrentGoal(_beliefSet);
if (Status != CompletionStatus.Unfinished) return;
IGoal<TBeliefSet> goal = _desireSet.GetCurrentGoal(_beliefSet);

// Intent
Tactic tactic = goal.Tactic;
Action? action = tactic.GetAction();
ITactic<TBeliefSet> tactic = goal.Tactic;
IAction<TBeliefSet>? action = tactic.GetAction(_beliefSet);

// Execute the action
action?.Execute();
action?.Execute(_beliefSet);
}
}
}
4 changes: 2 additions & 2 deletions Aplib.Core/Desire/DesireSet.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@ public class DesireSet<TBeliefSet> : IDesireSet<TBeliefSet>
/// Initializes a new instance of the <see cref="DesireSet{TBeliefSet}" /> class.
/// </summary>
/// <param name="mainGoal">The main goal structure that the agent needs to complete.</param>
public DesireSet(IGoalStructure<TBeliefSet> mainGoal)
public DesireSet(IGoalStructure<TBeliefSet> mainGoal)
=> _mainGoal = mainGoal;

/// <inheritdoc />
public IGoal GetCurrentGoal(TBeliefSet beliefSet)
public IGoal<TBeliefSet> GetCurrentGoal(TBeliefSet beliefSet)
=> _mainGoal.GetCurrentGoal(beliefSet);

/// <inheritdoc />
Expand Down
6 changes: 3 additions & 3 deletions Aplib.Core/Desire/FirstOfGoalStructure.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,15 @@ public class FirstOfGoalStructure<TBeliefSet> : GoalStructure<TBeliefSet>, IDisp
/// Initializes a new instance of the <see cref="FirstOfGoalStructure{TBeliefSet}" /> class.
/// </summary>
/// <param name="children">The children of the goal structure.</param>
public FirstOfGoalStructure(IList<IGoalStructure<TBeliefSet>> children) : base(children)
public FirstOfGoalStructure(params IGoalStructure<TBeliefSet>[] children) : base(children)
{
_childrenEnumerator = children.GetEnumerator();
_childrenEnumerator = _children.GetEnumerator();
_childrenEnumerator.MoveNext();
_currentGoalStructure = _childrenEnumerator.Current;
}

/// <inheritdoc />
public override IGoal GetCurrentGoal(TBeliefSet beliefSet) => _currentGoalStructure!.GetCurrentGoal(beliefSet);
public override IGoal<TBeliefSet> GetCurrentGoal(TBeliefSet beliefSet) => _currentGoalStructure!.GetCurrentGoal(beliefSet);

/// <inheritdoc />
public override void UpdateStatus(TBeliefSet beliefSet)
Expand Down
5 changes: 3 additions & 2 deletions Aplib.Core/Desire/GoalStructure.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ namespace Aplib.Core.Desire
/// <summary>
/// Describes a structure of goals that need to be fulfilled.
/// </summary>
public abstract class GoalStructure<TBeliefSet> : IGoalStructure<TBeliefSet> where TBeliefSet : IBeliefSet
public abstract class GoalStructure<TBeliefSet> : IGoalStructure<TBeliefSet>
where TBeliefSet : IBeliefSet
{
/// <inheritdoc />
public CompletionStatus Status { get; protected set; }
Expand All @@ -33,7 +34,7 @@ public abstract class GoalStructure<TBeliefSet> : IGoalStructure<TBeliefSet> whe
/// </summary>
/// <param name="beliefSet">The belief set of the agent.</param>
/// <returns>The current goal to be fulfilled.</returns>
public abstract IGoal GetCurrentGoal(TBeliefSet beliefSet);
public abstract IGoal<TBeliefSet> GetCurrentGoal(TBeliefSet beliefSet);

/// <summary>
/// Updates the state of the goal structure.
Expand Down
17 changes: 9 additions & 8 deletions Aplib.Core/Desire/Goals/CommonHeuristicFunctions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,36 +6,37 @@ namespace Aplib.Core.Desire.Goals
/// <summary>
/// Contains helper methods to generate commonly used heuristic functions.
/// </summary>
public static class CommonHeuristicFunctions
public static class CommonHeuristicFunctions<TBeliefSet>
where TBeliefSet : IBeliefSet
{
/// <summary>
/// Converts a boolean-based heuristic function to a <see cref="Goal.HeuristicFunction"/>.
/// Converts a boolean-based heuristic function to a <see cref="Goal{TBeliefSet}.HeuristicFunction"/>.
/// </summary>
/// <param name="heuristicFunction">
/// A heuristic function which returns true only when the state is considered completed.
/// </param>
/// <returns>A heuristic function which wraps around the boolean-based heuristic function.</returns>
public static Goal.HeuristicFunction Boolean(Func<bool> heuristicFunction)
=> _ => Heuristics.Boolean(heuristicFunction.Invoke());
public static Goal<TBeliefSet>.HeuristicFunction Boolean(Func<TBeliefSet, bool> heuristicFunction)
=> beliefSet => Heuristics.Boolean(heuristicFunction.Invoke(beliefSet));

/// <summary>
/// A <see cref="Goal.HeuristicFunction"/> which always returns <see cref="Heuristics"/> with the same distance.
/// A <see cref="Goal{TBeliefSet}.HeuristicFunction"/> which always returns <see cref="Heuristics"/> with the same distance.
/// </summary>
/// <param name="distance">The distance which the heuristic function must always return.</param>
public static Goal.HeuristicFunction Constant(float distance) => _ => new Heuristics { Distance = distance };
public static Goal<TBeliefSet>.HeuristicFunction Constant(float distance) => _ => new Heuristics { Distance = distance };

/// <summary>
/// Returns a heuristic function which always, at all times, and forever, returns a value indicating the state
/// can be seen as completed.
/// </summary>
/// <returns>Said heuristic function.</returns>
public static Goal.HeuristicFunction Completed() => Constant(0f);
public static Goal<TBeliefSet>.HeuristicFunction Completed() => Constant(0f);

/// <summary>
/// Returns a heuristic function which always, at all times, and forever, returns a value indicating the state
/// can be seen as NOT completed.
/// </summary>
/// <returns>Said heuristic function.</returns>
public static Goal.HeuristicFunction Uncompleted() => Constant(69_420f);
public static Goal<TBeliefSet>.HeuristicFunction Uncompleted() => Constant(69_420f);
}
}
22 changes: 12 additions & 10 deletions Aplib.Core/Desire/Goals/Goal.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,16 @@ namespace Aplib.Core.Desire.Goals
/// the testing.
/// </summary>
/// <seealso cref="GoalStructure{TBeliefSet}" />
public class Goal : IGoal
/// <typeparam name="TBeliefSet">The belief set of the agent.</typeparam>
public class Goal<TBeliefSet> : IGoal<TBeliefSet>
where TBeliefSet : IBeliefSet
{
/// <summary>
/// The abstract definition of what is means to test the Goal's heuristic function. Returns <see cref="Heuristics" />, as
/// they represent how close we are to matching the heuristic function, and if the goal is completed.
/// </summary>
/// <seealso cref="Goal.GetStatus" />
public delegate Heuristics HeuristicFunction(IBeliefSet beliefSet);
/// <seealso cref="Goal{TBeliefSet}.GetStatus" />
public delegate Heuristics HeuristicFunction(TBeliefSet beliefSet);

/// <summary>
/// Gets the metadata of the goal.
Expand All @@ -29,10 +31,10 @@ public class Goal : IGoal
public Metadata Metadata { get; }

/// <summary>
/// The <see cref="Intent.Tactics.Tactic" /> used to achieve this <see cref="Goal" />, which is executed during every
/// The <see cref="Intent.Tactics.Tactic{TBeliefSet}" /> used to achieve this <see cref="Goal{TBeliefSet}" />, which is executed during every
/// iteration of the BDI cycle.
/// </summary>
public Tactic Tactic { get; }
public ITactic<TBeliefSet> Tactic { get; }

/// <inheritdoc />
public CompletionStatus Status { get; protected set; }
Expand Down Expand Up @@ -68,7 +70,7 @@ public class Goal : IGoal
/// </param>
public Goal
(
Tactic tactic,
ITactic<TBeliefSet> tactic,
HeuristicFunction heuristicFunction,
double epsilon = 0.005d,
Metadata? metadata = null
Expand All @@ -92,10 +94,10 @@ public Goal
/// <param name="metadata">
/// Metadata about this goal, used to quickly display the goal in several contexts.
/// </param>
public Goal(Tactic tactic, Func<bool> predicate, double epsilon = 0.005d, Metadata? metadata = null)
public Goal(ITactic<TBeliefSet> tactic, Func<TBeliefSet, bool> predicate, double epsilon = 0.005d, Metadata? metadata = null)
{
Tactic = tactic;
_heuristicFunction = CommonHeuristicFunctions.Boolean(predicate);
_heuristicFunction = CommonHeuristicFunctions<TBeliefSet>.Boolean(predicate);
_epsilon = epsilon;
Metadata = metadata ?? new Metadata();
}
Expand All @@ -104,7 +106,7 @@ public Goal(Tactic tactic, Func<bool> predicate, double epsilon = 0.005d, Metada
/// Gets the <see cref="Heuristics" /> of the current state of the game.
/// </summary>
/// <remarks>If no heuristics have been calculated yet, they will be calculated first.</remarks>
public virtual Heuristics CurrentHeuristics(IBeliefSet beliefSet)
public virtual Heuristics CurrentHeuristics(TBeliefSet beliefSet)
=> _currentHeuristics ??= _heuristicFunction.Invoke(beliefSet);

/// <summary>
Expand All @@ -114,7 +116,7 @@ public virtual Heuristics CurrentHeuristics(IBeliefSet beliefSet)
/// </summary>
/// <returns>An enum representing whether the goal is complete and if so, with what result.</returns>
/// <seealso cref="_epsilon" />
public virtual CompletionStatus GetStatus(IBeliefSet beliefSet)
public virtual CompletionStatus GetStatus(TBeliefSet beliefSet)
{
Status = CurrentHeuristics(beliefSet).Distance < _epsilon
? CompletionStatus.Success
Expand Down
20 changes: 11 additions & 9 deletions Aplib.Core/Desire/Goals/IGoal.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,29 +4,31 @@
namespace Aplib.Core.Desire.Goals
{
/// <summary>
/// Defines a goal that can be achieved by a <see cref="Intent.Tactics.Tactic" />.
/// Defines a goal that can be achieved by a <see cref="Tactic{TBeliefSet}" />.
/// </summary>
public interface IGoal : ICompletable
/// <typeparam name="TBeliefSet">The belief set of the agent.</typeparam>
public interface IGoal<in TBeliefSet> : ICompletable
where TBeliefSet : IBeliefSet
{
/// <summary>
/// The <see cref="Intent.Tactics.Tactic" /> used to achieve this <see cref="Goal" />, which is executed during every
/// The <see cref="Tactic{TBeliefSet}" /> used to achieve this <see cref="Goal{TBeliefSet}" />, which is executed during every
/// iteration of the BDI cycle.
/// </summary>
Tactic Tactic { get; }
public ITactic<TBeliefSet> Tactic { get; }

/// <summary>
/// Gets the <see cref="Heuristics" /> of the current state of the game.
/// </summary>
/// <remarks>If no heuristics have been calculated yet, they will be calculated first.</remarks>
Heuristics CurrentHeuristics(IBeliefSet beliefSet);
Heuristics CurrentHeuristics(TBeliefSet beliefSet);

/// <summary>
/// Tests whether the goal has been achieved, bases on the <see cref="Goal._heuristicFunction" /> and the
/// <see cref="Goal.CurrentHeuristics" />. When the distance of the heuristics is smaller than <see cref="Goal._epsilon" />
/// Tests whether the goal has been achieved, based on the <see cref="Goal{TBeliefSet}._heuristicFunction" /> and the
/// <see cref="Goal{TBeliefSet}.CurrentHeuristics" />. When the distance of the heuristics is smaller than <see cref="Goal{TBeliefSet}._epsilon" />
/// , the goal is considered to be completed.
/// </summary>
/// <returns>An enum representing whether the goal is complete and if so, with what result.</returns>
/// <seealso cref="Goal._epsilon" />
CompletionStatus GetStatus(IBeliefSet beliefSet);
/// <seealso cref="Goal{TBeliefSet}._epsilon" />
CompletionStatus GetStatus(TBeliefSet beliefSet);
}
}
2 changes: 1 addition & 1 deletion Aplib.Core/Desire/IDesireSet.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public interface IDesireSet<in TBeliefSet> : ICompletable
/// </summary>
/// <param name="beliefSet">The belief set of the agent.</param>
/// <returns>The current goal to be fulfilled.</returns>
IGoal GetCurrentGoal(TBeliefSet beliefSet);
IGoal<TBeliefSet> GetCurrentGoal(TBeliefSet beliefSet);

/// <summary>
/// Updates the status of this <see cref="IDesireSet{TBeliefSet}"/>.
Expand Down
2 changes: 1 addition & 1 deletion Aplib.Core/Desire/IGoalStructure.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public interface IGoalStructure<in TBeliefSet> : ICompletable
/// </summary>
/// <param name="beliefSet">The belief set of the agent.</param>
/// <returns>The current goal to be fulfilled.</returns>
IGoal GetCurrentGoal(TBeliefSet beliefSet);
IGoal<TBeliefSet> GetCurrentGoal(TBeliefSet beliefSet);

/// <summary>
/// Updates the state of the goal structure.
Expand Down
6 changes: 3 additions & 3 deletions Aplib.Core/Desire/PrimitiveGoalStructure.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,16 @@ namespace Aplib.Core.Desire
public class PrimitiveGoalStructure<TBeliefSet> : GoalStructure<TBeliefSet>
where TBeliefSet : IBeliefSet
{
private readonly IGoal _goal;
private readonly IGoal<TBeliefSet> _goal;

/// <summary>
/// Initializes a new instance of the <see cref="PrimitiveGoalStructure{TBeliefSet}" /> class.
/// </summary>
/// <param name="goal">The goal to fulfill.</param>
public PrimitiveGoalStructure(IGoal goal) : base(Array.Empty<IGoalStructure<TBeliefSet>>()) => _goal = goal;
public PrimitiveGoalStructure(IGoal<TBeliefSet> goal) : base(Array.Empty<IGoalStructure<TBeliefSet>>()) => _goal = goal;

/// <inheritdoc />
public override IGoal GetCurrentGoal(TBeliefSet beliefSet) => _goal;
public override IGoal<TBeliefSet> GetCurrentGoal(TBeliefSet beliefSet) => _goal;

/// <inheritdoc />
public override void UpdateStatus(TBeliefSet beliefSet) =>
Expand Down
4 changes: 2 additions & 2 deletions Aplib.Core/Desire/RepeatGoalStructure.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public RepeatGoalStructure(IGoalStructure<TBeliefSet> goalStructure) : base(
_currentGoalStructure = goalStructure;

/// <inheritdoc />
public override IGoal GetCurrentGoal(TBeliefSet beliefSet) => _currentGoalStructure!.Status switch
public override IGoal<TBeliefSet> GetCurrentGoal(TBeliefSet beliefSet) => _currentGoalStructure!.Status switch
{
Unfinished or Failure => _currentGoalStructure.GetCurrentGoal(beliefSet),
_ => FinishRepeat(beliefSet)
Expand All @@ -42,7 +42,7 @@ public override void UpdateStatus(TBeliefSet beliefSet)
};
}

private IGoal FinishRepeat(TBeliefSet beliefSet)
private IGoal<TBeliefSet> FinishRepeat(TBeliefSet beliefSet)
{
Status = Success;
return _currentGoalStructure!.GetCurrentGoal(beliefSet);
Expand Down
6 changes: 3 additions & 3 deletions Aplib.Core/Desire/SequentialGoalStructure.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,17 @@ public class SequentialGoalStructure<TBeliefSet> : GoalStructure<TBeliefSet>, ID
/// Initializes a new instance of the <see cref="SequentialGoalStructure{TBeliefSet}" /> class.
/// </summary>
/// <param name="children">The children of the goal structure.</param>
public SequentialGoalStructure(IList<IGoalStructure<TBeliefSet>> children) : base(children)
public SequentialGoalStructure(params IGoalStructure<TBeliefSet>[] children) : base(children)
{
if (children.Count <= 0)
if (children.Length <= 0)
throw new ArgumentException("Collection of children is empty", nameof(children));
_childrenEnumerator = _children.GetEnumerator();
_childrenEnumerator.MoveNext();
_currentGoalStructure = _childrenEnumerator.Current;
}

/// <inheritdoc />
public override IGoal GetCurrentGoal(TBeliefSet beliefSet) => _currentGoalStructure!.GetCurrentGoal(beliefSet);
public override IGoal<TBeliefSet> GetCurrentGoal(TBeliefSet beliefSet) => _currentGoalStructure!.GetCurrentGoal(beliefSet);

/// <inheritdoc />
public override void UpdateStatus(TBeliefSet beliefSet)
Expand Down
Loading

0 comments on commit e421288

Please sign in to comment.