diff --git a/Assets/Scripts/ParkingManager.cs b/Assets/Scripts/ParkingManager.cs index 3fd14bf..ed4eb93 100644 --- a/Assets/Scripts/ParkingManager.cs +++ b/Assets/Scripts/ParkingManager.cs @@ -37,7 +37,9 @@ namespace Parking private bool _emergencyActivated; private int _initialConfigurationSpotCount; + private int[,] _initialSolution; private int[] _rejectedDrivers = {0, 0, 0, 0}; + private List _spotPrefabs; private void Awake() { @@ -46,14 +48,17 @@ namespace Parking private void Start() { + _spotPrefabs = new List {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,11 +137,22 @@ 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}"); - driver.Rejected = true; - _rejectedDrivers[(int) driver.Size]++; - rejectedText.text = $"Małe: {_rejectedDrivers[0]} Średnie: {_rejectedDrivers[1]} " + - $"Duże: {_rejectedDrivers[2]}"; + 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) { @@ -145,8 +164,21 @@ namespace Parking 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() @@ -230,7 +262,7 @@ namespace Parking driver.GameObject = Instantiate(carPrefab); driver.GameObject.GetComponentInChildren().text = driver.Number.ToString(); driver.GameObject.GetComponentInChildren().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 {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,54 +287,85 @@ 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(); - float diff = (_spotHeights[(int) spot.Size] - _spotHeights[size]) / 2.0f; - if (!spot.AlignToTop) - diff *= -1; + // 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); - 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; - 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: ; - } + 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) + 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(); + 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() { int[] freeSpots = {0, 0, 0, 0}; @@ -314,18 +376,15 @@ namespace Parking return freeSpots; } - private List GetNextCars(int n) + private List GetNextCars(int steps) { var nextCars = new List(); - TimeSpan updatedTime = _currentTime + TimeSpan.FromMinutes(stepTime); - while (nextCars.Count < n && updatedTime < EndTime) { - foreach (Driver driver in DataImporter.Drivers) - if (updatedTime <= driver.Times[1].TimeOfDay && - updatedTime > driver.Times[0].TimeOfDay && - !driver.Parked && !driver.Rejected && !nextCars.Contains(driver)) - nextCars.Add(driver); - updatedTime += TimeSpan.FromMinutes(stepTime); - } + 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.Add(driver); 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> 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++) {