-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
acbbca2
commit 362eb9a
Showing
14 changed files
with
591 additions
and
146 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,124 +1,87 @@ | ||
using ConsoleApp1.sim; | ||
using ConsoleApp1.sim.graph; | ||
using ConsoleApp1.util; | ||
using MQTTnet.Client; | ||
using QuickGraph.Algorithms; | ||
|
||
namespace ConsoleApp1.clients; | ||
|
||
public abstract class CarClient : BaseClient | ||
{ | ||
protected int Id { get; } | ||
protected PhysicalWorld PhysicalWorld { get; } | ||
protected StreetPosition Position { get; set; } | ||
protected IEnumerable<StreetEdge> Path { get; set; } | ||
protected StreetNode Destination { get; set; } | ||
|
||
protected CarClientStatus Status { get; set; } | ||
|
||
protected bool Logging { get; set; } | ||
|
||
public override string ToString() => $"[CAR\t{Id},\t{Status}\t]"; | ||
|
||
protected abstract void HandleDestinationReached(); | ||
protected abstract Task HandleNodeReached(); | ||
protected abstract void TurnOnNextStreetEdge(); | ||
protected abstract void UpdateDestination(); | ||
|
||
protected CarClient(IMqttClient mqttClient, PhysicalWorld physicalWorld, int id, bool logging) : base(mqttClient) | ||
{ | ||
Id = id; | ||
PhysicalWorld = physicalWorld; | ||
Logging = logging; | ||
Path = Enumerable.Empty<StreetEdge>(); | ||
|
||
// init position | ||
Position = StreetPosition.WithRandomDistance(physicalWorld.StreetEdges.RandomElement()); | ||
Position.StreetEdge.IncrementCarCount(); | ||
|
||
// get initial dest | ||
UpdateDestination(); | ||
} | ||
|
||
protected void HandlePathingFailed() | ||
{ | ||
RespawnAtRandom(); | ||
} | ||
|
||
protected void RespawnAtRandom() | ||
{ | ||
Position.StreetEdge.DecrementCarCount(); | ||
Position = StreetPosition.WithRandomDistance(PhysicalWorld.StreetEdges.RandomElement()); | ||
Position.StreetEdge.IncrementCarCount(); | ||
UpdateDestination(); | ||
} | ||
|
||
protected async Task HandleDriving() | ||
{ | ||
if (DestinationReached()) // car reached destination after driving | ||
{ | ||
HandleDestinationReached(); | ||
} | ||
else | ||
{ | ||
await DriveAccordingToPath(); | ||
} | ||
} | ||
|
||
|
||
private bool DestinationReached() | ||
{ | ||
return !Path.Any() && Destination == Position.StreetEdge.Target && | ||
Position.DistanceFromSource >= Position.StreetEdge.Length; | ||
} | ||
|
||
protected async Task DriveAccordingToPath() | ||
{ | ||
if (Position.DistanceFromSource < Position.StreetEdge.Length) // driving on street | ||
{ | ||
UpdatePosition(); | ||
} | ||
else | ||
{ | ||
await HandleNodeReached(); | ||
} | ||
} | ||
|
||
private void UpdatePosition() | ||
{ | ||
double speed = Position.StreetEdge.CurrentMaxSpeed(); | ||
Position = new StreetPosition(Position.StreetEdge, Position.DistanceFromSource + MathUtil.KmhToMs(speed)); | ||
|
||
if (Logging) | ||
{ | ||
Console.WriteLine($"{this}\ttick | {Position.ToString()} | dest: {Destination.Id} | car count: {Position.StreetEdge.CarCount} | driving at {speed:F2}kmh/{Position.StreetEdge.SpeedLimit:F2}kmh"); | ||
} | ||
|
||
} | ||
|
||
protected void UpdatePath() | ||
{ | ||
var shortestPaths = PhysicalWorld.Graph.ShortestPathsDijkstra( | ||
edge => 100 - edge.SpeedLimit, | ||
Position.StreetEdge.Source); | ||
|
||
if (shortestPaths.Invoke(Destination, out var path)) | ||
{ | ||
Path = path.ToList(); | ||
if (Logging) | ||
{ | ||
Console.WriteLine($"{this}\tpath: {string.Join(',', Path.Select(p => p.StreetName))}"); | ||
} | ||
} | ||
else | ||
{ | ||
if (Logging) | ||
{ | ||
Console.WriteLine($"{this}\tno path found [destination: {Destination.Id}, position: {Position}, node: {Position.StreetEdge.Source.Id}]"); | ||
} | ||
Path = Enumerable.Empty<StreetEdge>(); | ||
Status = CarClientStatus.PathingFailed; | ||
} | ||
} | ||
|
||
using ConsoleApp1.pgs; | ||
using ConsoleApp1.sim; | ||
using ConsoleApp1.sim.graph; | ||
using ConsoleApp1.util; | ||
using MQTTnet.Client; | ||
|
||
namespace ConsoleApp1.clients; | ||
|
||
public class CarClient: BaseClient | ||
{ | ||
protected CarClient(IMqttClient mqttClient, ICarClientBehaviour behaviour, PhysicalWorld world, ParkingGuidanceSystem pgs, int id, bool logging) : base(mqttClient) | ||
{ | ||
Behaviour = behaviour; | ||
var kpiManager = new KpiManager(mqttClient, Car); | ||
Car = new MockCar(id, world, kpiManager, logging); | ||
Pgs = pgs; | ||
|
||
// get initial dest | ||
Car.Status = CarStatus.Driving; | ||
Car.KpiManager.Reset(); | ||
Behaviour.UpdateDestination(Car); | ||
} | ||
|
||
public ParkingGuidanceSystem Pgs { get; set; } | ||
|
||
private ICarClientBehaviour Behaviour { get; set; } | ||
|
||
public MockCar Car { get; set; } | ||
|
||
/* | ||
* Creation through factory | ||
*/ | ||
public static async Task<CarClient> Create(MqttClientFactory clientFactory, ICarClientBehaviour behaviour, | ||
PhysicalWorld physicalWorld, ParkingGuidanceSystem pgs, int id, bool logging) | ||
{ | ||
var client = await clientFactory.CreateClient(builder => builder.WithTopicFilter("tickgen/tick")); | ||
return new CarClient(client, behaviour, physicalWorld, pgs, id, logging); | ||
} | ||
|
||
/** | ||
* Main state machine | ||
*/ | ||
protected override async Task MqttClientOnApplicationMessageReceivedAsync(MqttApplicationMessageReceivedEventArgs arg) | ||
{ | ||
switch (Car.Status) | ||
{ | ||
case CarStatus.PathingFailed: | ||
Car.Status = CarStatus.Driving; | ||
Car.RespawnAtRandom(); | ||
Behaviour.UpdateDestination(Car); | ||
break; | ||
|
||
case CarStatus.Driving: | ||
if (Car.DestinationReached()) | ||
{ | ||
Car.Status = CarStatus.Parking; | ||
} | ||
else | ||
{ | ||
Behaviour.DriveAlongPath(Car); | ||
} | ||
break; | ||
|
||
case CarStatus.Parking: | ||
Car.KpiManager.TicksSpentParking++; | ||
Behaviour.SeekParkingSpot(Car); | ||
new CruiserClientBehaviour().DriveAlongPath(Car); | ||
if (Behaviour.AttemptLocalParking(Car)) | ||
{ | ||
Car.Status = CarStatus.Parked; | ||
} | ||
break; | ||
|
||
case CarStatus.Parked: | ||
if (!Behaviour.StayParked(Car)) | ||
{ | ||
Car.Status = CarStatus.Driving; | ||
Behaviour.UpdateDestination(Car); | ||
} | ||
break; | ||
|
||
default: | ||
throw new InvalidOperationException($"{this}\tInvalid status: {Car.Status}"); | ||
} | ||
} | ||
|
||
} |
123 changes: 123 additions & 0 deletions
123
src/Solution1/ConsoleApp1/clients/CarClientDeprecated.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
using ConsoleApp1.sim; | ||
using ConsoleApp1.sim.graph; | ||
using ConsoleApp1.util; | ||
using MQTTnet.Client; | ||
using QuickGraph.Algorithms; | ||
|
||
namespace ConsoleApp1.clients; | ||
|
||
public abstract class CarClientDeprecated : BaseClient | ||
{ | ||
protected int Id { get; } | ||
protected PhysicalWorld PhysicalWorld { get; } | ||
protected StreetPosition Position { get; set; } | ||
protected IEnumerable<StreetEdge> Path { get; set; } | ||
protected StreetNode Destination { get; set; } | ||
|
||
protected CarStatus Status { get; set; } | ||
|
||
protected bool Logging { get; set; } | ||
|
||
public override string ToString() => $"[CAR\t{Id},\t{Status}\t]"; | ||
|
||
protected abstract void HandleDestinationReached(); | ||
protected abstract Task HandleNodeReached(); | ||
protected abstract void TurnOnNextStreetEdge(); | ||
protected abstract void UpdateDestination(); | ||
|
||
protected CarClientDeprecated(IMqttClient mqttClient, PhysicalWorld physicalWorld, int id, bool logging) : base(mqttClient) | ||
{ | ||
Id = id; | ||
PhysicalWorld = physicalWorld; | ||
Logging = logging; | ||
Path = Enumerable.Empty<StreetEdge>(); | ||
|
||
// init position | ||
Position = StreetPosition.WithRandomDistance(physicalWorld.StreetEdges.RandomElement()); | ||
Position.StreetEdge.IncrementCarCount(); | ||
|
||
// get initial dest | ||
UpdateDestination(); | ||
} | ||
|
||
protected void HandlePathingFailed() | ||
{ | ||
RespawnAtRandom(); | ||
} | ||
|
||
protected void RespawnAtRandom() | ||
{ | ||
Position.StreetEdge.DecrementCarCount(); | ||
Position = StreetPosition.WithRandomDistance(PhysicalWorld.StreetEdges.RandomElement()); | ||
Position.StreetEdge.IncrementCarCount(); | ||
UpdateDestination(); | ||
} | ||
|
||
protected async Task HandleDriving() | ||
{ | ||
if (DestinationReached()) // car reached destination after driving | ||
{ | ||
HandleDestinationReached(); | ||
} | ||
else | ||
{ | ||
await DriveAccordingToPath(); | ||
} | ||
} | ||
|
||
|
||
private bool DestinationReached() | ||
{ | ||
return !Path.Any() && Destination == Position.StreetEdge.Target && | ||
Position.DistanceFromSource >= Position.StreetEdge.Length; | ||
} | ||
|
||
protected async Task DriveAccordingToPath() | ||
{ | ||
if (Position.DistanceFromSource < Position.StreetEdge.Length) // driving on street | ||
{ | ||
UpdatePosition(); | ||
} | ||
else | ||
{ | ||
await HandleNodeReached(); | ||
} | ||
} | ||
|
||
private void UpdatePosition() | ||
{ | ||
double speed = Position.StreetEdge.CurrentMaxSpeed(); | ||
Position = new StreetPosition(Position.StreetEdge, Position.DistanceFromSource + MathUtil.KmhToMs(speed)); | ||
|
||
if (Logging) | ||
{ | ||
Console.WriteLine($"{this}\ttick | {Position.ToString()} | dest: {Destination.Id} | car count: {Position.StreetEdge.CarCount} | driving at {speed:F2}kmh/{Position.StreetEdge.SpeedLimit:F2}kmh"); | ||
} | ||
} | ||
|
||
protected void UpdatePath() | ||
{ | ||
var shortestPaths = PhysicalWorld.Graph.ShortestPathsDijkstra( | ||
edge => 100 - edge.SpeedLimit, | ||
Position.StreetEdge.Source); | ||
|
||
if (shortestPaths.Invoke(Destination, out var path)) | ||
{ | ||
Path = path.ToList(); | ||
if (Logging) | ||
{ | ||
Console.WriteLine($"{this}\tpath: {string.Join(',', Path.Select(p => p.StreetName))}"); | ||
} | ||
} | ||
else | ||
{ | ||
if (Logging) | ||
{ | ||
Console.WriteLine($"{this}\tno path found [destination: {Destination.Id}, position: {Position}, node: {Position.StreetEdge.Source.Id}]"); | ||
} | ||
Path = Enumerable.Empty<StreetEdge>(); | ||
Status = CarStatus.PathingFailed; | ||
} | ||
} | ||
|
||
} |
2 changes: 1 addition & 1 deletion
2
...n1/ConsoleApp1/clients/CarClientStatus.cs → ...olution1/ConsoleApp1/clients/CarStatus.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,6 @@ | ||
namespace ConsoleApp1.clients; | ||
|
||
public enum CarClientStatus | ||
public enum CarStatus | ||
{ | ||
Driving, | ||
Parking, | ||
|
Oops, something went wrong.