Parking/Assets/Scripts/InitialConfigurationGenerator.cs
2022-08-31 20:50:59 +02:00

221 lines
8.9 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace Parking
{
public class InitialConfigurationGenerator
{
private static readonly List<int[]> Combinations = new(3000);
private static readonly float[] AvailableSizesCombinations = {0, 2.5f, 4, 4.5f, 5}; //, 7.5f};
private readonly float _spotWidth = 2.25f;
public int[,] FindSolution()
{
PreProcessCombinations(out var spotCountsPerpendicular, out var spotCountsParallel);
var spotsCreated = new int[4, 4];
var start = 80;
var count = start;
var maxCount = 0;
if (PlaceNCars(30, 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}");
return spotsCreated;
}
private bool PlaceNCars(int carsToPlace, int[] spotCountsPerpendicular, int[,] spotCountsParallel,
int[,] spotsCreated)
{
int[] counts = {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 (var i = 0; i < DataImporter.Drivers.Count && i + fixedCarSpots < carsToPlace; i++)
counts[(int) DataImporter.Drivers[i].Size]++;
var countsString = $"A: {counts[0]} B: {counts[1]} C: {counts[2]} " +
$"Suma: {counts.Sum()}";
ParkingManager.Instance.UpdateText(countsString);
Debug.Log(countsString);
Debug.Log("Printing top 5 combinations...");
foreach (var comb in Combinations)
{
var 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...");
float[] spotLengthsParallel = {4f, 4.5f, 5f}; //, 7.5f};
spotCountsPerpendicular = new[] {0, 0, 0, 0};
spotCountsPerpendicular[0] = Mathf.FloorToInt((ParkingManager.Width - 5.5f) / _spotWidth);
spotCountsPerpendicular[1] = Mathf.FloorToInt((ParkingManager.Width - 5.5f - 2.5f) / _spotWidth);
spotCountsPerpendicular[2] = Mathf.FloorToInt((ParkingManager.Width - 5.5f - 2.5f) / _spotWidth);
spotCountsPerpendicular[3] =
Mathf.FloorToInt((ParkingManager.Width - 5.5f - 3.6f * 2 - 2.5f * 4) / _spotWidth);
spotCountsParallel = new int[4, 4];
for (var i = 0; i < 3; i++)
for (var j = 0; j < spotLengthsParallel.Length; j++)
spotCountsParallel[i, j] = Mathf.FloorToInt((ParkingManager.Width - 5.5f) / spotLengthsParallel[j]);
for (var j = 0; j < spotLengthsParallel.Length; j++)
spotCountsParallel[3, j] =
Mathf.FloorToInt((ParkingManager.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};
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)
{
var sizes = sizeIds.Select(x => AvailableSizesCombinations[x]).ToArray();
Debug.Log($"Testing: {sizes[0]} {sizes[1]} {sizes[2]} {sizes[3]} sum: {sizes.Sum()}");
for (var i = 0; i < spotsCreated.GetLength(0); i++)
for (var j = 0; j < spotsCreated.GetLength(1); j++)
spotsCreated[i, j] = 0;
var requiredCounts = new int[requiredCountsRef.Length];
requiredCountsRef.CopyTo((Span<int>) requiredCounts);
var spotCountsPerpendicular = new int[spotCountsPerpendicularRef.Length];
spotCountsPerpendicularRef.CopyTo((Span<int>) spotCountsPerpendicular);
var spotCountsParallel = new int[spotCountsParallelRef.GetLength(0), spotCountsParallelRef.GetLength(1)];
for (var i = 0; i < spotCountsParallelRef.GetLength(0); i++)
for (var j = 0; j < spotCountsParallelRef.GetLength(1); j++)
spotCountsParallel[i, j] = spotCountsParallelRef[i, j];
float[] spotSizes = {4, 4.5f, 5};
for (var spotSize = 2; spotSize >= 0; spotSize--)
for (var laneId = 3; laneId >= 0; laneId--)
{
if (AvailableSizesCombinations[sizeIds[laneId]] <= spotSizes[spotSize] &&
spotCountsPerpendicular[laneId] != 0)
{
// parking perpendicular
var spotsTaken = Math.Min(requiredCounts[spotSize], spotCountsPerpendicular[laneId]);
spotCountsPerpendicular[laneId] -= spotsTaken;
requiredCounts[spotSize] -= spotsTaken;
spotsCreated[laneId, spotSize] += spotsTaken;
// TODO: Allow modified configuration
for (var x = 0; x < 3; 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 < 3; x++)
// if(x != spotSize)
// spotCountsParallel[laneId, x] = 0;
// }
if (requiredCounts[spotSize] == 0)
break;
}
var sum = requiredCounts.Sum();
if (sum > 0)
return false;
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]]);
var hasEnoughSpace = tempArr.Select(x => AvailableSizesCombinations[x]).Sum() <
ParkingManager.Height - 11;
var contains5 = tempArr.Contains(4);
tempArr.Sort();
if (hasEnoughSpace && contains5)
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);
}
}
}