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;
|
2022-08-28 22:42:21 +02:00
|
|
|
using Unity.VisualScripting;
|
2022-08-25 17:58:26 +02:00
|
|
|
using UnityEngine;
|
|
|
|
|
|
|
|
public class ParkingManager : MonoBehaviour
|
|
|
|
{
|
2022-08-28 22:59:22 +02:00
|
|
|
private static readonly float[] AvailableSizesCombinations = {0, 2.5f, 4, 4.5f, 5};//, 7.5f};
|
2022-08-28 22:42:21 +02:00
|
|
|
|
|
|
|
private static readonly List<int[]> combinations = new(3000);
|
|
|
|
[SerializeField] private float width = 68;
|
2022-08-25 17:58:26 +02:00
|
|
|
[SerializeField] private float height = 29;
|
|
|
|
[SerializeField] private int stepTime = 15;
|
|
|
|
[SerializeField] private TextMeshProUGUI timeText;
|
2022-08-29 23:01:18 +02:00
|
|
|
[SerializeField] private GameObject spotPrefabA;
|
|
|
|
[SerializeField] private GameObject spotPrefabB;
|
|
|
|
[SerializeField] private GameObject spotPrefabC;
|
2022-08-25 17:58:26 +02:00
|
|
|
|
2022-08-28 22:42:21 +02:00
|
|
|
private TimeSpan _currentTime = TimeSpan.FromHours(8);
|
2022-08-25 18:38:38 +02:00
|
|
|
private float[] _spotHeights = {3.5f, 4f, 5f, 7.5f};
|
|
|
|
|
2022-08-28 22:42:21 +02:00
|
|
|
private float _spotWidth = 2.25f;
|
|
|
|
|
|
|
|
private void Start()
|
|
|
|
{
|
|
|
|
timeText.text = _currentTime.ToString();
|
|
|
|
DataImporter.ReadFile("Assets/Data/v1.csv");
|
|
|
|
Debug.Log(DataImporter.Drivers);
|
|
|
|
FindSolution();
|
|
|
|
}
|
|
|
|
|
2022-08-25 17:58:26 +02:00
|
|
|
public void AdvanceTime()
|
|
|
|
{
|
|
|
|
_currentTime += TimeSpan.FromMinutes(15);
|
|
|
|
timeText.text = _currentTime.ToString();
|
|
|
|
}
|
2022-08-28 22:42:21 +02:00
|
|
|
|
|
|
|
private void FindSolution()
|
2022-08-25 17:58:26 +02:00
|
|
|
{
|
2022-08-28 22:42:21 +02:00
|
|
|
PreProcessCombinations(out var spotCountsPerpendicular, out var spotCountsParallel);
|
|
|
|
|
|
|
|
int[,] spotsCreated = new int[4, 4];
|
|
|
|
|
|
|
|
int start = 20;
|
|
|
|
int count = start;
|
|
|
|
|
|
|
|
int maxCount = 0;
|
|
|
|
|
2022-08-28 22:59:22 +02:00
|
|
|
if (PlaceNCars(30, spotCountsPerpendicular, spotCountsParallel, spotsCreated))
|
2022-08-28 22:42:21 +02:00
|
|
|
{
|
|
|
|
count++;
|
|
|
|
while (PlaceNCars(count, spotCountsPerpendicular, spotCountsParallel, spotsCreated))
|
|
|
|
{
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
|
|
|
|
maxCount = count--;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
count--;
|
|
|
|
while (!PlaceNCars(count, spotCountsPerpendicular, spotCountsParallel, spotsCreated))
|
|
|
|
{
|
|
|
|
count--;
|
|
|
|
}
|
|
|
|
|
|
|
|
maxCount = count;
|
|
|
|
}
|
|
|
|
Debug.Log($"Best solution count {maxCount}");
|
2022-08-29 23:01:18 +02:00
|
|
|
|
|
|
|
VisualiseSpots(spotsCreated);
|
|
|
|
}
|
|
|
|
|
|
|
|
private void VisualiseSpots(int[,] spotsCreated)
|
|
|
|
{
|
|
|
|
List<List<Size>> spotMap = new List<List<Size>>() {new(), new(), new(), new()};
|
|
|
|
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++)
|
|
|
|
{
|
|
|
|
spotMap[i].Add((Size) j);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int i = 0; i < 4; i++)
|
|
|
|
{
|
|
|
|
float currentY;// = i * 5.5f;
|
|
|
|
switch (i)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
currentY = -height / 2.0f + 2f;
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
currentY = -2.0f;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
currentY = 2.0f;
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
currentY = height / 2.0f - 2f;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
currentY = -10;
|
|
|
|
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;
|
|
|
|
for (int j = 0; j < spotMap[i].Count; j++)
|
|
|
|
{
|
|
|
|
GameObject spot;
|
|
|
|
bool alignTop = i % 2 != 0;
|
|
|
|
switch (spotMap[i][j])
|
|
|
|
{
|
|
|
|
case Size.A:
|
|
|
|
spot = Instantiate(spotPrefabA);
|
|
|
|
spot.transform.position = new Vector3(currentX, currentY, 0);
|
|
|
|
break;
|
|
|
|
case Size.B:
|
|
|
|
spot = Instantiate(spotPrefabB);
|
|
|
|
spot.transform.position = new Vector3(currentX, currentY + (alignTop ? -1 : 1) * 0.25f, 0);
|
|
|
|
break;
|
|
|
|
case Size.C:
|
|
|
|
spot = Instantiate(spotPrefabC);
|
|
|
|
spot.transform.position = new Vector3(currentX, currentY + (alignTop ? -1 : 1) * 0.5f, 0);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
currentX += 2.25f;
|
|
|
|
}
|
|
|
|
}
|
2022-08-28 22:42:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
private bool PlaceNCars(int carsToPlace, int[] spotCountsPerpendicular, int[,] spotCountsParallel, int[,] spotsCreated)
|
|
|
|
{
|
|
|
|
|
2022-08-28 22:59:22 +02:00
|
|
|
int[] counts = {0, 0, 0};
|
2022-08-28 22:42:21 +02:00
|
|
|
counts[(int) Size.A] += 2;
|
|
|
|
counts[(int) Size.B] += 2;
|
2022-08-28 22:59:22 +02:00
|
|
|
// counts[(int) Size.D] += 1;
|
2022-08-28 22:42:21 +02:00
|
|
|
var fixedCarSpots = 0;
|
|
|
|
foreach (var c in counts) fixedCarSpots += c;
|
|
|
|
Debug.Log($"Fixed car spots: {fixedCarSpots}");
|
|
|
|
|
|
|
|
Debug.Log("Calculating required spot counts...");
|
|
|
|
for (int i = 0; i < DataImporter.Drivers.Count && i + fixedCarSpots < carsToPlace; i++)
|
|
|
|
{
|
|
|
|
counts[(int) DataImporter.Drivers[i].Size]++;
|
|
|
|
}
|
|
|
|
|
2022-08-28 22:59:22 +02:00
|
|
|
Debug.Log($"A: {counts[0]} B: {counts[1]} C: {counts[2]} " +
|
2022-08-28 22:42:21 +02:00
|
|
|
$"Sum: {counts.Sum()}");
|
|
|
|
|
|
|
|
|
|
|
|
Debug.Log("Printing top 5 combinations...");
|
|
|
|
foreach (var comb in combinations)
|
|
|
|
{
|
|
|
|
bool res = TestCombination(comb.ToArray(), spotCountsPerpendicular, spotCountsParallel, counts, spotsCreated);
|
|
|
|
if (res)
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
private void PreProcessCombinations(out int[] spotCountsPerpendicular, out int[,] spotCountsParallel)
|
|
|
|
{
|
|
|
|
Debug.Log("Calculating spot counts...");
|
2022-08-28 22:59:22 +02:00
|
|
|
float[] spotLengthsParallel = {4f, 4.5f, 5f};//, 7.5f};
|
2022-08-28 22:42:21 +02:00
|
|
|
spotCountsPerpendicular = new[] {0, 0, 0, 0};
|
2022-08-28 22:59:22 +02:00
|
|
|
spotCountsPerpendicular[0] = Mathf.FloorToInt((width - 5.5f) / _spotWidth);
|
2022-08-29 23:01:18 +02:00
|
|
|
spotCountsPerpendicular[1] = Mathf.FloorToInt((width - 5.5f - 2.5f) / _spotWidth);
|
|
|
|
spotCountsPerpendicular[2] = Mathf.FloorToInt((width - 5.5f - 2.5f) / _spotWidth);
|
2022-08-28 22:59:22 +02:00
|
|
|
spotCountsPerpendicular[3] = Mathf.FloorToInt((width - 5.5f - (3.6f * 2) - (2.5f * 4)) / _spotWidth);
|
2022-08-28 22:42:21 +02:00
|
|
|
spotCountsParallel = new int[4, 4];
|
|
|
|
for (int i = 0; i < 3; i++)
|
2022-08-28 22:59:22 +02:00
|
|
|
for (int j = 0; j < spotLengthsParallel.Length; j++)
|
2022-08-28 22:42:21 +02:00
|
|
|
spotCountsParallel[i, j] = Mathf.FloorToInt((width - 5.5f) / spotLengthsParallel[j]);
|
2022-08-28 22:59:22 +02:00
|
|
|
for (int j = 0; j < spotLengthsParallel.Length; j++)
|
2022-08-28 22:42:21 +02:00
|
|
|
spotCountsParallel[3, j] = Mathf.FloorToInt((width - 5.5f - (3.6f * 2) - (2.5f * 4)) / spotLengthsParallel[j]);
|
|
|
|
Debug.Log($"" +
|
|
|
|
$"P1: {spotCountsPerpendicular[0]}/ P2: {spotCountsPerpendicular[1]} " +
|
|
|
|
$"P3: {spotCountsPerpendicular[2]} P4: {spotCountsPerpendicular[3]} " +
|
|
|
|
$"Sum: {spotCountsPerpendicular.Sum()}");
|
|
|
|
|
|
|
|
Debug.Log("Generating combinations...");
|
2022-08-28 22:59:22 +02:00
|
|
|
int[] arr = {0, 1, 2, 3, 4};
|
2022-08-28 22:42:21 +02:00
|
|
|
var n = arr.Length;
|
|
|
|
var r = 4;
|
|
|
|
CombinationRepetition(arr, n, r);
|
|
|
|
Debug.Log($"Found {combinations.Count} available combinations");
|
|
|
|
|
|
|
|
Debug.Log("Sorting available combinations...");
|
|
|
|
combinations.Sort(UsesMoreSpaceComparator);
|
2022-08-25 17:58:26 +02:00
|
|
|
}
|
|
|
|
|
2022-08-28 22:42:21 +02:00
|
|
|
private bool TestCombination(int[] sizeIds, int[] spotCountsPerpendicularRef, int[,] spotCountsParallelRef, int[] requiredCountsRef, int[,] spotsCreated)
|
2022-08-25 17:58:26 +02:00
|
|
|
{
|
2022-08-28 22:42:21 +02:00
|
|
|
float[] sizes = sizeIds.Select(x => AvailableSizesCombinations[x]).ToArray();
|
2022-08-28 22:59:22 +02:00
|
|
|
Debug.Log($"Testing: {sizes[0]} {sizes[1]} {sizes[2]} sum: {sizes.Sum()}");
|
2022-08-28 22:42:21 +02:00
|
|
|
|
|
|
|
for(int i = 0; i < spotsCreated.GetLength(0); i++)
|
|
|
|
for (int j = 0; j < spotsCreated.GetLength(1); j++)
|
|
|
|
spotsCreated[i, j] = 0;
|
|
|
|
|
|
|
|
int[] requiredCounts = new int[requiredCountsRef.Length];
|
|
|
|
requiredCountsRef.CopyTo((Span<int>) requiredCounts);
|
|
|
|
|
|
|
|
int[] spotCountsPerpendicular = new int[spotCountsPerpendicularRef.Length];
|
|
|
|
spotCountsPerpendicularRef.CopyTo((Span<int>) spotCountsPerpendicular);
|
|
|
|
|
|
|
|
int[,] spotCountsParallel = new int[spotCountsParallelRef.GetLength(0), spotCountsParallelRef.GetLength(1)];
|
|
|
|
for(int i = 0; i < spotCountsParallelRef.GetLength(0); i++)
|
|
|
|
for(int j = 0; j < spotCountsParallelRef.GetLength(1); j++)
|
|
|
|
spotCountsParallel[i,j] = spotCountsParallelRef[i, j];
|
2022-08-25 17:58:26 +02:00
|
|
|
|
2022-08-29 23:01:18 +02:00
|
|
|
float[] spotSizes = {4, 4.5f, 5};
|
|
|
|
|
2022-08-28 22:59:22 +02:00
|
|
|
for (int spotSize = 2; spotSize >= 0; spotSize--)
|
2022-08-28 22:42:21 +02:00
|
|
|
{
|
|
|
|
for (int laneId = 0; laneId < 4; laneId++)
|
|
|
|
{
|
2022-08-29 23:01:18 +02:00
|
|
|
if (AvailableSizesCombinations[sizeIds[laneId]] <= spotSizes[spotSize] && spotCountsPerpendicular[laneId] != 0) { // parking perpendicular
|
2022-08-28 22:42:21 +02:00
|
|
|
int spotsTaken = Math.Min(requiredCounts[spotSize], spotCountsPerpendicular[laneId]);
|
|
|
|
|
|
|
|
spotCountsPerpendicular[laneId] -= spotsTaken;
|
|
|
|
requiredCounts[spotSize] -= spotsTaken;
|
|
|
|
|
|
|
|
spotsCreated[laneId, spotSize] += spotsTaken;
|
|
|
|
|
|
|
|
// TODO: Allow modified configuration
|
2022-08-28 22:59:22 +02:00
|
|
|
for(int x = 0; x < 3; x++)
|
2022-08-28 22:42:21 +02:00
|
|
|
spotCountsParallel[laneId, x] = 0;
|
|
|
|
}
|
2022-08-28 22:59:22 +02:00
|
|
|
// else if (sizeIds[laneId] == 0 && spotCountsParallel[laneId, spotSize] != 0) { // parking parallel
|
|
|
|
// int spotsTaken = Math.Min(requiredCounts[spotSize], spotCountsParallel[laneId, spotSize]);
|
|
|
|
//
|
|
|
|
// spotCountsParallel[laneId, spotSize] -= spotsTaken;
|
|
|
|
// requiredCounts[spotSize] -= spotsTaken;
|
|
|
|
//
|
|
|
|
// spotsCreated[laneId, spotSize] += spotsTaken;
|
|
|
|
//
|
|
|
|
// // TODO: Allow modified configuration
|
|
|
|
// spotCountsPerpendicular[laneId] = 0;
|
|
|
|
// for(int x = 0; x < 3; x++)
|
|
|
|
// if(x != spotSize)
|
|
|
|
// spotCountsParallel[laneId, x] = 0;
|
|
|
|
// }
|
2022-08-28 22:42:21 +02:00
|
|
|
if(requiredCounts[spotSize] == 0)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int sum = requiredCounts.Sum();
|
|
|
|
if(sum > 0)
|
|
|
|
return false;
|
|
|
|
else
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
private int UsesMoreSpaceComparator(int[] a1, int[] a2)
|
|
|
|
{
|
|
|
|
float sum1 = 0;
|
|
|
|
float sum2 = 0;
|
|
|
|
foreach (float val in a1) sum1 += val;
|
|
|
|
|
|
|
|
foreach (float val in a2) sum2 += val;
|
|
|
|
|
|
|
|
return -1 * sum1.CompareTo(sum2);
|
|
|
|
}
|
|
|
|
|
|
|
|
private void CombinationRepetitionUtil(int[] chosen, int[] arr,
|
|
|
|
int index, int r, int start, int end)
|
|
|
|
{
|
|
|
|
if (index == r)
|
|
|
|
{
|
|
|
|
// combinations.Add(new[] {arr[chosen[0]]});
|
|
|
|
var tempArr = new List<int>(r);
|
|
|
|
for (var i = 0; i < r; i++) tempArr.Add(arr[chosen[i]]);
|
|
|
|
if (tempArr.Select(x => AvailableSizesCombinations[x]).Sum() < height - 11)
|
|
|
|
combinations.Add(tempArr.ToArray());
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (var i = start; i <= end; i++)
|
|
|
|
{
|
|
|
|
chosen[index] = i;
|
|
|
|
CombinationRepetitionUtil(chosen, arr, index + 1,
|
|
|
|
r, i, end);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void CombinationRepetition(int[] arr, int n, int r)
|
|
|
|
{
|
|
|
|
var chosen = new int[r + 1];
|
|
|
|
CombinationRepetitionUtil(chosen, arr, 0, r, 0, n - 1);
|
2022-08-25 17:58:26 +02:00
|
|
|
}
|
2022-08-28 22:42:21 +02:00
|
|
|
}
|