Skip to content

Commit

Permalink
Improved implementation to be more generic
Browse files Browse the repository at this point in the history
- SimulationController now allows custom event implementations
- EventBase can now be simply overriden and extended
  • Loading branch information
dolejska-daniel committed Dec 27, 2020
1 parent 07ef164 commit b103998
Show file tree
Hide file tree
Showing 8 changed files with 77 additions and 65 deletions.
14 changes: 7 additions & 7 deletions Scripts/CoroutineMonoSimulationController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ namespace UnityDES
/// The MonoBehaviour proxy class of <see cref="SimulationController"/>.
/// Simulation ticks will also be run in a coroutine.
/// </summary>
public class CoroutineMonoSimulationController : MonoBehaviour, ISimulationController<EventBase<SimulationTime>, SimulationTime>
public class CoroutineMonoSimulationController : MonoBehaviour, ISimulationController<SimulationTimeEvent, SimulationTime>
{
//==========================================================================dd==
// MonoBehaviour METHODS
Expand All @@ -18,30 +18,30 @@ public class CoroutineMonoSimulationController : MonoBehaviour, ISimulationContr

protected virtual void Start()
{
Controller = new SimulationController(TicksPerFrame);
Controller = new SimulationController<SimulationTimeEvent>(TicksPerFrame);
StartCoroutine("RunAvailableTicksCoroutine");
}

//==========================================================================dd==
// ISimulationController METHODS
//==========================================================================dd==

protected SimulationController Controller { get; set; }
protected SimulationController<SimulationTimeEvent> Controller { get; set; }

public SimulationTime SimulationTime => Controller.SimulationTime;

public int SimulationSpeed { get => Controller.SimulationSpeed; set => Controller.SimulationSpeed = value; }

public bool Reschedule(EventBase<SimulationTime> @event) => Controller.Reschedule(@event);
public bool Reschedule(SimulationTimeEvent @event) => Controller.Reschedule(@event);

public void RunAvailableTicks(float deltaTime) => Controller.RunAvailableTicks(deltaTime);

public IEnumerator RunAvailableTicksCoroutine() => Controller.RunAvailableTicksCoroutine();

public void Schedule(EventBase<SimulationTime> @event, float scheduleTime) => Controller.Schedule(@event, scheduleTime);
public void Schedule(SimulationTimeEvent @event, float scheduleTime) => Controller.Schedule(@event, scheduleTime);

public void Schedule(EventBase<SimulationTime> @event, int tickCount = 1) => Controller.Schedule(@event, tickCount);
public void Schedule(SimulationTimeEvent @event, int tickCount = 1) => Controller.Schedule(@event, tickCount);

public bool Unschedule(EventBase<SimulationTime> @event) => Controller.Unschedule(@event);
public bool Unschedule(SimulationTimeEvent @event) => Controller.Unschedule(@event);
}
}
4 changes: 2 additions & 2 deletions Scripts/Events/BehaviourResult.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public struct BehaviourResult<TEvent, TKey>
const float TIME_UNSCHEDULE = -2f;

/// <summary>
/// Minimum number of time to pass before running the event's behaviour again.
/// Minimum amount of time to pass before running the event's behaviour again.
/// </summary>
/// <remarks>
/// Values <c>&lt;0</c> are reserved for other result states.
Expand Down Expand Up @@ -52,7 +52,7 @@ public struct BehaviourResult<TEvent, TKey>
public TEvent NewEvent { get; internal set; }

/// <summary>
/// .
/// Minimum amount of time to pass before running the event.
/// </summary>
public float NewEventScheduleTime { get; internal set; }

Expand Down
43 changes: 26 additions & 17 deletions Scripts/Events/EventBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,14 @@ namespace UnityDES.Events
/// </summary>
///
/// <typeparam name="TKey">Type of the queue key</typeparam>
public abstract class EventBase<TKey> : IEvent<EventBase<TKey>, TKey>
public abstract class EventBase<TEvent, TKey> : IEvent<TEvent, TKey>
where TEvent : class, IEvent<TEvent, TKey>
{
public TKey QueueKey { get; set; }

public TKey SimulationTime { get => QueueKey; }

public IEnumerator<BehaviourResult<EventBase<TKey>, TKey>> BehaviourCycle { get; protected set; }
public IEnumerator<BehaviourResult<TEvent, TKey>> BehaviourCycle { get; protected set; }

/// <summary>
/// Initializes BehaviourCycle property.
Expand All @@ -24,19 +25,27 @@ public EventBase()
BehaviourCycle = Behaviour();
}

