2022-08-25 17:58:26 +02:00
|
|
|
using System;
|
|
|
|
using System.Collections.Generic;
|
2022-08-28 22:42:21 +02:00
|
|
|
using System.Linq;
|
2022-08-25 17:58:26 +02:00
|
|
|
using TMPro;
|
|
|
|
using UnityEngine;
|
|
|
|
|
2022-08-31 20:50:59 +02:00
|
|
|
namespace Parking
|
2022-08-25 17:58:26 +02:00
|
|
|
{
|
2022-08-31 20:50:59 +02:00
|
|
|
public class ParkingManager : MonoBehaviour
|
2022-08-28 22:42:21 +02:00
|
|
|
{
|
2022-08-31 20:50:59 +02:00
|
|
|
public const float Width = 68;
|
|
|
|
public const float Height = 29;
|
2022-08-28 22:42:21 +02:00
|
|
|
|
2022-08-31 20:50:59 +02:00
|
|
|
public static ParkingManager Instance;
|
2022-08-28 22:42:21 +02:00
|
|
|
|
2022-08-31 20:50:59 +02:00
|
|
|
[SerializeField] private int stepTime = 15;
|
|
|
|
[SerializeField] private TextMeshProUGUI timeText;
|
|
|
|
[SerializeField] public TextMeshProUGUI countsText;
|
2022-09-03 00:23:15 +02:00
|
|
|
[SerializeField] public TextMeshProUGUI rejectedText;
|
2022-08-31 20:50:59 +02:00
|
|
|
[SerializeField] public GameObject spotPrefabA;
|
|
|
|
[SerializeField] public GameObject spotPrefabB;
|
|
|
|
[SerializeField] public GameObject spotPrefabC;
|
2022-08-31 21:19:20 +02:00
|
|
|
[SerializeField] public GameObject spotPrefabD;
|
2022-09-01 22:31:57 +02:00
|
|
|
[SerializeField] public GameObject carPrefab;
|
2022-08-28 22:42:21 +02:00
|
|
|
|
2022-08-31 20:50:59 +02:00
|
|
|
private readonly float[] _spotHeights = {3.5f, 4f, 5f, 7.5f};
|
2022-08-28 22:42:21 +02:00
|
|
|
|
2022-09-03 00:23:15 +02:00
|
|
|
public readonly List<List<Spot>> SpotMap = new()
|
|
|
|
{new List<Spot>(), new List<Spot>(), new List<Spot>(), new List<Spot>()};
|
|
|
|
|
2022-09-03 21:27:31 +02:00
|
|
|
private static readonly TimeSpan StartTime = TimeSpan.FromHours(5) + TimeSpan.FromMinutes(45);
|
|
|
|
private static readonly TimeSpan EndTime = TimeSpan.FromHours(17) + TimeSpan.FromMinutes(15);
|
|
|
|
private static TimeSpan _currentTime = StartTime;
|
|
|
|
private int[] _rejectedDrivers = {0, 0, 0, 0};
|
2022-08-28 22:42:21 +02:00
|
|
|
|
2022-08-31 20:50:59 +02:00
|
|
|
private void Awake()
|
2022-08-28 22:42:21 +02:00
|
|
|
{
|
2022-08-31 20:50:59 +02:00
|
|
|
Instance = this;
|
2022-08-28 22:42:21 +02:00
|
|
|
}
|
|
|
|
|
2022-08-31 20:50:59 +02:00
|
|
|
private void Start()
|
|
|
|
{
|
|
|
|
timeText.text = _currentTime.ToString();
|
2022-09-03 21:27:31 +02:00
|
|
|
rejectedText.text = $"Małe: {_rejectedDrivers[0]} Średnie: {_rejectedDrivers[1]} " +
|
|
|
|
$"Duże: {_rejectedDrivers[2]}";
|
2022-08-31 20:50:59 +02:00
|
|
|
DataImporter.ReadFile("Assets/Data/v1.csv");
|
|
|
|
Debug.Log(DataImporter.Drivers);
|
|
|
|
InitialConfigurationGenerator generator = new();
|
|
|
|
ArrangeSpots(generator.FindSolution());
|
2022-08-28 22:42:21 +02:00
|
|
|
}
|
2022-08-29 23:01:18 +02:00
|
|
|
|
2022-08-31 20:50:59 +02:00
|
|
|
public void AdvanceTime()
|
|
|
|
{
|
2022-09-03 21:27:31 +02:00
|
|
|
_currentTime += TimeSpan.FromMinutes(stepTime);
|
|
|
|
if (_currentTime > EndTime)
|
|
|
|
{
|
|
|
|
_currentTime = StartTime;
|
|
|
|
ResetDrivers();
|
|
|
|
_rejectedDrivers = new int[]{0, 0,0 ,0};
|
|
|
|
rejectedText.text = $"Małe: {_rejectedDrivers[0]} Średnie: {_rejectedDrivers[1]} " +
|
|
|
|
$"Duże: {_rejectedDrivers[2]}";
|
|
|
|
timeText.text = _currentTime.ToString();
|
|
|
|
return;
|
|
|
|
}
|
2022-08-31 20:50:59 +02:00
|
|
|
timeText.text = _currentTime.ToString();
|
2022-09-01 22:31:57 +02:00
|
|
|
foreach (Driver driver in DataImporter.Drivers)
|
2022-09-03 00:23:15 +02:00
|
|
|
if (_currentTime <= driver.Times[1].TimeOfDay && _currentTime > driver.Times[0].TimeOfDay &&
|
|
|
|
!driver.Parked && !driver.Rejected)
|
2022-09-01 22:31:57 +02:00
|
|
|
{
|
2022-09-03 00:23:15 +02:00
|
|
|
if (!PlaceCarOnParking(driver))
|
|
|
|
{
|
2022-09-03 21:27:31 +02:00
|
|
|
Debug.Log($"Placing failed for car {driver.Number}");
|
2022-09-03 00:23:15 +02:00
|
|
|
driver.Rejected = true;
|
2022-09-03 21:27:31 +02:00
|
|
|
_rejectedDrivers[(int)driver.Size]++;
|
|
|
|
rejectedText.text = $"Małe: {_rejectedDrivers[0]} Średnie: {_rejectedDrivers[1]} " +
|
|
|
|
$"Duże: {_rejectedDrivers[2]}";
|
2022-09-03 00:23:15 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (_currentTime > driver.Times[1].TimeOfDay &&
|
|
|
|
driver.Parked)
|
2022-09-01 22:31:57 +02:00
|
|
|
{
|
2022-09-03 21:27:31 +02:00
|
|
|
driver.Reset();
|
2022-09-01 22:31:57 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-09-03 21:27:31 +02:00
|
|
|
private void ResetDrivers()
|
|
|
|
{
|
|
|
|
foreach (Driver driver in DataImporter.Drivers)
|
|
|
|
{
|
|
|
|
driver.Reset();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-09-03 00:23:15 +02:00
|
|
|
private bool PlaceCarOnParking(Driver driver)
|
2022-09-01 22:31:57 +02:00
|
|
|
{
|
2022-09-03 00:23:15 +02:00
|
|
|
for (var i = 0; i < SpotMap.Count; i++)
|
|
|
|
foreach (Spot spot in SpotMap[i])
|
|
|
|
if (spot.Size == driver.Size && spot.Free &&
|
|
|
|
(spot.ParkingDirection == driver.ParkingPreference ||
|
|
|
|
spot.ParkingDirection == ParkingPreference.Any))
|
|
|
|
{
|
|
|
|
spot.Free = false;
|
|
|
|
driver.Spot = spot;
|
|
|
|
driver.Parked = true;
|
|
|
|
driver.GameObject = Instantiate(carPrefab, spot.GameObject.transform, true);
|
2022-09-03 21:27:31 +02:00
|
|
|
driver.GameObject.GetComponentInChildren<TextMeshProUGUI>().text = driver.Number.ToString();
|
|
|
|
driver.GameObject.GetComponentInChildren<TextMeshProUGUI>().transform.rotation =
|
|
|
|
Quaternion.Euler(new Vector3(0, 0, spot.Flipped ? 180 : 0));
|
2022-09-03 00:23:15 +02:00
|
|
|
driver.GameObject.transform.position = spot.GameObject.transform.position;
|
|
|
|
driver.GameObject.transform.rotation =
|
|
|
|
Quaternion.Euler(new Vector3(0, 0, spot.Flipped ? 180 : 0));
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (var i = 0; i < SpotMap.Count; i++)
|
2022-09-01 22:31:57 +02:00
|
|
|
foreach (Spot spot in SpotMap[i])
|
|
|
|
if (spot.Size == driver.Size && spot.Free)
|
|
|
|
{
|
|
|
|
spot.Free = false;
|
|
|
|
driver.Spot = spot;
|
|
|
|
driver.Parked = true;
|
|
|
|
driver.GameObject = Instantiate(carPrefab, spot.GameObject.transform, true);
|
2022-09-03 21:27:31 +02:00
|
|
|
driver.GameObject.GetComponentInChildren<TextMeshProUGUI>().text = driver.Number.ToString();
|
|
|
|
driver.GameObject.GetComponentInChildren<TextMeshProUGUI>().transform.rotation =
|
|
|
|
Quaternion.Euler(new Vector3(0, 0, spot.Flipped ? 180 : 0));
|
2022-09-01 22:31:57 +02:00
|
|
|
driver.GameObject.transform.position = spot.GameObject.transform.position;
|
2022-09-03 00:23:15 +02:00
|
|
|
driver.GameObject.transform.rotation =
|
|
|
|
Quaternion.Euler(new Vector3(0, 0, spot.Flipped ? 180 : 0));
|
|
|
|
|
|
|
|
return true;
|
2022-09-01 22:31:57 +02:00
|
|
|
}
|
2022-09-03 00:23:15 +02:00
|
|
|
|
|
|
|
return false;
|
2022-08-31 20:50:59 +02:00
|
|
|
}
|
2022-08-29 23:01:18 +02:00
|
|
|
|
2022-08-31 20:50:59 +02:00
|
|
|
public void UpdateText(string text)
|
2022-08-29 23:01:18 +02:00
|
|
|
{
|
2022-08-31 20:50:59 +02:00
|
|
|
countsText.text = text;
|
2022-08-29 23:01:18 +02:00
|
|
|
}
|
2022-08-29 23:32:16 +02:00
|
|
|
|
2022-09-03 21:27:31 +02:00
|
|
|
private void ReconfigureSpots()
|
|
|
|
{
|
|
|
|
int[] freeSpots = GetFreeSpotCount();
|
|
|
|
List<Driver> nextCars = GetNextCars(10);
|
|
|
|
int[] plannedSpots = new[] {0, 0, 0, 0};
|
|
|
|
foreach (Driver driver in nextCars)
|
|
|
|
plannedSpots[(int)driver.Size]++;
|
|
|
|
|
|
|
|
int[] neededSpots = new[] {0, 0, 0, 0};
|
|
|
|
|
|
|
|
for (int i = 0; i < neededSpots.Length; i++)
|
|
|
|
neededSpots[i] = Math.Max(freeSpots[i] - plannedSpots[i], 0);
|
|
|
|
if (neededSpots.Max() > 0)
|
|
|
|
{
|
|
|
|
Debug.Log($"Needed spots = {neededSpots[0]} {neededSpots[1]} {neededSpots[2]} {neededSpots[3]}");
|
|
|
|
Debug.Log($"Attempting reconfiguration...");
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
private int[] GetFreeSpotCount()
|
|
|
|
{
|
|
|
|
int[] freeSpots = new[] {0, 0, 0, 0};
|
|
|
|
foreach (var t in SpotMap)
|
|
|
|
foreach (Spot spot in t)
|
|
|
|
if (spot.Free)
|
|
|
|
freeSpots[(int)spot.Size]++;
|
|
|
|
return freeSpots;
|
|
|
|
}
|
|
|
|
|
|
|
|
private List<Driver> GetNextCars(int n)
|
|
|
|
{
|
|
|
|
List<Driver> nextCars = new List<Driver>();
|
|
|
|
TimeSpan updatedTime = _currentTime + TimeSpan.FromMinutes(stepTime);
|
|
|
|
while (nextCars.Count < n && updatedTime < EndTime)
|
|
|
|
{
|
|
|
|
foreach (Driver driver in DataImporter.Drivers)
|
|
|
|
if (_currentTime + updatedTime <= driver.Times[1].TimeOfDay &&
|
|
|
|
_currentTime > driver.Times[0].TimeOfDay &&
|
|
|
|
!driver.Parked && !driver.Rejected && !nextCars.Contains(driver))
|
|
|
|
{
|
|
|
|
nextCars.Add(driver);
|
|
|
|
}
|
|
|
|
updatedTime += TimeSpan.FromMinutes(stepTime);
|
|
|
|
}
|
|
|
|
|
|
|
|
return nextCars;
|
|
|
|
}
|
|
|
|
|
2022-08-31 20:50:59 +02:00
|
|
|
private void ArrangeSpots(int[,] spotsCreated)
|
2022-08-29 23:01:18 +02:00
|
|
|
{
|
2022-08-31 20:50:59 +02:00
|
|
|
var spotMap = GenerateSpotMap(spotsCreated);
|
|
|
|
|
|
|
|
var maxP3 = _spotHeights[(int) spotMap[2].Max().Size];
|
|
|
|
var maxP2 = _spotHeights[(int) spotMap[1].Max().Size];
|
|
|
|
|
|
|
|
for (var i = 0; i < 4; i++)
|
2022-08-29 23:01:18 +02:00
|
|
|
{
|
2022-08-31 20:50:59 +02:00
|
|
|
float currentY;
|
|
|
|
switch (i)
|
2022-08-29 23:01:18 +02:00
|
|
|
{
|
2022-08-31 20:50:59 +02:00
|
|
|
case 0:
|
|
|
|
currentY = -Height / 2.0f + 2f;
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
currentY = Height / 2 - 5.5f - 5f - maxP3 / 2.0f - maxP2;
|
2022-08-29 23:01:18 +02:00
|
|
|
break;
|
2022-08-31 20:50:59 +02:00
|
|
|
case 2:
|
|
|
|
currentY = Height / 2 - 5.5f - 5f - maxP3 / 2.0f;
|
2022-08-29 23:01:18 +02:00
|
|
|
break;
|
2022-08-31 20:50:59 +02:00
|
|
|
case 3:
|
|
|
|
currentY = Height / 2.0f - 2f;
|
2022-08-29 23:01:18 +02:00
|
|
|
break;
|
|
|
|
default:
|
2022-08-31 20:50:59 +02:00
|
|
|
currentY = -10;
|
2022-08-29 23:01:18 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2022-08-31 20:50:59 +02:00
|
|
|
float currentX;
|
|
|
|
if (i != 0) currentX = -Width / 2f - 2.25f / 2f + 2.25f;
|
|
|
|
else currentX = -Width / 2f + 5.5f - 2.25f / 2f + 2.25f + 1.75f;
|
2022-08-28 22:42:21 +02:00
|
|
|
|
2022-08-31 20:50:59 +02:00
|
|
|
var flipped = false;
|
2022-09-03 00:23:15 +02:00
|
|
|
var parkingFromTop = i % 2 != 0;
|
2022-08-28 22:42:21 +02:00
|
|
|
|
2022-08-31 20:50:59 +02:00
|
|
|
for (var j = 0; j < spotMap[i].Count; j++)
|
|
|
|
{
|
|
|
|
spotMap[i][j].Flipped = flipped;
|
|
|
|
var alignTop = i % 2 != 0;
|
|
|
|
switch (spotMap[i][j].Size)
|
|
|
|
{
|
|
|
|
case Size.A:
|
|
|
|
spotMap[i][j].GameObject = Instantiate(Instance.spotPrefabA);
|
|
|
|
spotMap[i][j].GameObject.transform.position = new Vector3(currentX, currentY, 0);
|
|
|
|
break;
|
|
|
|
case Size.B:
|
|
|
|
spotMap[i][j].GameObject = Instantiate(Instance.spotPrefabB);
|
|
|
|
spotMap[i][j].GameObject.transform.position =
|
|
|
|
new Vector3(currentX, currentY + (alignTop ? -1 : 1) * 0.25f, 0);
|
|
|
|
break;
|
|
|
|
case Size.C:
|
|
|
|
spotMap[i][j].GameObject = Instantiate(Instance.spotPrefabC);
|
|
|
|
spotMap[i][j].GameObject.transform.position =
|
|
|
|
new Vector3(currentX, currentY + (alignTop ? -1 : 1) * 0.5f, 0);
|
|
|
|
break;
|
2022-08-31 21:19:20 +02:00
|
|
|
case Size.D:
|
|
|
|
spotMap[i][j].GameObject = Instantiate(Instance.spotPrefabD);
|
|
|
|
spotMap[i][j].GameObject.transform.position =
|
2022-09-03 00:23:15 +02:00
|
|
|
new Vector3(currentX, currentY - 2.0f, 0);
|
2022-08-31 21:19:20 +02:00
|
|
|
break;
|
2022-08-31 20:50:59 +02:00
|
|
|
}
|
2022-09-03 00:23:15 +02:00
|
|
|
|
2022-09-01 22:31:57 +02:00
|
|
|
spotMap[i][j].GameObject.transform.rotation =
|
|
|
|
Quaternion.Euler(new Vector3(0, 0, spotMap[i][j].Flipped ? 180 : 0));
|
2022-08-31 20:50:59 +02:00
|
|
|
|
2022-09-03 00:23:15 +02:00
|
|
|
var frontalParking = !parkingFromTop ^ flipped;
|
|
|
|
spotMap[i][j].ParkingDirection = frontalParking ? ParkingPreference.Front : ParkingPreference.Back;
|
|
|
|
|
2022-08-31 20:50:59 +02:00
|
|
|
currentX += 2.25f;
|
|
|
|
|
|
|
|
flipped = !flipped;
|
2022-08-28 22:42:21 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-31 20:50:59 +02:00
|
|
|
private List<List<Spot>> GenerateSpotMap(int[,] spotsCreated)
|
2022-08-28 22:42:21 +02:00
|
|
|
{
|
2022-08-31 20:50:59 +02:00
|
|
|
for (var i = 0; i < 4; i++)
|
|
|
|
for (var j = 0; j < spotsCreated.GetLength(1); j++)
|
|
|
|
for (var k = 0; k < spotsCreated[i, j]; k++)
|
|
|
|
SpotMap[i].Add(new Spot((Size) j, false));
|
|
|
|
|
|
|
|
SpotMap[0].Sort((a, b) => a.Size.CompareTo(b.Size)); // ascending sort
|
|
|
|
SpotMap[1].Sort((a, b) => b.Size.CompareTo(a.Size)); // descending sort
|
|
|
|
SpotMap[2].Sort((a, b) => b.Size.CompareTo(a.Size)); // descending sort
|
|
|
|
SpotMap[3].Sort((a, b) => a.Size.CompareTo(b.Size)); // ascending sort
|
2022-08-31 21:19:20 +02:00
|
|
|
SpotMap[2].Add(new Spot(Size.D, false));
|
2022-08-31 20:50:59 +02:00
|
|
|
return SpotMap;
|
2022-08-28 22:42:21 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|