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