/// <summary>
/// Returns instance of the generic event derived from this class.
/// This method is necessary for correct type checking.
/// </summary>
///
/// <returns>Current instance of the generic event</returns>
protected abstract TEvent This();

/// <summary>
/// Updates the key so the event's execution happens in the future based on value of <paramref name="time"/>.
/// </summary>
///
/// <param name="time">Time offset into the future</param>
protected abstract void IncreaseKey(float time);

public abstract IEnumerator<BehaviourResult<EventBase<TKey>, TKey>> Behaviour();
public abstract IEnumerator<BehaviourResult<TEvent, TKey>> Behaviour();

public void Run(ISimulationController<EventBase<TKey>, TKey> simulationController)
public void Run(ISimulationController<TEvent, TKey> simulationController)
{
bool unfinished;
BehaviourResult<EventBase<TKey>, TKey> behaviourResult;
BehaviourResult<TEvent, TKey> behaviourResult;

do
{
Expand All @@ -57,7 +66,7 @@ public void Run(ISimulationController<EventBase<TKey>, TKey> simulationControlle
IncreaseKey(behaviourResult.RescheduleTime);

// reschedule the event
if (!simulationController.Reschedule(this))
if (!simulationController.Reschedule(This()))
throw new ApplicationException("Rescheduling of existing event has failed!");

if (behaviourResult.ResetBehaviour)
Expand All @@ -70,28 +79,28 @@ public void Run(ISimulationController<EventBase<TKey>, TKey> simulationControlle
{
// the event's behaviour either completely finished or it voluntarily wants to be unscheduled
// remove the event from the simulation
simulationController.Unschedule(this);
simulationController.Unschedule(This());
}
}

/// <inheritdoc cref="BehaviourResult{TEvent, TKey}.ScheduleNew(float, TEvent, float, bool)"/>
protected BehaviourResult<EventBase<TKey>, TKey> ScheduleNew(float rescheduleTime, EventBase<TKey> @event, float scheduleTime, bool reset = false)
=> BehaviourResult<EventBase<TKey>, TKey>.ScheduleNew(rescheduleTime, @event, scheduleTime, reset);
protected BehaviourResult<TEvent, TKey> ScheduleNew(float rescheduleTime, TEvent @event, float scheduleTime, bool reset = false)
=> BehaviourResult<TEvent, TKey>.ScheduleNew(rescheduleTime, @event, scheduleTime, reset);

/// <inheritdoc cref="BehaviourResult{TEvent, TKey}.ScheduleNewAndContinue(TEvent, float, bool)"/>
protected BehaviourResult<EventBase<TKey>, TKey> ScheduleNewAndContinue(EventBase<TKey> @event, float scheduleTime, bool reset = false)
=> BehaviourResult<EventBase<TKey>, TKey>.ScheduleNewAndContinue(@event, scheduleTime, reset);
protected BehaviourResult<TEvent, TKey> ScheduleNewAndContinue(TEvent @event, float scheduleTime, bool reset = false)
=> BehaviourResult<TEvent, TKey>.ScheduleNewAndContinue(@event, scheduleTime, reset);

/// <inheritdoc cref="BehaviourResult{TEvent, TKey}.Continue(bool)"/>
protected BehaviourResult<EventBase<TKey>, TKey> Continue(bool reset = false)
=> BehaviourResult<EventBase<TKey>, TKey>.Continue(reset);
protected BehaviourResult<TEvent, TKey> Continue(bool reset = false)
=> BehaviourResult<TEvent, TKey>.Continue(reset);

/// <inheritdoc cref="BehaviourResult{TEvent, TKey}.Reschedule(float, bool)"/>
protected BehaviourResult<EventBase<TKey>, TKey> Reschedule(float rescheduleTime, bool reset = true)
=> BehaviourResult<EventBase<TKey>, TKey>.Reschedule(rescheduleTime, reset);
protected BehaviourResult<TEvent, TKey> Reschedule(float rescheduleTime, bool reset = true)
=> BehaviourResult<TEvent, TKey>.Reschedule(rescheduleTime, reset);

/// <inheritdoc cref="BehaviourResult{TEvent, TKey}.Unschedule"/>
protected BehaviourResult<EventBase<TKey>, TKey> Unschedule()
=> BehaviourResult<EventBase<TKey>, TKey>.Unschedule();
protected BehaviourResult<TEvent, TKey> Unschedule()
=> BehaviourResult<TEvent, TKey>.Unschedule();
}
}
4 changes: 3 additions & 1 deletion Scripts/Events/SimulationTimeEvent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ namespace UnityDES.Events
/// <summary>
/// Simple base class for any event implementations with <see cref="SimulationTime"/> as a queue key.
/// </summary>
public abstract class SimulationTimeEvent : EventBase<SimulationTime>
public abstract class SimulationTimeEvent : EventBase<SimulationTimeEvent, SimulationTime>
{
protected SimulationTimeEvent(SimulationTime simulationTime) : base()
{
Expand All @@ -16,6 +16,8 @@ protected SimulationTimeEvent(int ticksPerFrame) : base()
QueueKey = new SimulationTime(ticksPerFrame);
}

protected override SimulationTimeEvent This() => this;

protected override void IncreaseKey(float time) => QueueKey.DoTick(time);
}
}
17 changes: 9 additions & 8 deletions Scripts/SimulationController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ namespace UnityDES
/// <summary>
/// The main class controlling the simulation.
/// </summary>
public class SimulationController : ISimulationController<EventBase<SimulationTime>, SimulationTime>
public class SimulationController<TEvent> : ISimulationController<TEvent, SimulationTime>
where TEvent : class, IEvent<TEvent, SimulationTime>
{
public SimulationTime SimulationTime { get; protected set; }

Expand All @@ -21,12 +22,12 @@ public class SimulationController : ISimulationController<EventBase<SimulationTi
/// <summary>
/// Queue of the simulation events.
/// </summary>
protected PriorityQueue<EventBase<SimulationTime>, SimulationTime> Events;
protected PriorityQueue<TEvent, SimulationTime> Events;

/// <summary>
/// Comparer of the simulation events for the queue.
/// </summary>
public static readonly Comparer<EventBase<SimulationTime>> EventComparer = Comparer<EventBase<SimulationTime>>.Create(
public static readonly Comparer<TEvent> EventComparer = Comparer<TEvent>.Create(
(a, b) => SimulationTime.Comparer.Compare(a.QueueKey, b.QueueKey));

/// <summary>
Expand All @@ -35,7 +36,7 @@ public class SimulationController : ISimulationController<EventBase<SimulationTi
public SimulationController(int ticksPerFrame = 1)
{
SimulationTime = new SimulationTime(ticksPerFrame);
Events = new PriorityQueue<EventBase<SimulationTime>, SimulationTime>(EventComparer);
Events = new PriorityQueue<TEvent, SimulationTime>(EventComparer);
}

public IEnumerator RunAvailableTicksCoroutine()
Expand Down Expand Up @@ -90,10 +91,10 @@ public void RunTick()
SimulationTime.DoTick();
}

public void Schedule(EventBase<SimulationTime> @event, float scheduleTime)
public void Schedule(TEvent @event, float scheduleTime)
=> Schedule(@event, (int)Math.Ceiling(@event.QueueKey.TicksPerFrame * scheduleTime));

public void Schedule(EventBase<SimulationTime> @event, int tickCount = 1)
public void Schedule(TEvent @event, int tickCount = 1)
{
// set current simulation time
@event.QueueKey.Frame = SimulationTime.Frame;
Expand All @@ -105,13 +106,13 @@ public void Schedule(EventBase<SimulationTime> @event, int tickCount = 1)
Events.Enqueue(@event);
}

public bool Reschedule(EventBase<SimulationTime> @event)
public bool Reschedule(TEvent @event)
{
// re-enqueue the event
return Events.Update(@event);
}

public bool Unschedule(EventBase<SimulationTime> @event)
public bool Unschedule(TEvent @event)
{
// remove the event from the queue
return Events.Dequeue(@event);
Expand Down
24 changes: 12 additions & 12 deletions Tests/Controls/FacilityTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public PublicEvent(int ticksPerFrame = 10) : base(ticksPerFrame)
{
}

public override IEnumerator<BehaviourResult<EventBase<SimulationTime>, SimulationTime>> Behaviour()
public override IEnumerator<BehaviourResult<SimulationTimeEvent, SimulationTime>> Behaviour()
{
// reschedule to next tick
yield return Reschedule(QueueKey.TickLength, false);
Expand All @@ -27,25 +27,25 @@ public override IEnumerator<BehaviourResult<EventBase<SimulationTime>, Simulatio
public new void IncreaseKey(float time) => base.IncreaseKey(time);
}

public class PublicFacility : Facility<EventBase<SimulationTime>, SimulationTime>
public class PublicFacility : Facility<SimulationTimeEvent, SimulationTime>
{
public new PriorityQueue<FacilityEntry, int> WaitingQueue { get => base.WaitingQueue; }

public new PriorityQueue<FacilityEntry, int> InterruptedQueue { get => base.InterruptedQueue; }

public new SortedSet<FacilityEntry> Inside { get => base.Inside; }

public new Dictionary<EventBase<SimulationTime>, FacilityEntry> EventEntryMapping { get => base.EventEntryMapping; }
public new Dictionary<SimulationTimeEvent, FacilityEntry> EventEntryMapping { get => base.EventEntryMapping; }

public PublicFacility(ISimulationController<EventBase<SimulationTime>, SimulationTime> controller, int capacity = 1) : base(controller, capacity)
public PublicFacility(ISimulationController<SimulationTimeEvent, SimulationTime> controller, int capacity = 1) : base(controller, capacity)
{
}
}

[Test]
public void Claim_Free()
{
var controller = new SimulationController(4);
var controller = new SimulationController<SimulationTimeEvent>(4);
var facility = new PublicFacility(controller);

var event1 = new PublicEvent(4);
Expand All @@ -71,7 +71,7 @@ public void Claim_Free()
[Test]
public void Claim_Full()
{
var controller = new SimulationController(4);
var controller = new SimulationController<SimulationTimeEvent>(4);
var facility = new PublicFacility(controller);

var event1 = new PublicEvent(4);
Expand All @@ -98,7 +98,7 @@ public void Claim_Full()
[Test]
public void Claim_Full_Priority()
{
var controller = new SimulationController(4);
var controller = new SimulationController<SimulationTimeEvent>(4);
var facility = new PublicFacility(controller);

var event1 = new PublicEvent(4);
Expand Down Expand Up @@ -128,7 +128,7 @@ public void Claim_Full_Priority()
[Test]
public void Claim_Full_PrioritySelction()
{
var controller = new SimulationController(4);
var controller = new SimulationController<SimulationTimeEvent>(4);
var facility = new PublicFacility(controller);

var event1 = new PublicEvent(4);
Expand Down Expand Up @@ -164,7 +164,7 @@ public void Claim_Full_PrioritySelction()
[Test]
public void Free()
{
var controller = new SimulationController(4);
var controller = new SimulationController<SimulationTimeEvent>(4);
var facility = new PublicFacility(controller);

var event1 = new PublicEvent(4);
Expand All @@ -190,7 +190,7 @@ public void Free()
[Test]
public void Free_WithWaiting()
{
var controller = new SimulationController(4);
var controller = new SimulationController<SimulationTimeEvent>(4);
var facility = new PublicFacility(controller);

var event1 = new PublicEvent(4);
Expand Down Expand Up @@ -220,7 +220,7 @@ public void Free_WithWaiting()
[Test]
public void Free_WithInterrupted()
{
var controller = new SimulationController(4);
var controller = new SimulationController<SimulationTimeEvent>(4);
var facility = new PublicFacility(controller);

var event1 = new PublicEvent(4);
Expand Down Expand Up @@ -253,7 +253,7 @@ public void Free_WithInterrupted()
[Test]
public void Free_WithWaiting_WithInterrupted()
{
var controller = new SimulationController(4);
var controller = new SimulationController<SimulationTimeEvent>(4);
var facility = new PublicFacility(controller);

var event1 = new PublicEvent(4);
Expand Down
Loading

0 comments on commit b103998

Please sign in to comment.