Parking/Assets/Scripts/ParkingManager.cs

282 lines
12 KiB
C#
Raw Normal View History

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;
namespace Parking
2022-08-25 17:58:26 +02:00
{
public class ParkingManager : MonoBehaviour
2022-08-28 22:42:21 +02:00
{
public const float Width = 68;
public const float Height = 29;
2022-08-28 22:42:21 +02:00
public static ParkingManager Instance;
2022-08-28 22:42:21 +02:00
[SerializeField] private int stepTime = 15;
[SerializeField] private TextMeshProUGUI timeText;
[SerializeField] public TextMeshProUGUI countsText;
[SerializeField] public TextMeshProUGUI rejectedText;
[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
private readonly float[] _spotHeights = {3.5f, 4f, 5f, 7.5f};
2022-08-28 22:42:21 +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
private void Awake()
2022-08-28 22:42:21 +02:00
{
Instance = this;
2022-08-28 22:42:21 +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]}";
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
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;
}
timeText.text = _currentTime.ToString();
2022-09-01 22:31:57 +02:00
foreach (Driver driver in DataImporter.Drivers)
if (_currentTime <= driver.Times[1].TimeOfDay && _currentTime > driver.Times[0].TimeOfDay &&
!driver.Parked && !driver.Rejected)
2022-09-01 22:31:57 +02:00
{
if (!PlaceCarOnParking(driver))
{
2022-09-03 21:27:31 +02:00
Debug.Log($"Placing failed for car {driver.Number}");
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]}";
}
}
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();
}
}
private bool PlaceCarOnParking(Driver driver)
2022-09-01 22:31:57 +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));
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;
driver.GameObject.transform.rotation =
Quaternion.Euler(new Vector3(0, 0, spot.Flipped ? 180 : 0));
return true;
2022-09-01 22:31:57 +02:00
}
return false;
}
2022-08-29 23:01:18 +02:00
public void UpdateText(string text)
2022-08-29 23:01:18 +02:00
{
countsText.text = text;
2022-08-29 23:01:18 +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;
}
private void ArrangeSpots(int[,] spotsCreated)
2022-08-29 23:01:18 +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
{
float currentY;
switch (i)
2022-08-29 23:01:18 +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;
case 2:
currentY = Height / 2 - 5.5f - 5f - maxP3 / 2.0f;
2022-08-29 23:01:18 +02:00
break;
case 3:
currentY = Height / 2.0f - 2f;
2022-08-29 23:01:18 +02:00
break;
default:
currentY = -10;
2022-08-29 23:01:18 +02:00
break;
}
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
var flipped = false;
var parkingFromTop = i % 2 != 0;
2022-08-28 22:42:21 +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 =
new Vector3(currentX, currentY - 2.0f, 0);
2022-08-31 21:19:20 +02:00
break;
}
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));
var frontalParking = !parkingFromTop ^ flipped;
spotMap[i][j].ParkingDirection = frontalParking ? ParkingPreference.Front : ParkingPreference.Back;
currentX += 2.25f;
flipped = !flipped;
2022-08-28 22:42:21 +02:00
}
}
}
private List<List<Spot>> GenerateSpotMap(int[,] spotsCreated)
2022-08-28 22:42:21 +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));
return SpotMap;
2022-08-28 22:42:21 +02:00
}
}
}