diff --git a/047-TrafficControlWithDapr/README.md b/047-TrafficControlWithDapr/README.md
index a0c7012f33..0a6bac2546 100644
--- a/047-TrafficControlWithDapr/README.md
+++ b/047-TrafficControlWithDapr/README.md
@@ -71,3 +71,4 @@ When the car passes an exit-camera, another photo and timestamp are registered.
- Rob Vettor
- Edwin van Wijk
- Chandrasekar B
+- Vaclav Jirovsky
diff --git a/047-TrafficControlWithDapr/Student/Challenge-00.md b/047-TrafficControlWithDapr/Student/Challenge-00.md
index b48aab77ca..6cdab85605 100644
--- a/047-TrafficControlWithDapr/Student/Challenge-00.md
+++ b/047-TrafficControlWithDapr/Student/Challenge-00.md
@@ -18,7 +18,7 @@ Your coach will provide you with a `Resources.zip` package file that contains th
Install all the prerequisites listed below and make sure they're working correctly:
- Git ([download](https://git-scm.com/))
- - .NET 5 SDK ([download](https://dotnet.microsoft.com/download/dotnet/5.0))
+ - .NET 5 SDK ([download](https://dotnet.microsoft.com/download/dotnet/5.0)), .NET 6 SDK ([download](https://dotnet.microsoft.com/download/dotnet/6.0))
- Visual Studio Code ([download](https://code.visualstudio.com/download)) with the following extensions installed:
- [C#](https://marketplace.visualstudio.com/items?itemName=ms-dotnettools.csharp)
- [REST Client](https://marketplace.visualstudio.com/items?itemName=humao.rest-client)
diff --git a/047-TrafficControlWithDapr/Student/Resources/Simulation/CameraSimulation.cs b/047-TrafficControlWithDapr/Student/Resources/Simulation/CameraSimulation.cs
index 21ad8ae260..20a5541ea2 100644
--- a/047-TrafficControlWithDapr/Student/Resources/Simulation/CameraSimulation.cs
+++ b/047-TrafficControlWithDapr/Student/Resources/Simulation/CameraSimulation.cs
@@ -1,4 +1,5 @@
using System;
+using System.Diagnostics;
using System.Net.Http;
using System.Net.Http.Json;
using System.Text.Json;
@@ -11,6 +12,7 @@ namespace Simulation
public class CameraSimulation
{
private readonly ITrafficControlService _trafficControlService;
+ private readonly UiRenderingService _uiRenderingService;
private Random _rnd;
private int _camNumber;
private int _minEntryDelayInMS = 50;
@@ -18,10 +20,11 @@ public class CameraSimulation
private int _minExitDelayInS = 4;
private int _maxExitDelayInS = 10;
- public CameraSimulation(int camNumber, ITrafficControlService trafficControlService)
+ public CameraSimulation(int camNumber, ITrafficControlService trafficControlService, UiRenderingService uiRenderingService)
{
_camNumber = camNumber;
_trafficControlService = trafficControlService;
+ _uiRenderingService = uiRenderingService;
}
public void Start()
@@ -47,10 +50,15 @@ public void Start()
{
Lane = _camNumber,
LicenseNumber = GenerateRandomLicenseNumber(),
- Timestamp = entryTimestamp
+ Timestamp = entryTimestamp,
+ BackgroundColor = GenerateRandomColor()
+
};
_trafficControlService.SendVehicleEntry(vehicleRegistered);
- Console.WriteLine($"Simulated ENTRY of vehicle with license-number {vehicleRegistered.LicenseNumber} in lane {vehicleRegistered.Lane}");
+ Debug.WriteLine($"Simulated ENTRY of vehicle with license-number {vehicleRegistered.LicenseNumber} in lane {vehicleRegistered.Lane}");
+ _uiRenderingService.AddCarToBeAnimatedInWindow(0, _camNumber, vehicleRegistered.LicenseNumber, "#FFFFFF", vehicleRegistered.BackgroundColor);
+
+
// simulate exit
TimeSpan exitDelay = TimeSpan.FromSeconds(_rnd.Next(_minExitDelayInS, _maxExitDelayInS) + _rnd.NextDouble());
@@ -58,7 +66,8 @@ public void Start()
vehicleRegistered.Timestamp = DateTime.Now;
vehicleRegistered.Lane = _rnd.Next(1, 4);
_trafficControlService.SendVehicleExit(vehicleRegistered);
- Console.WriteLine($"Simulated EXIT of vehicle with license-number {vehicleRegistered.LicenseNumber} in lane {vehicleRegistered.Lane}");
+ Debug.WriteLine($"Simulated EXIT of vehicle with license-number {vehicleRegistered.LicenseNumber} in lane {vehicleRegistered.Lane}");
+ _uiRenderingService.AddCarToBeAnimatedInWindow(1, _camNumber, vehicleRegistered.LicenseNumber, "#FFFFFF", vehicleRegistered.BackgroundColor);
});
}
catch (Exception ex)
@@ -107,6 +116,38 @@ private string GenerateRandomLicenseNumber()
return kenteken;
}
+
+ private string GenerateRandomColor()
+ {
+ int type = _rnd.Next(1, 9);
+ string mycolor = null;
+ switch (type)
+ {
+ default:
+ case 1: // silver
+ mycolor = "#A5BCB6";
+ break;
+ case 2: // blue
+ mycolor = "#1524EC";
+ break;
+ case 3: // yellow
+ mycolor = "#ffe599";
+ break;
+ case 4: // white
+ mycolor = "#FFFFFF";
+ break;
+ case 5: // red
+ mycolor = "#ea9999";
+ break;
+ case 6: // green #2
+ mycolor = "#d9ead3";
+ break;
+ }
+
+ return mycolor;
+ }
+
+
private string GenerateRandomCharacters(int aantal)
{
char[] chars = new char[aantal];
diff --git a/047-TrafficControlWithDapr/Student/Resources/Simulation/Events/VehicleRegistered.cs b/047-TrafficControlWithDapr/Student/Resources/Simulation/Events/VehicleRegistered.cs
index f45c14b349..5a5573cb2c 100644
--- a/047-TrafficControlWithDapr/Student/Resources/Simulation/Events/VehicleRegistered.cs
+++ b/047-TrafficControlWithDapr/Student/Resources/Simulation/Events/VehicleRegistered.cs
@@ -1,4 +1,5 @@
using System;
+using System.Text.Json.Serialization;
namespace Simulation.Events
{
@@ -7,5 +8,8 @@ public class VehicleRegistered
public int Lane { get; set; }
public string LicenseNumber { get; set; }
public DateTime Timestamp { get; set; }
+
+ [JsonIgnore]
+ public string BackgroundColor { get; set; }
}
}
\ No newline at end of file
diff --git a/047-TrafficControlWithDapr/Student/Resources/Simulation/Program.cs b/047-TrafficControlWithDapr/Student/Resources/Simulation/Program.cs
index d32144e595..cac784f6c3 100644
--- a/047-TrafficControlWithDapr/Student/Resources/Simulation/Program.cs
+++ b/047-TrafficControlWithDapr/Student/Resources/Simulation/Program.cs
@@ -1,7 +1,10 @@
using System;
+using System.Collections.Generic;
+using System.Linq;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
+using Pastel;
using Simulation.Proxies;
namespace Simulation
@@ -12,12 +15,43 @@ static void Main(string[] args)
{
var httpClient = new HttpClient();
int lanes = 3;
+
+ var rand = new Random();
+ int lanesOffsetWindow1 = rand.Next(0, 5);
+ int lanesOffsetWindow2 = rand.Next(0, 5);
+
+ var uiRenderingService = new UiRenderingService(Console.BufferWidth, Console.BufferHeight, lanes);
+
+ Task.Run(() =>
+ {
+ while (true)
+ {
+ uiRenderingService.RedrawScene(Console.BufferWidth - 1, Console.BufferHeight - 2, lanes, lanesOffsetWindow1, lanesOffsetWindow2);
+ Thread.Sleep(1000);
+ }
+ }
+ );
+
+ Task.Run(() =>
+ {
+
+ while (true)
+ {
+ uiRenderingService.MoveAllCarsForWindow(0);
+ uiRenderingService.MoveAllCarsForWindow(1);
+ Thread.Sleep(100);
+ }
+ }
+ );
+
+
+
CameraSimulation[] cameras = new CameraSimulation[lanes];
for (var i = 0; i < lanes; i++)
{
int camNumber = i + 1;
var trafficControlService = new HttpTrafficControlService(httpClient);
- cameras[i] = new CameraSimulation(camNumber, trafficControlService);
+ cameras[i] = new CameraSimulation(camNumber, trafficControlService, uiRenderingService);
}
Parallel.ForEach(cameras, cam => cam.Start());
diff --git a/047-TrafficControlWithDapr/Student/Resources/Simulation/Proxies/HttpTrafficControlService.cs b/047-TrafficControlWithDapr/Student/Resources/Simulation/Proxies/HttpTrafficControlService.cs
index e9bc694d35..81ea3ef261 100644
--- a/047-TrafficControlWithDapr/Student/Resources/Simulation/Proxies/HttpTrafficControlService.cs
+++ b/047-TrafficControlWithDapr/Student/Resources/Simulation/Proxies/HttpTrafficControlService.cs
@@ -1,3 +1,5 @@
+using System;
+using System.Diagnostics;
using System.Net.Http;
using System.Net.Http.Json;
using System.Text.Json;
diff --git a/047-TrafficControlWithDapr/Student/Resources/Simulation/Simulation.csproj b/047-TrafficControlWithDapr/Student/Resources/Simulation/Simulation.csproj
index 680291a4cf..d30274b5aa 100644
--- a/047-TrafficControlWithDapr/Student/Resources/Simulation/Simulation.csproj
+++ b/047-TrafficControlWithDapr/Student/Resources/Simulation/Simulation.csproj
@@ -1,8 +1,9 @@
-
Exe
- netcoreapp5.0
+ net6.0
-
+
+
+
diff --git a/047-TrafficControlWithDapr/Student/Resources/Simulation/UIRenderingService.cs b/047-TrafficControlWithDapr/Student/Resources/Simulation/UIRenderingService.cs
new file mode 100644
index 0000000000..dac407771b
--- /dev/null
+++ b/047-TrafficControlWithDapr/Student/Resources/Simulation/UIRenderingService.cs
@@ -0,0 +1,323 @@
+using Pastel;
+using Simulation.Events;
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Simulation
+{
+ public class UiRenderingService
+ {
+ private static ConcurrentDictionary> sceneMatrix = new ConcurrentDictionary>();
+
+ private const bool isDebugMatrixHighlighted = false;
+
+ private const string DEFAULT_BACKGROUND = "#000000";
+ private const string ROAD_COLOR = "#575757";
+ private const string GRAY_COLOR = "#666666";
+ private const string BLACK_COLOR = "#000000";
+ private const string WHITE_COLOR = "#FFFFFF";
+ private const string YELLOW_COLOR = "#FFFF00";
+ private const string GREEN_COLOR = "#069420";
+
+ private int _sceneWidth;
+ private int _sceneHeight;
+
+ private int _lanesCount;
+
+ private Dictionary _windowStartX = new Dictionary();
+ private Dictionary _windowSize = new Dictionary();
+
+
+ private ConcurrentDictionary> _windowCars = new ConcurrentDictionary>();
+
+ public UiRenderingService(int sceneWidth, int sceneHeight, int lanesCount)
+ {
+ _sceneWidth = sceneWidth;
+ _sceneHeight = sceneHeight;
+ _lanesCount = lanesCount;
+ }
+
+ /// returns last x position of the string's char
+ public int SaveStringIntoMatrix(int y, int startX, string input, string foregroundColor, string backgroundColor, int ignoreLowerThanX = 0, int ignoreHigherThanX = 99999, int ignoreLowerThanY = 0, int ignoreHigherThanY = 99999)
+ {
+ var chars = input.ToCharArray();
+ int x = startX;
+ foreach (var myChar in chars)
+ {
+ if (x > ignoreHigherThanX || x < ignoreLowerThanX || y < ignoreLowerThanY || y > ignoreHigherThanY)
+ {
+ x++;
+ continue;
+ }
+ if (!sceneMatrix.ContainsKey(y))
+ {
+ continue;
+ }
+
+ sceneMatrix[y][x] = myChar.ToString();
+ if (!string.IsNullOrEmpty(foregroundColor))
+ {
+ sceneMatrix[y][x] = sceneMatrix[y][x].Pastel(foregroundColor);
+ }
+
+ if (!string.IsNullOrEmpty(backgroundColor))
+ {
+ sceneMatrix[y][x] = sceneMatrix[y][x].PastelBg(backgroundColor);
+ }
+
+ x++;
+ }
+
+ return x;
+ }
+
+
+ private int RedrawSubWindow(int windowId, int startXPosition, int lanesOffset = 0)
+ {
+ _windowStartX[windowId] = startXPosition;
+
+ //heading
+ int currentY = 6;
+ string tempText = $"▼ Camera {windowId + 1} ▼";
+ int windowStartXPosition = startXPosition;
+ int windowTitlePaddingLength = (_sceneWidth / 4) - (tempText.Length / 2) - 5;
+ startXPosition = SaveStringIntoMatrix(currentY, startXPosition, "".PadRight(windowTitlePaddingLength), "#000000", GRAY_COLOR);
+
+ startXPosition = SaveStringIntoMatrix(currentY, startXPosition, tempText, BLACK_COLOR, GRAY_COLOR);
+ startXPosition = SaveStringIntoMatrix(currentY, startXPosition, "".PadRight(windowTitlePaddingLength), "#000000", GRAY_COLOR);
+
+ int windowSize = startXPosition - windowStartXPosition;
+
+ currentY++;
+
+ //grass
+ SaveStringIntoMatrix(currentY, windowStartXPosition, "".PadRight(windowSize), GREEN_COLOR, GREEN_COLOR);
+ currentY++;
+
+ SaveStringIntoMatrix(currentY, windowStartXPosition, "".PadRight(windowSize), ROAD_COLOR, ROAD_COLOR);
+ currentY++;
+
+ //highway divider
+ SaveStringIntoMatrix(currentY, windowStartXPosition, "".PadRight(windowSize), YELLOW_COLOR, YELLOW_COLOR);
+ currentY++;
+
+ //lanes
+
+ int lanesStartY = currentY;
+
+ for (int i = 0; i < _lanesCount; i++)
+ {
+ SaveStringIntoMatrix(currentY, windowStartXPosition, "".PadRight(windowSize), BLACK_COLOR, ROAD_COLOR);
+ currentY++;
+ SaveStringIntoMatrix(currentY, windowStartXPosition, "".PadRight(windowSize), BLACK_COLOR, ROAD_COLOR);
+ currentY++;
+ SaveStringIntoMatrix(currentY, windowStartXPosition, "".PadRight(windowSize), BLACK_COLOR, ROAD_COLOR);
+ currentY++;
+
+
+ if (i < _lanesCount - 1)
+ {
+ //lane dividers
+ int currentX = windowStartXPosition - lanesOffset;
+
+ for (int j = 0; j < (windowSize / 11) + 1; j++)
+ {
+ SaveStringIntoMatrix(currentY, currentX, "".PadRight(6), BLACK_COLOR, WHITE_COLOR, windowStartXPosition, (windowStartXPosition + windowSize - 1));
+ currentX += 6;
+ SaveStringIntoMatrix(currentY, currentX, "".PadRight(5), BLACK_COLOR, ROAD_COLOR, windowStartXPosition, (windowStartXPosition + windowSize - 1));
+ currentX += 5;
+ }
+
+ currentY++;
+ }
+ }
+
+
+ //highway divider
+ SaveStringIntoMatrix(currentY, windowStartXPosition, "".PadRight(windowSize), YELLOW_COLOR, YELLOW_COLOR);
+ currentY++;
+
+ SaveStringIntoMatrix(currentY, windowStartXPosition, "".PadRight(windowSize), ROAD_COLOR, ROAD_COLOR);
+ currentY++;
+
+ //grass
+ SaveStringIntoMatrix(currentY, windowStartXPosition, "".PadRight(windowSize), GREEN_COLOR, GREEN_COLOR);
+ currentY++;
+
+ _windowSize[windowId] = windowSize;
+
+
+ //draw cars
+
+ if (_windowCars.ContainsKey(windowId))
+ {
+ Parallel.For(1, _lanesCount + 1, (laneId, state) =>
+ {
+ int currentFreeLanePosition = windowStartXPosition;
+ foreach (var car in _windowCars[windowId].Where(c => c.Value.Lane.Equals(laneId)).OrderBy(c => c.Value.PositionOnCameraImage))
+ {
+
+ int carXPosition = car.Value.PositionOnCameraImage + currentFreeLanePosition;
+ int carYPosition = 10 + (car.Value.Lane - 1) * 4;
+
+ SaveStringIntoMatrix(carYPosition, carXPosition, "┌──────────┐", BLACK_COLOR, car.Value.BackgroundColor, _windowStartX[windowId], (_windowStartX[windowId] + _windowSize[windowId] - 1));
+ SaveStringIntoMatrix(carYPosition + 1, carXPosition, $"| {car.Value.LicenseNumber} |", BLACK_COLOR, car.Value.BackgroundColor, _windowStartX[windowId], (_windowStartX[windowId] + _windowSize[windowId] - 1));
+ SaveStringIntoMatrix(carYPosition + 2, carXPosition, "└──────────┘", BLACK_COLOR, car.Value.BackgroundColor, _windowStartX[windowId], (_windowStartX[windowId] + _windowSize[windowId] - 1));
+
+ currentFreeLanePosition += 20;
+ }
+ });
+ }
+
+ return windowSize;
+ }
+
+ public void AddCarToBeAnimatedInWindow(int windowId, int laneId, string licenseNumber, string foregroundColor, string backgroundColor)
+ {
+ //if(!_windowsStartX.ContainsKey(windowId))
+ // return;
+ if (!_windowCars.ContainsKey(windowId))
+ {
+ _windowCars.TryAdd(windowId, new ConcurrentDictionary());
+ }
+
+ _windowCars[windowId].TryAdd(licenseNumber, new CarToBeRendered()
+ {
+ Lane = laneId,
+ LicenseNumber = licenseNumber,
+ PositionOnCameraImage = 0,
+ BackgroundColor = backgroundColor,
+
+ });
+ }
+
+ public void RedrawScene(int sceneWidth, int sceneHeight, int lanesCount, int lanes1Offset = 0, int lanes2Offset = 0)
+ {
+
+ if (sceneWidth < 70)
+ {
+ Console.Clear();
+ Console.WriteLine("Please resize the window to 70 cols width at minimum.");
+ return;
+ }
+
+ if (sceneHeight < 22)
+ {
+ Console.Clear();
+ Console.WriteLine("Please resize the window to 22 lines height at minimum.");
+ return;
+ }
+
+ _sceneWidth = sceneWidth;
+ _sceneHeight = sceneHeight;
+
+ string tempText;
+ int startXPosition;
+
+ for (int y = 0; y < sceneHeight; y++)
+ {
+ sceneMatrix[y] = new Dictionary();
+ }
+
+
+ // header
+ tempText = " __________________________________________________________________ ";
+ SaveStringIntoMatrix(0, (sceneWidth / 2) - (tempText.Length / 2), tempText, GRAY_COLOR, DEFAULT_BACKGROUND);
+
+ tempText = "| |";
+ SaveStringIntoMatrix(1, (sceneWidth / 2) - (tempText.Length / 2), tempText, GRAY_COLOR, DEFAULT_BACKGROUND);
+
+ tempText = "| What The Hack - Traffic Control with Dapr - Traffic simulator |";
+ SaveStringIntoMatrix(2, (sceneWidth / 2) - (tempText.Length / 2), tempText, GRAY_COLOR, DEFAULT_BACKGROUND);
+
+ tempText = "|__________________________________________________________________|";
+ SaveStringIntoMatrix(3, (sceneWidth / 2) - (tempText.Length / 2), tempText, GRAY_COLOR, DEFAULT_BACKGROUND);
+
+
+ // window #0
+ int windowSize = RedrawSubWindow(0, 1, lanes1Offset);
+
+
+ // window #1
+ RedrawSubWindow(1, (sceneWidth - windowSize - 1), lanes2Offset);
+
+
+ // windows separator
+ for (int my = 6; my < sceneHeight; my++)
+ {
+ startXPosition = SaveStringIntoMatrix(my, (sceneWidth / 2) - 1, " ", GRAY_COLOR, GRAY_COLOR);
+ }
+
+
+ // Final scene render
+ string scene = "";
+ for (int y = 0; y < sceneHeight; y++)
+ {
+
+ for (int x = 0; x < sceneWidth; x++)
+ {
+ if (sceneMatrix.ContainsKey(y) && sceneMatrix[y].ContainsKey(x))
+ {
+ scene += sceneMatrix[y][x];
+ }
+ else
+ {
+ if (isDebugMatrixHighlighted)
+ {
+ scene += " ".PastelBg("#FFFF00");
+ }
+ else
+ {
+ scene += " ";
+ }
+ }
+ }
+
+ scene += "\n";
+
+ }
+
+ Console.Clear();
+ Console.Write(scene);
+
+ }
+
+
+
+ public void MoveAllCarsForWindow(int windowId)
+ {
+ if (!_windowCars.ContainsKey(windowId)) {
+ return;
+ }
+
+ Parallel.For(1, _lanesCount + 1, (laneId, state) =>
+ {
+ foreach (var car in _windowCars[windowId].Where(c => c.Value.Lane.Equals(laneId)).OrderBy(c => c.Value.PositionOnCameraImage))
+ {
+ car.Value.PositionOnCameraImage += 1;
+
+ if (car.Value.PositionOnCameraImage > 30)
+ {
+ CarToBeRendered carToBeDeleted;
+ _windowCars[windowId].Remove(car.Key, out carToBeDeleted);
+
+ }
+ }
+ });
+ }
+
+ }
+
+
+ public class CarToBeRendered
+ {
+ public int Lane { get; set; }
+ public string LicenseNumber { get; set; }
+ public int PositionOnCameraImage { get; set; }
+ public string BackgroundColor { get; set; }
+ }
+}
\ No newline at end of file