From 528be18635b77e49e290625ddddee5f4c3799c0f Mon Sep 17 00:00:00 2001 From: Dawid Pietrykowski Date: Sun, 28 Aug 2022 22:42:21 +0200 Subject: [PATCH] WIP Initial configuration generation --- Assets/Scripts/Driver.cs | 2 +- Assets/Scripts/ParkingManager.cs | 233 +++++++++++++++++++++++++++++-- 2 files changed, 220 insertions(+), 15 deletions(-) diff --git a/Assets/Scripts/Driver.cs b/Assets/Scripts/Driver.cs index 8270c42..0447890 100644 --- a/Assets/Scripts/Driver.cs +++ b/Assets/Scripts/Driver.cs @@ -21,7 +21,7 @@ public enum Size { A = 0, B = 1, C = 2, - D = 4 + D = 3 } public enum ParkingPreference { diff --git a/Assets/Scripts/ParkingManager.cs b/Assets/Scripts/ParkingManager.cs index 5b41c1b..b06887f 100644 --- a/Assets/Scripts/ParkingManager.cs +++ b/Assets/Scripts/ParkingManager.cs @@ -1,38 +1,243 @@ using System; -using System.Collections; using System.Collections.Generic; +using System.Linq; using TMPro; +using Unity.VisualScripting; using UnityEngine; public class ParkingManager : MonoBehaviour { - [SerializeField] private float width = 68; + private static readonly float[] AvailableSizesCombinations = {0, 2.5f, 4, 4.5f, 5, 7.5f}; + + private static readonly List combinations = new(3000); + [SerializeField] private float width = 68; [SerializeField] private float height = 29; [SerializeField] private int stepTime = 15; [SerializeField] private TextMeshProUGUI timeText; - private float _spotWidth = 2.25f; + private TimeSpan _currentTime = TimeSpan.FromHours(8); private float[] _spotHeights = {3.5f, 4f, 5f, 7.5f}; - private TimeSpan _currentTime = TimeSpan.FromHours(8); - + private float _spotWidth = 2.25f; + + private void Start() + { + timeText.text = _currentTime.ToString(); + DataImporter.ReadFile("Assets/Data/v1.csv"); + Debug.Log(DataImporter.Drivers); + FindSolution(); + } + public void AdvanceTime() { _currentTime += TimeSpan.FromMinutes(15); timeText.text = _currentTime.ToString(); } - - // Start is called before the first frame update - void Start() + + private void FindSolution() { - timeText.text = _currentTime.ToString(); - DataImporter.ReadFile("Assets/Data/v1.csv"); - Debug.Log(DataImporter.Drivers); + PreProcessCombinations(out var spotCountsPerpendicular, out var spotCountsParallel); + + int[,] spotsCreated = new int[4, 4]; + + int start = 20; + int count = start; + + int maxCount = 0; + + if (PlaceNCars(60, spotCountsPerpendicular, spotCountsParallel, spotsCreated)) + { + 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}"); } - // Update is called once per frame - void Update() + private bool PlaceNCars(int carsToPlace, int[] spotCountsPerpendicular, int[,] spotCountsParallel, int[,] spotsCreated) { + + int[] counts = {0, 0, 0, 0}; + counts[(int) Size.A] += 2; + counts[(int) Size.B] += 2; + counts[(int) Size.D] += 1; + 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]++; + } + + Debug.Log($"A: {counts[0]} B: {counts[1]} C: {counts[2]} D: {counts[3]} " + + $"Sum: {counts.Sum()}"); + + Debug.Log("Printing top 5 combinations..."); + var count = 0; + foreach (var comb in combinations) + { + // var sizes = comb.Select(x => AvailableSizesCombinations[x]).ToArray(); + // Debug.Log($"{sizes[0]} {sizes[1]} {sizes[2]} {sizes[3]} sum: {sizes.Sum()}"); + bool res = TestCombination(comb.ToArray(), spotCountsPerpendicular, spotCountsParallel, counts, spotsCreated); + if (res) + return true; + count++; + // if (count >= 5) + // return; + } + + // var placingFailed = false; + // while (fixedCarSpots < carsToPlace && !placingFailed) break; + + return false; + Application.Quit(); } -} + + private void PreProcessCombinations(out int[] spotCountsPerpendicular, out int[,] spotCountsParallel) + { + Debug.Log("Calculating spot counts..."); + float[] spotLengthsParallel = {4f, 4.5f, 5f, 7.5f}; + spotCountsPerpendicular = new[] {0, 0, 0, 0}; + spotCountsPerpendicular[0] = Mathf.FloorToInt((width - 5.5f) / 2.25f); + spotCountsPerpendicular[1] = Mathf.FloorToInt((width - 5.5f) / 2.25f); + spotCountsPerpendicular[2] = Mathf.FloorToInt((width - 5.5f) / 2.25f); + spotCountsPerpendicular[3] = Mathf.FloorToInt((width - 5.5f - (3.6f * 2) - (2.5f * 4)) / 2.25f); + spotCountsParallel = new int[4, 4]; + for (int i = 0; i < 3; i++) + for (int j = 0; j < 4; j++) + spotCountsParallel[i, j] = Mathf.FloorToInt((width - 5.5f) / spotLengthsParallel[j]); + for (int j = 0; j < 4; j++) + 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..."); + int[] arr = {0, 1, 2, 3, 4, 5}; + 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); + } + + private bool TestCombination(int[] sizeIds, int[] spotCountsPerpendicularRef, int[,] spotCountsParallelRef, int[] requiredCountsRef, int[,] spotsCreated) + { + float[] sizes = sizeIds.Select(x => AvailableSizesCombinations[x]).ToArray(); + Debug.Log($"Testing: {sizes[0]} {sizes[1]} {sizes[2]} {sizes[3]} sum: {sizes.Sum()}"); + + 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) requiredCounts); + + int[] spotCountsPerpendicular = new int[spotCountsPerpendicularRef.Length]; + spotCountsPerpendicularRef.CopyTo((Span) 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]; + + for (int spotSize = 3; spotSize >= 0; spotSize--) + { + for (int laneId = 0; laneId < 4; laneId++) + { + if (sizeIds[laneId] == spotSize && spotCountsPerpendicular[laneId] != 0) { // parking perpendicular + int spotsTaken = Math.Min(requiredCounts[spotSize], spotCountsPerpendicular[laneId]); + + spotCountsPerpendicular[laneId] -= spotsTaken; + requiredCounts[spotSize] -= spotsTaken; + + spotsCreated[laneId, spotSize] += spotsTaken; + + // TODO: Allow modified configuration + for(int x = 0; x < 4; x++) + spotCountsParallel[laneId, x] = 0; + }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 < 4; x++) + if(x != spotSize) + spotCountsParallel[laneId, x] = 0; + } + 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(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); + } +} \ No newline at end of file