Parking/Assets/Scripts/InitialConfigurationGenerator.cs

245 lines
10 KiB
C#
Raw Normal View History

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()
{
2022-09-05 22:01:52 +02:00
PreProcessCombinations(out int[] spotCountsPerpendicular, out int[,] spotCountsParallel);
2022-09-05 23:31:33 +02:00
int[,] spotsCreated = new int[4, 8];
2022-09-05 22:01:52 +02:00
int maxCount = TestCombinations(spotCountsPerpendicular, spotCountsParallel, spotsCreated);
Debug.Log($"Best solution count {maxCount}");
2022-09-05 22:01:52 +02:00
int[] counts = {0, 0, 0, 0};
for (int i = 0; i < spotsCreated.GetLength(0); i++)
for (int j = 0; j < spotsCreated.GetLength(1); j++)
2022-09-05 23:31:33 +02:00
counts[j % 4] += spotsCreated[i, j];
2022-09-05 22:01:52 +02:00
string countsString = $"Małe: {counts[0]} Średnie: {counts[1]} Duże: {counts[2]} " +
$"Suma: {counts.Sum() + 1}";
ParkingManager.Instance.UpdateText(countsString);
Debug.Log(countsString);
2022-09-05 22:01:52 +02:00
return spotsCreated;
}
private int TestCombinations(int[] spotCountsPerpendicular, int[,] spotCountsParallel, int[,] spotsCreated)
{
int[] counts = {0, 0, 0};
counts[(int) Size.A] += 2;
counts[(int) Size.B] += 2;
2022-09-05 22:01:52 +02:00
int fixedCarSpots = 0;
foreach (int c in counts) fixedCarSpots += c;
2022-09-05 22:01:52 +02:00
string countsString = $"Małe: {counts[0]} Średnie: {counts[1]} Duże: {counts[2]} " +
$"Suma: {counts.Sum() + 1}";
ParkingManager.Instance.UpdateText(countsString);
Debug.Log(countsString);
int maxCount = 0;
2022-09-05 22:01:52 +02:00
int[] maxComb = {1, 1, 1, 1};
2022-09-07 20:35:01 +02:00
List<Driver> drivers = new List<Driver>(DataImporter.Drivers.Count + 4);
drivers.Add(new Driver(Size.A, 0, ParkingPreference.Any, 2, 15));
drivers.Add(new Driver(Size.A, 0, ParkingPreference.Any, 2, 15));
drivers.Add(new Driver(Size.B, 0, ParkingPreference.Any, 2, 15));
drivers.Add(new Driver(Size.B, 0, ParkingPreference.Any, 2, 15));
drivers.AddRange(DataImporter.Drivers);
2022-09-04 00:35:45 +02:00
// Debug.Log("Printing top 5 combinations...");
2022-09-05 22:01:52 +02:00
foreach (int[] comb in Combinations) {
int res = TryFillCombination(comb.ToArray(), spotCountsPerpendicular, spotCountsParallel, counts,
2022-09-07 20:35:01 +02:00
spotsCreated, drivers);
if (res > maxCount) {
maxCount = res;
maxComb = comb;
}
}
TryFillCombination(maxComb, spotCountsPerpendicular, spotCountsParallel, counts,
2022-09-07 20:35:01 +02:00
spotsCreated, drivers, true);
return maxCount;
}
2022-09-05 22:01:52 +02:00
private int TryFillCombination(int[] sizeIds, int[] spotCountsPerpendicularRef, int[,] spotCountsParallelRef,
2022-09-07 20:35:01 +02:00
int[] counts, int[,] spotsCreated, List<Driver> drivers, bool copyToArray = false)
{
2022-09-05 23:31:33 +02:00
int[,] spotsCreatedTemp = new int[4, 8];
2022-09-05 22:01:52 +02:00
for (int i = 0; i < spotsCreatedTemp.GetLength(0); i++)
for (int j = 0; j < spotsCreatedTemp.GetLength(1); j++)
spotsCreatedTemp[i, j] = 0;
2022-09-05 22:01:52 +02:00
int[] spotCountsPerpendicular = new int[spotCountsPerpendicularRef.Length];
spotCountsPerpendicularRef.CopyTo((Span<int>) spotCountsPerpendicular);
2022-09-05 22:01:52 +02:00
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-09-05 23:31:33 +02:00
float[] parallelLengthAvailable = new[]
{
ParkingManager.Width - 5.5f, ParkingManager.Width - 5.5f,
ParkingManager.Width - 5.5f, 0
};
float[] spotSizes = {4, 4.5f, 5};
2022-09-07 20:35:01 +02:00
foreach (Driver driver in drivers) {
2022-09-05 22:01:52 +02:00
var laneIds = new List<int> {0, 1, 2, 3};
if (driver.Size == Size.C)
laneIds.Reverse();
2022-09-05 22:01:52 +02:00
for (int i = 0; i < 4; i++) {
int laneId = laneIds[i];
2022-09-05 23:31:33 +02:00
bool freePerpendicularSpotsAvailable = spotCountsPerpendicular[laneId] != 0;
bool freeParallelSpotsAvailable = parallelLengthAvailable[laneId] >= 4;
bool carFitsPerpendicular = AvailableSizesCombinations[sizeIds[laneId]] >= spotSizes[(int) driver.Size];
bool carFitsParallel = (sizeIds[laneId] == 1) && parallelLengthAvailable[laneId] >= spotSizes[(int) driver.Size];
if (carFitsPerpendicular && freePerpendicularSpotsAvailable) {
spotCountsPerpendicular[laneId]--;
2022-09-05 22:01:52 +02:00
spotsCreatedTemp[laneId, (int) driver.Size]++;
break;
}
2022-09-05 23:31:33 +02:00
else if(carFitsParallel && freeParallelSpotsAvailable){
2022-09-10 20:40:50 +02:00
parallelLengthAvailable[laneId] -= spotSizes[(int) driver.Size] + 0.5f;
2022-09-05 23:31:33 +02:00
spotCountsPerpendicular[laneId] = 0;
spotsCreatedTemp[laneId, (int) driver.Size + 4]++;
break;
}
}
}
int count = 0;
2022-09-05 22:01:52 +02:00
for (int i = 0; i < spotsCreatedTemp.GetLength(0); i++)
for (int j = 0; j < spotsCreatedTemp.GetLength(1); j++)
2022-09-05 00:27:58 +02:00
count += spotsCreatedTemp[i, j];
if (!copyToArray)
return count;
2022-09-05 22:01:52 +02:00
for (int laneId = 3; laneId >= 0; laneId--)
2022-09-05 00:27:58 +02:00
if (spotCountsPerpendicular[laneId] != 0) {
if (sizeIds[laneId] == 0) {
// empty
}
else if (sizeIds[laneId] == 1) {
// parallel only
}
else {
spotsCreatedTemp[laneId, sizeIds[laneId] - 2] += spotCountsPerpendicular[laneId];
count += spotCountsPerpendicular[laneId];
spotCountsPerpendicular[laneId] = 0;
}
}
2022-09-05 22:01:52 +02:00
for (int i = 0; i < spotsCreatedTemp.GetLength(0); i++)
for (int j = 0; j < spotsCreatedTemp.GetLength(1); j++)
2022-09-05 00:27:58 +02:00
spotsCreated[i, j] = spotsCreatedTemp[i, j];
2022-09-05 22:01:52 +02:00
return count;
}
private void PreProcessCombinations(out int[] spotCountsPerpendicular, out int[,] spotCountsParallel)
{
2022-09-04 00:35:45 +02:00
// 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];
2022-09-05 22:01:52 +02:00
for (int i = 0; i < 3; i++)
for (int j = 0; j < spotLengthsParallel.Length; j++)
spotCountsParallel[i, j] = Mathf.FloorToInt((ParkingManager.Width - 5.5f) / spotLengthsParallel[j]);
2022-09-05 22:01:52 +02:00
for (int j = 0; j < spotLengthsParallel.Length; j++)
spotCountsParallel[3, j] =
Mathf.FloorToInt((ParkingManager.Width - 5.5f - 3.6f * 2 - 2.5f * 4) / spotLengthsParallel[j]);
2022-09-04 00:35:45 +02:00
// Debug.Log("" +
// $"P1: {spotCountsPerpendicular[0]}/ P2: {spotCountsPerpendicular[1]} " +
// $"P3: {spotCountsPerpendicular[2]} P4: {spotCountsPerpendicular[3]} " +
// $"Sum: {spotCountsPerpendicular.Sum()}");
2022-09-05 00:47:52 +02:00
// Debug.Log("Generating combinations...");
int[] arr = {0, 1, 2, 3, 4};
2022-09-05 22:01:52 +02:00
int n = arr.Length;
int r = 4;
CombinationRepetition(arr, n, r);
2022-09-05 00:47:52 +02:00
// Debug.Log($"Found {Combinations.Count} available combinations");
2022-09-05 00:47:52 +02:00
// Debug.Log("Sorting available combinations...");
Combinations.Sort(UsesMoreSpaceComparator);
}
2022-09-05 22:01:52 +02:00
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);
}
2022-09-05 22:01:52 +02:00
private int BiggerSizeComparator(Driver d1, Driver d2)
{
int sizeComp = d1.Size.CompareTo(d2.Size);
if (sizeComp == 0)
return d1.Priority.CompareTo(d2.Priority);
return sizeComp;
}
private void CombinationRepetitionUtil(int[] chosen, int[] arr,
int index, int r, int start, int end)
{
2022-09-05 22:01:52 +02:00
if (index == r) {
// combinations.Add(new[] {arr[chosen[0]]});
var tempArr = new List<int>(r);
2022-09-05 22:01:52 +02:00
for (int i = 0; i < r; i++) tempArr.Add(arr[chosen[i]]);
bool hasEnoughSpace = tempArr.Select(x => AvailableSizesCombinations[x]).Sum() <=
ParkingManager.Height - 11;
bool contains5 = tempArr.Contains(4);
tempArr.Sort();
if (hasEnoughSpace && contains5)
Combinations.Add(tempArr.ToArray());
return;
}
2022-09-05 22:01:52 +02:00
for (int 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)
{
2022-09-05 22:01:52 +02:00
int[] chosen = new int[r + 1];
CombinationRepetitionUtil(chosen, arr, 0, r, 0, n - 1);
}
}
}