Skip to content

Commit

Permalink
wip: overgave aan Thijs
Browse files Browse the repository at this point in the history
  • Loading branch information
SilasPeters committed Mar 28, 2024
1 parent dc07266 commit 5347df3
Show file tree
Hide file tree
Showing 8 changed files with 195 additions and 12 deletions.
34 changes: 34 additions & 0 deletions Aplib.Core/Desire/FirstOfGoalStructure.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using Aplib.Core.Belief;
using Aplib.Core.Desire.Goals;
using System.Collections.Generic;

namespace Aplib.Core.Desire
{
public class FirstOfGoalStructure : SequentialGoalStructure
{
protected Goal? _currentGoal;

/// <inheritdoc />
public override Goal? DetermineCurrentGoal(IBeliefSet beliefSet)
{
_currentGoal ??= GetNextGoal(beliefSet); // Should only happen the first time this method is called
if (_currentGoal is null) return null; // Can be the case when no next goal can be found

switch (_currentGoal!.GetState(beliefSet))
{
case GoalState.Success:
return null;
case GoalState.Failure:
_currentGoal = GetNextGoal(beliefSet);
return DetermineCurrentGoal(beliefSet);

default:
return _currentGoal;
}
}

/// <inheritdoc />
public FirstOfGoalStructure(IList<GoalStructure> children) : base(children)
{ }
}
}
35 changes: 35 additions & 0 deletions Aplib.Core/Desire/GoalStructure.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
using Aplib.Core.Belief;
using Aplib.Core.Desire.Goals;
using System.Collections.Generic;

namespace Aplib.Core.Desire
{
public abstract class GoalStructure
{
protected IList<GoalStructure> _children;
protected Goal? _currentGoal;
public GoalStructureState GoalStructureState { get; set; } = GoalStructureState.Unfinished; // TODO

protected GoalStructure(IList<GoalStructure> children)
{
_children = children;
}

public void Interrupt()
{
// Premature optimisation:
// foreach (var processedChild in GetAllProcessedChildren())
// processedChild.Interrupt();
foreach (GoalStructure child in _children)
child.Interrupt();

ProcessInterrupt();
}

public abstract Goal? DetermineCurrentGoal(IBeliefSet beliefSet);

protected abstract void ProcessInterrupt();
}

public enum GoalStructureState { Unfinished, Success, Failure }
}
18 changes: 11 additions & 7 deletions Aplib.Core/Desire/Goals/Goal.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,15 @@ public class Goal
/// 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="IsCompleted"/>
public delegate Heuristics HeuristicFunction(BeliefSet beliefSet);
/// <seealso cref="Goal.GetState"/>
public delegate Heuristics HeuristicFunction(IBeliefSet beliefSet);


/// <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>
public virtual Heuristics CurrentHeuristics(BeliefSet beliefSet)
public virtual Heuristics CurrentHeuristics(IBeliefSet beliefSet)
=> _currentHeuristics ??= _heuristicFunction.Invoke(beliefSet);

/// <summary>
Expand All @@ -48,7 +48,7 @@ public virtual Heuristics CurrentHeuristics(BeliefSet beliefSet)
/// The concrete implementation of this Goal's <see cref="HeuristicFunction"/>. Used to test whether this goal is
/// completed.
/// </summary>
/// <seealso cref="IsCompleted"/>
/// <seealso cref="GetState"/>
protected HeuristicFunction _heuristicFunction;

/// <summary>
Expand Down Expand Up @@ -86,7 +86,7 @@ public Goal(Tactic tactic, HeuristicFunction heuristicFunction, string name, str
/// Creates a new goal which works with boolean-based <see cref="Heuristics"/>.
/// </summary>
/// <param name="tactic">The tactic used to approach this goal.</param>
/// <param name="predicate">The heuristic function (or specifically predicate) which defines whether a goal is reached</param>
/// <param name="predicate">The heuristic function (or specifically predicate) which defines whether a goal is reached.</param>
/// <param name="name">The name of this goal, used to quickly display this goal in several contexts.</param>
/// <param name="description">The description of this goal, used to explain this goal in several contexts.</param>
/// <param name="epsilon">
Expand All @@ -107,8 +107,12 @@ public Goal(Tactic tactic, Func<bool> predicate, string name, string description
/// <see cref="CurrentHeuristics"/>. When the distance of the heuristics is smaller than <see cref="_epsilon"/>,
/// the goal is considered to be completed.
/// </summary>
/// <returns>A boolean representing whether the goal is considered to be completed.</returns>
/// <returns>An enum representing whether the goal is complete and if so, with what result.</returns>
/// <seealso cref="_epsilon"/>
public bool IsCompleted(BeliefSet beliefSet) => CurrentHeuristics(beliefSet).Distance < _epsilon;
public GoalState GetState(IBeliefSet beliefSet) => CurrentHeuristics(beliefSet).Distance < _epsilon
? GoalState.Success
: GoalState.Unfinished; // TODO what about failure?
}

public enum GoalState { Unfinished, Success, Failure }
}
25 changes: 25 additions & 0 deletions Aplib.Core/Desire/PrimitiveGoalStructure.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using Aplib.Core.Belief;
using Aplib.Core.Desire.Goals;
using static Aplib.Core.Desire.Goals.GoalState;

