Added parallel reconfiguration and other improvements

This commit is contained in:
Dawid Pietrykowski 2022-09-06 23:20:53 +02:00
parent 7571ca1d5d
commit 8a01e3f3bd

View File

@ -37,7 +37,9 @@ namespace Parking
private bool _emergencyActivated;
private int _initialConfigurationSpotCount;
private int[,] _initialSolution;
private int[] _rejectedDrivers = {0, 0, 0, 0};
private List<GameObject> _spotPrefabs;
private void Awake()
{
@ -46,14 +48,17 @@ namespace Parking
private void Start()
{
_spotPrefabs = new List<GameObject> {spotPrefabA, spotPrefabB, spotPrefabC, spotPrefabD};
timeText.text = _currentTime.ToString();
rejectedText.text = $"Małe: {_rejectedDrivers[0]} Średnie: {_rejectedDrivers[1]} " +
$"Duże: {_rejectedDrivers[2]}";
GenerateEmergencyPlan();
DataImporter.ReadFile("Assets/Data/Tablica4.csv");
DataImporter.ReadFile("Assets/Data/Tablica3.csv");
InitialConfigurationGenerator generator = new();
ArrangeSpots(generator.FindSolution());
_initialSolution = generator.FindSolution();
ArrangeSpots(_initialSolution);
ReserveInitialSpots();
}
@ -106,6 +111,7 @@ namespace Parking
mainPlanContainer.gameObject.SetActive(false);
}
else {
ArrangeSpots(_initialSolution);
ReserveInitialSpots();
ResetDrivers();
}
@ -118,6 +124,8 @@ namespace Parking
if (_emergencyActivated)
return;
ReconfigureSpots();
foreach (Driver driver in DataImporter.Drivers) {
// TODO: Check if car can stay before other reservation - may not work for priority-based reservations
bool triesToPark = _currentTime <= driver.Times[3].TimeOfDay &&
@ -129,13 +137,24 @@ namespace Parking
&& !driver.Parked && !driver.Rejected && _currentTime <= driver.Times[3].TimeOfDay;
if (triesToPark && !driver.Parked && !driver.Rejected) {
if (!PlaceCarOnParking(driver)) {
Debug.Log($"Placing failed for car {driver.Number}");
if (TryReconfigureSpotForSize(driver.Size)) {
if (!PlaceCarOnParking(driver)) {
Debug.Log($"Placing failed for car {driver.Number} size {driver.Size}");
driver.Rejected = true;
_rejectedDrivers[(int) driver.Size]++;
rejectedText.text = $"Małe: {_rejectedDrivers[0]} Średnie: {_rejectedDrivers[1]} " +
$"Duże: {_rejectedDrivers[2]}";
}
}
else {
Debug.Log($"Placing failed for car {driver.Number} size {driver.Size}");
driver.Rejected = true;
_rejectedDrivers[(int) driver.Size]++;
rejectedText.text = $"Małe: {_rejectedDrivers[0]} Średnie: {_rejectedDrivers[1]} " +
$"Duże: {_rejectedDrivers[2]}";
}
}
}
else if (leftTheParking) {
driver.Spot.Reserved = false;
driver.Reset();
@ -146,7 +165,20 @@ namespace Parking
}
}
ReconfigureSpots();
UpdateCounts();
}
private void UpdateCounts()
{
int[] counts = {0, 0, 0, 0};
for (int i = 0; i < _spotMap.Count; i++)
for (int j = 0; j < _spotMap[i].Count; j++)
counts[(int) _spotMap[i][j].Size]++;
string countsString = $"Małe: {counts[0]} Średnie: {counts[1]} Duże: {counts[2]} " +
$"Suma: {counts.Sum()}";
UpdateText(countsString);
}
private void ResetDrivers()
@ -230,7 +262,7 @@ namespace Parking
driver.GameObject = Instantiate(carPrefab);
driver.GameObject.GetComponentInChildren<TextMeshProUGUI>().text = driver.Number.ToString();
driver.GameObject.GetComponentInChildren<TextMeshProUGUI>().transform.rotation =
Quaternion.Euler(new Vector3(0, 0, (spot.Flipped ? 180 : 0) + (!spot.Perpendicular ? 90 : 0)));
Quaternion.Euler(new Vector3(0, 0, (spot.Flipped ? 180 : 0) + (!spot.Perpendicular ? -90 : 0)));
driver.GameObject.transform.rotation =
Quaternion.Euler(new Vector3(0, 0, (spot.Flipped ? 180 : 0) + (!spot.Perpendicular ? 90 : 0)));
driver.GameObject.transform.position = spot.GameObject.transform.position;
@ -245,9 +277,8 @@ namespace Parking
private void ReconfigureSpots()
{
var prefabs = new List<GameObject> {spotPrefabA, spotPrefabB, spotPrefabC};
int[] freeSpots = GetFreeSpotCount();
var nextCars = GetNextCars(10);
var nextCars = GetNextCars(1);
int[] plannedSpots = {0, 0, 0, 0};
foreach (Driver driver in nextCars)
plannedSpots[(int) driver.Size]++;
@ -256,18 +287,32 @@ namespace Parking
for (int i = 0; i < neededSpots.Length; i++)
neededSpots[i] = Math.Max(plannedSpots[i] - freeSpots[i], 0);
if (neededSpots.Sum() > 5) {
if (neededSpots.Sum() > 1) {
Debug.Log($"Needed spots = {neededSpots[0]} {neededSpots[1]} {neededSpots[2]} {neededSpots[3]}");
Debug.Log("Attempting reconfiguration...");
for (int size = 0; size < 3; size++) {
bool foundReplacement = true;
while (foundReplacement && neededSpots[size] != 0) {
foundReplacement = false;
foreach (var t in _spotMap)
foreach (Spot spot in t)
if ((int) spot.Size > size && spot.Free && spot.Lane != 3 && spot.Size != Size.D) {
foundReplacement = true;
var spotlessCars = new List<Driver>();
// Filter drivers by assigning free space
foreach (Driver nextCar in nextCars)
if (freeSpots[(int) nextCar.Size] != 0)
freeSpots[(int) nextCar.Size]--;
else
spotlessCars.Add(nextCar);
foreach (Driver nextCar in spotlessCars) {
TryReconfigureSpotForSize(nextCar.Size);
}
}
}
private bool TryReconfigureSpotForSize(Size newSize)
{
foreach (var currentLaneSpots in _spotMap)
foreach (Spot spot in currentLaneSpots) {
if (spot.Size > newSize && spot.Free && spot.Size != Size.D && !spot.Reserved) {
int size = (int) newSize;
float diff = (_spotHeights[(int) spot.Size] - _spotHeights[size]) / 2.0f;
if (!spot.AlignToTop)
@ -284,24 +329,41 @@ namespace Parking
spot.Reserved = false;
Vector3 offset;
if (spot.Perpendicular)
offset = new Vector3(0, diff, 0);
else
offset = new Vector3(-diff, 0, 0);
Vector3 offset = spot.Perpendicular ? new Vector3(0, diff, 0) : new Vector3(-diff, 0, 0);
Vector3 newPosition = position + offset;
if (!spot.Perpendicular) {
var allBorders = new List<float>();
foreach (Spot spot1 in currentLaneSpots) {
if (spot1 == spot)
continue;
Vector3 spotPosition = spot1.GameObject.transform.position;
float sizeOffset = _spotHeights[(int) spot1.Size] / 2.0f;
allBorders.Add(spotPosition.x + sizeOffset);
allBorders.Add(spotPosition.x - sizeOffset);
}
allBorders.Sort();
foreach (float adjacentBorder in allBorders)
if (adjacentBorder > position.x) {
newPosition = new Vector3(adjacentBorder -
_spotHeights[size] / 2.0f,
newPosition.y, newPosition.z);
break;
}
}
// TODO: check how much space to right to push
spot.GameObject = Instantiate(prefabs[size],
position + offset, rotation, mainPlanContainer);
spot.GameObject = Instantiate(_spotPrefabs[size],
newPosition, rotation, mainPlanContainer);
goto whileEnd;
return true;
}
}
whileEnd: ;
}
}
}
return false;
}
private int[] GetFreeSpotCount()
@ -314,18 +376,15 @@ namespace Parking
return freeSpots;
}
private List<Driver> GetNextCars(int n)
private List<Driver> GetNextCars(int steps)
{
var nextCars = new List<Driver>();
TimeSpan updatedTime = _currentTime + TimeSpan.FromMinutes(stepTime);
while (nextCars.Count < n && updatedTime < EndTime) {
TimeSpan updatedTime = _currentTime + TimeSpan.FromMinutes(stepTime * steps);
foreach (Driver driver in DataImporter.Drivers)
if (updatedTime <= driver.Times[1].TimeOfDay &&
updatedTime > driver.Times[0].TimeOfDay &&
!driver.Parked && !driver.Rejected && !nextCars.Contains(driver))
updatedTime >= driver.Times[0].TimeOfDay &&
!driver.Parked && !driver.Rejected)
nextCars.Add(driver);
updatedTime += TimeSpan.FromMinutes(stepTime);
}
return nextCars;
}
@ -458,7 +517,7 @@ namespace Parking
for (int j = 0; j < emergencyMap[i]; j++)
if (i == 0) {
Vector3 position = new(currentX, currentY + 2.25f / 2.0f, 0);
spawnedSpot = Instantiate(Instance.spotPrefabC, position,
Instantiate(Instance.spotPrefabC, position,
Quaternion.Euler(new Vector3(0, 0, 90)), emergencyPlanContainer);
currentX -= 5;
@ -481,6 +540,13 @@ namespace Parking
private List<List<Spot>> GenerateSpotMap(int[,] spotsCreated)
{
foreach (var list in _spotMap) {
foreach (Spot spot in list)
if (spot.GameObject != null)
Destroy(spot.GameObject);
list.Clear();
}
for (int i = 0; i < 4; i++)
for (int j = 0; j < spotsCreated.GetLength(1); j++)
for (int k = 0; k < spotsCreated[i, j]; k++) {