namespace Aplib.Core.Desire
{
public class PrimitiveGoalStructure : GoalStructure
{
/// <inheritdoc />
public PrimitiveGoalStructure(Goal goal) : base(children: System.Array.Empty<GoalStructure>())
{
// We use _currentGoal as 'the' goal. It will never change hereafter.
_currentGoal = goal;
}

public override Goal? DetermineCurrentGoal(IBeliefSet beliefSet) => _currentGoal!.GetState(beliefSet) switch
{
Unfinished => _currentGoal,
_ => null
};

/// <inheritdoc />
protected override void ProcessInterrupt() { /* Do nothing */ }
}
}
20 changes: 20 additions & 0 deletions Aplib.Core/Desire/RepeatGoalStructure.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using Aplib.Core.Belief;
using Aplib.Core.Desire.Goals;
using static Aplib.Core.Desire.Goals.GoalState;

namespace Aplib.Core.Desire
{
public class RepeatGoalStructure : PrimitiveGoalStructure
{
/// <inheritdoc />
public RepeatGoalStructure(Goal goal) : base(goal)
{ }

/// <inheritdoc />
public override Goal? DetermineCurrentGoal(IBeliefSet beliefSet) => _currentGoal.GetState(beliefSet) switch
{
Unfinished or Failure => _currentGoal,
Success => null
};
}
}
57 changes: 57 additions & 0 deletions Aplib.Core/Desire/SequentialGoalStructure.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
using Aplib.Core.Belief;
using Aplib.Core.Desire.Goals;
using System;
using System.Collections.Generic;
using System.Linq;

namespace Aplib.Core.Desire
{
public class SequentialGoalStructure : GoalStructure, IDisposable
{
protected readonly IEnumerator<GoalStructure> _childrenEnumerator; // TODO autoproperty?


/// <inheritdoc />
public override Goal? DetermineCurrentGoal(IBeliefSet beliefSet) => GetNextGoal(beliefSet);

/// <summary>
/// Returns the goal from the first child which returns a goal.
/// </summary>
/// <param name="beliefSet"></param>
/// <returns>TODO</returns>
protected Goal? GetNextGoal(IBeliefSet beliefSet)
{
// throw new NotImplementedException("Why move to the next one immediatly?");
// if (!_childrenEnumerator.MoveNext())
// return null;
// return _childrenEnumerator.Current!.DetermineCurrentGoal(beliefSet) ?? GetNextGoal(beliefSet);

Goal? currentGoal = _childrenEnumerator.Current!.DetermineCurrentGoal(beliefSet); // TODO what happens once Current is undefined?
if (currentGoal is not null) return currentGoal;
// TODO what if the previous goal becomes uncompleted due to e.g. enemies?

return _childrenEnumerator.MoveNext() ? DetermineCurrentGoal(beliefSet) : null;
}

/// <inheritdoc />
protected override void ProcessInterrupt() => _childrenEnumerator.Reset();

/// <inheritdoc />
public SequentialGoalStructure(IList<GoalStructure> children) : base(children)
{
if (!children.Any())
throw new ArgumentException("Collection of children is empty", nameof(children));
_childrenEnumerator = _children.GetEnumerator();
}

/// <inheritdoc />
public void Dispose()
{
_childrenEnumerator.Dispose();

// Tell the Garbage Collector that it does not need to run the finalizer of this class anymore
// https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1816#rule-description
GC.SuppressFinalize(this);
}
}
}
8 changes: 8 additions & 0 deletions Aplib.Tests/Desire/GoalStructureTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using FluentAssertions;

namespace Aplib.Tests.Desire;

public class GoalStructureTests
{

}
10 changes: 5 additions & 5 deletions Aplib.Tests/Desire/GoalTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ public void Goal_WhenReached_ReturnsAsCompleted()

// Act
Goal goal = new TestGoalBuilder().WithHeuristicFunction(heuristicFunction).Build();
bool isCompleted = goal.IsCompleted(beliefSet);
bool isCompleted = goal.GetState(beliefSet);

// Assert
isCompleted.Should().Be(true);
Expand All @@ -86,7 +86,7 @@ public void Goal_WhenNotReached_DoesNotReturnAsCompleted()

// Act
Goal goal = new TestGoalBuilder().WithHeuristicFunction(heuristicFunction).Build();
bool isCompleted = goal.IsCompleted(beliefSet);
bool isCompleted = goal.GetState(beliefSet);

// Assert
isCompleted.Should().Be(false);
Expand All @@ -105,7 +105,7 @@ public void Goal_WhereEvaluationIsPerformed_DoesNotInfluenceBelieveSet()

// Act
Goal goal = new TestGoalBuilder().Build();
_ = goal.IsCompleted(beliefSet);
_ = goal.GetState(beliefSet);

// Assert
beliefSet.MyBelief.Updated.Should().Be(false);
Expand Down Expand Up @@ -135,8 +135,8 @@ public void GoalConstructor_WhereHeuristicFunctionTypeDiffers_HasEqualBehaviour(

// Act
MyBeliefSet beliefSet = new();
bool goalBooleanEvaluation = goalBoolean.IsCompleted(beliefSet);
bool goalNonBooleanEvaluation = goalNonBoolean.IsCompleted(beliefSet);
bool goalBooleanEvaluation = goalBoolean.GetState(beliefSet);
bool goalNonBooleanEvaluation = goalNonBoolean.GetState(beliefSet);

// Assert
goalBooleanEvaluation.Should().Be(goalNonBooleanEvaluation);
Expand Down

0 comments on commit 5347df3

Please sign in to comment.