SpaceRiver

Untitled

Feb 22nd, 2023
69
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 15.72 KB | None | 0 0
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. using SimpleDb;
  5. using System;
  6. using Scenes;
  7. using System.Linq;
  8.  
  9. namespace Algorithms {
  10.  
  11.     public class AlgorithmFactory {
  12.         public Algorithm GetAlgorithm() {
  13.             Profile profile = StaticValues.profile;
  14.             if (profile == null) {
  15.                 throw new Exception("Profile is null");
  16.             }
  17.             switch (profile.Algorithm) {
  18.                 case "Uniform":
  19.                     return new UniformAlgorithm(profile);
  20.                 case "UniformOrdered":
  21.                     return new UniformOrderedAlgorithm(profile);
  22.                 case "Greedy":
  23.                     return new GreedyAlgorithm(profile);
  24.                 default:
  25.                     throw new Exception("Algorithm not found");
  26.             }
  27.         }
  28.     }
  29.    
  30.     public abstract class Algorithm {
  31.         protected Profile Profile;
  32.  
  33.         protected List<Box> Boxes;
  34.         protected Dimensions ContainerDimensions;
  35.         protected string? ExtraPreferences;
  36.         protected int ProblemId;
  37.  
  38.         protected Solution Solution;
  39.  
  40.  
  41.         public Algorithm(Profile profile) {
  42.             Boxes = null;
  43.             ContainerDimensions = null;
  44.             ExtraPreferences = null;
  45.             Solution = null;
  46.             Profile = profile;
  47.         }
  48.        
  49.         protected bool Fits(List<BoxPlacement> boxPlacements, BoxPlacement boxPlacement) {
  50.             foreach (BoxPlacement placedBox in boxPlacements) {
  51.                 float x1Min = placedBox.Position.x;
  52.                 float x1Max = placedBox.Position.x + placedBox.Box.Dimensions.Width;
  53.                 float y1Min = placedBox.Position.y;
  54.                 float y1Max = placedBox.Position.y + placedBox.Box.Dimensions.Height;
  55.                 float z1Min = placedBox.Position.z;
  56.                 float z1Max = placedBox.Position.z + placedBox.Box.Dimensions.Length;
  57.  
  58.                 float x2Min = boxPlacement.Position.x;
  59.                 float x2Max = boxPlacement.Position.x + boxPlacement.Box.Dimensions.Width;
  60.                 float y2Min = boxPlacement.Position.y;
  61.                 float y2Max = boxPlacement.Position.y + boxPlacement.Box.Dimensions.Height;
  62.                 float z2Min = boxPlacement.Position.z;
  63.                 float z2Max = boxPlacement.Position.z + boxPlacement.Box.Dimensions.Length;
  64.  
  65.                 // if intersecting the container return false
  66.                 if (x2Min < 0 || x2Max > ContainerDimensions.Width || y2Min < 0 || y2Max > ContainerDimensions.Height || z2Min < 0 || z2Max > ContainerDimensions.Length) {
  67.                     return false;
  68.                 }
  69.                 // if not intersecting then coninue
  70.                 if (x1Max <= x2Min || x2Max <= x1Min || y1Max <= y2Min || y2Max <= y1Min || z1Max <= z2Min || z2Max <= z1Min) {
  71.                     continue;
  72.                 } else {
  73.                     return false;
  74.                 }
  75.             }
  76.             return true;
  77.         }
  78.  
  79.         protected Box GetRandomOrientation(Box box, float heat) {
  80.             Box newBox = new Box(box.Description, box.Dimensions, box.Restrictions, box.OrderInList, box.Preferences);
  81.             // get number between 0 and 1
  82.             float random = UnityEngine.Random.Range(0f, 1f);
  83.             // if random is more than heat then return the box
  84.             if (random >= heat) {
  85.                 return newBox;
  86.             }
  87.             // get random orientation
  88.             int orientation = UnityEngine.Random.Range(0, 5);
  89.             switch (orientation) {
  90.                 case 0:
  91.                     newBox.Dimensions = box.Dimensions;
  92.                     break;
  93.                 case 1:
  94.                     newBox.Dimensions = new Dimensions(box.Dimensions.Length, box.Dimensions.Width, box.Dimensions.Height);
  95.                     break;
  96.                 case 2:
  97.                     newBox.Dimensions = new Dimensions(box.Dimensions.Height, box.Dimensions.Length, box.Dimensions.Width);
  98.                     break;
  99.                 case 3:
  100.                     newBox.Dimensions = new Dimensions(box.Dimensions.Width, box.Dimensions.Height, box.Dimensions.Length);
  101.                     break;
  102.                 case 4:
  103.                     newBox.Dimensions = new Dimensions(box.Dimensions.Height, box.Dimensions.Width, box.Dimensions.Length);
  104.                     break;
  105.                 case 5:
  106.                     newBox.Dimensions = new Dimensions(box.Dimensions.Length, box.Dimensions.Height, box.Dimensions.Width);
  107.                     break;
  108.             }
  109.             return newBox;
  110.         }
  111.         protected List<List<Box>> GetRandomBoxeOrientations(List<Box> currentOrientation, int num_of_similar, int num_of_normal, int num_of_differnet) {
  112.             List<List<Box>> boxOrientations = new List<List<Box>>();
  113.             // always have the default one
  114.             boxOrientations.Add(Boxes);
  115.  
  116.             // add the similar ones
  117.             for (int i = 0; i < num_of_similar; i++) {
  118.                 List<Box> boxes = new List<Box>();
  119.                 foreach (Box box in currentOrientation) {
  120.                     boxes.Add(GetRandomOrientation(box, 0.02f));
  121.                 }
  122.                 boxOrientations.Add(boxes);
  123.             }
  124.             // add the normal ones
  125.             for (int i = 0; i < num_of_normal; i++) {
  126.                 List<Box> boxes = new List<Box>();
  127.                 foreach (Box box in currentOrientation) {
  128.                     boxes.Add(GetRandomOrientation(box, 0.1f));
  129.                 }
  130.                 boxOrientations.Add(boxes);
  131.             }
  132.             // add the different ones
  133.             for (int i = 0; i < num_of_differnet; i++) {
  134.                 List<Box> boxes = new List<Box>();
  135.                 foreach (Box box in currentOrientation) {
  136.                     boxes.Add(GetRandomOrientation(box, 0.3f));
  137.                 }
  138.                 boxOrientations.Add(boxes);
  139.             }
  140.             // add 1 random
  141.             List<Box> boxes = new List<Box>();
  142.             foreach (Box box in currentOrientation) {
  143.                 boxes.Add(GetRandomOrientation(box, 1f));
  144.             }
  145.             boxOrientations.Add(boxes);
  146.            
  147.             return boxOrientations;
  148.         }
  149.  
  150.         protected BoxPlacement getFirstAvailableBoxPlacement(List<BoxPlacement> boxPlacements, Box box) {
  151.             Position position = new Position();
  152.             position.x = 0;
  153.             position.y = 0;
  154.             position.z = 0;
  155.             List<float> allPossibleX = new List<float>();
  156.             List<float> allPossibleY = new List<float>();
  157.             List<float> allPossibleZ = new List<float>();
  158.             foreach (BoxPlacement boxPlacement in boxPlacements) {
  159.                 //Debug.Log("BoxPlacement: " + boxPlacement.Position.x + " " + boxPlacement.Position.y + " " + boxPlacement.Position.z);
  160.                 // debug the sizes
  161.                 //Debug.Log("BoxPlacement: " + boxPlacement.Box.Dimensions.Width + " " + boxPlacement.Box.Dimensions.Height + " " + boxPlacement.Box.Dimensions.Length);
  162.                 allPossibleX.Add(boxPlacement.Position.x + boxPlacement.Box.Dimensions.Width);
  163.                 allPossibleY.Add(boxPlacement.Position.y + boxPlacement.Box.Dimensions.Height);
  164.                 allPossibleZ.Add(boxPlacement.Position.z + boxPlacement.Box.Dimensions.Length);
  165.             }
  166.             // add 0,0,0
  167.             allPossibleX.Add(0);
  168.             allPossibleY.Add(0);
  169.             allPossibleZ.Add(0);
  170.  
  171.             // remove duplicates
  172.             allPossibleX = allPossibleX.Distinct().ToList();
  173.             allPossibleY = allPossibleY.Distinct().ToList();
  174.             allPossibleZ = allPossibleZ.Distinct().ToList();
  175.             // sort so that the smallest values are first
  176.             allPossibleX.Sort();
  177.             allPossibleY.Sort();
  178.             allPossibleZ.Sort();
  179.  
  180.  
  181.             // find the first available position
  182.             foreach (float x in allPossibleX) {
  183.                 foreach (float y in allPossibleY) {
  184.                     foreach (float z in allPossibleZ) {
  185.                         position = new Position();
  186.                         position.x = x;
  187.                         position.y = y;
  188.                         position.z = z;
  189.                         BoxPlacement boxPlacement = new BoxPlacement();
  190.                         boxPlacement.Box = box;
  191.                         boxPlacement.Position = position;
  192.                         if (Fits(boxPlacements, boxPlacement)) {
  193.                             return boxPlacement;
  194.                         }
  195.                     }
  196.                 }
  197.             }
  198.             return null;
  199.         }
  200.  
  201.         public abstract Solution Solve(Problem problem);
  202.  
  203.         protected List<Dimensions> GetRotations(Dimensions dimensions) {
  204.             List<Dimensions> rotations = new List<Dimensions>();
  205.             rotations.Add(dimensions);
  206.             rotations.Add(new Dimensions(dimensions.Height, dimensions.Width, dimensions.Length));
  207.             rotations.Add(new Dimensions(dimensions.Length, dimensions.Height, dimensions.Width));
  208.             return rotations;
  209.         }
  210.  
  211.         public Solution GetSolution(Problem problem) {
  212.             if (Boxes == null || ContainerDimensions == null) {
  213.                 throw new Exception("Boxes or ContainerDimensions not set");
  214.             } else {
  215.                 if (Solution == null) {
  216.                     Solution = Solve(problem);
  217.                 }
  218.                 return Solution;
  219.             }
  220.         }
  221.     }
  222.  
  223.     public class UniformAlgorithm : Algorithm {
  224.         public UniformAlgorithm(Profile profile) : base(profile) { }
  225.  
  226.  
  227.         public override Solution Solve(Problem Problem) {
  228.             Boxes = Problem.Boxes;
  229.             ContainerDimensions = Problem.ContainerDimensions;
  230.             ExtraPreferences = Problem.ExtraPreferences;
  231.             ProblemId = Problem.Id;
  232.             if (!CheckUniform()) {
  233.                 throw new Exception("Boxes are not uniform");
  234.             }
  235.             // try fit boxes in container without rotation
  236.             Dimensions firstBoxDimensions = Boxes[0].Dimensions;
  237.             List<Dimensions> rotations = GetRotations(firstBoxDimensions);
  238.             foreach (Dimensions rotation in rotations) {
  239.                 if(OniformFits(rotation)) {
  240.                     return ArrangeBoxes(rotation);
  241.                 }
  242.             }
  243.             throw new Exception("Boxes do not fit in container");
  244.         }
  245.  
  246.         private Solution ArrangeBoxes(Dimensions boxDimensions) {
  247.             int x = Convert.ToInt32(ContainerDimensions.Width / boxDimensions.Width);
  248.             int y = Convert.ToInt32(ContainerDimensions.Height / boxDimensions.Height);
  249.             int z = Convert.ToInt32(ContainerDimensions.Length / boxDimensions.Length);
  250.             int boxCount = Boxes.Count;
  251.             List<BoxPlacement> boxPlacements = new List<BoxPlacement>();
  252.             for (int i = 0; i < boxCount; i++) {
  253.                 int xIndex = i % x;
  254.                 int yIndex = (i / x) % y;
  255.                 int zIndex = i / (x * y);
  256.                 Position position = new Position();
  257.                 position.x = xIndex * boxDimensions.Width;
  258.                 position.y = yIndex * boxDimensions.Height;
  259.                 position.z = zIndex * boxDimensions.Length;
  260.                 BoxPlacement boxPlacement = new BoxPlacement();
  261.                 Box box = Boxes[i];
  262.                 box.Dimensions = boxDimensions;
  263.                 boxPlacement.Box = box;
  264.                 boxPlacement.Position = position;
  265.                 boxPlacements.Add(boxPlacement);
  266.             }
  267.             Solution solution = new Solution();
  268.             solution.Placements = boxPlacements;
  269.             solution.ProblemId = ProblemId;
  270.             solution.ProfileId = Profile.Id;
  271.             return solution;
  272.         }
  273.         private bool OniformFits(Dimensions boxDimensions) {
  274.             int x = Convert.ToInt32(ContainerDimensions.Width / boxDimensions.Width);
  275.             int y = Convert.ToInt32(ContainerDimensions.Height / boxDimensions.Height);
  276.             int z = Convert.ToInt32(ContainerDimensions.Length / boxDimensions.Length);
  277.             int maxBoxes = x * y * z;
  278.             int boxCount = Boxes.Count;
  279.             return maxBoxes >= boxCount;
  280.         }
  281.  
  282.         // checks all the boxes are the same size
  283.         private bool CheckUniform() {
  284.             if (Boxes.Count == 0) {
  285.                 return false;
  286.             }
  287.             Dimensions firstBoxDimensions = Boxes[0].Dimensions;
  288.             foreach (Box box in Boxes) {
  289.                 if (box.Dimensions.Height != firstBoxDimensions.Height || box.Dimensions.Width != firstBoxDimensions.Width || box.Dimensions.Length != firstBoxDimensions.Length) {
  290.                     return false;
  291.                 }
  292.             }
  293.             return true;
  294.         }
  295.     }
  296.  
  297.     public class UniformOrderedAlgorithm : Algorithm {
  298.         public UniformOrderedAlgorithm(Profile profile) : base(profile) { }
  299.  
  300.         public override Solution Solve(Problem problem) {
  301.             Algorithm algorithm = new UniformAlgorithm(Profile);
  302.             // order boxes based on ORderInList, where the biggest numbers will be first
  303.             problem.Boxes.Sort((x, y) => y.OrderInList.CompareTo(x.OrderInList));
  304.             Solution solution = algorithm.Solve(problem);
  305.             return solution;
  306.         }
  307.     }
  308.  
  309.     public class GreedyAlgorithm : Algorithm {
  310.         private List<BoxPlacement> boxPlacements;
  311.         private int mostBoxesPlaced = 0;
  312.         private List<Box> bestOrientation;
  313.         public GreedyAlgorithm(Profile profile) : base(profile) {
  314.             boxPlacements = new List<BoxPlacement>();
  315.         }
  316.  
  317.         private Solution SolveForOrientation(Problem problem, List<Box> boxes) {
  318.             boxes.Sort((x, y) => x.Dimensions.Height.CompareTo(y.Dimensions.Height));
  319.             boxes.Sort((x, y) => x.Dimensions.Width.CompareTo(y.Dimensions.Width));
  320.             boxes.Sort((x, y) => x.Dimensions.Length.CompareTo(y.Dimensions.Length));
  321.  
  322.  
  323.             // our current position in the container
  324.             int counter = 0;
  325.             foreach (Box box in boxes) {
  326.                 BoxPlacement boxPlacement = getFirstAvailableBoxPlacement(boxPlacements,box);
  327.                 if (boxPlacement == null) {
  328.                     Debug.Log(counter);
  329.                     boxPlacements = new List<BoxPlacement>();
  330.                     if (counter >= mostBoxesPlaced) {
  331.                         mostBoxesPlaced = counter;
  332.                         bestOrientation = boxes;
  333.                     }
  334.                     return null;
  335.                 }
  336.                 boxPlacements.Add(boxPlacement);
  337.                 counter++;
  338.             }
  339.             Solution solution = new Solution();
  340.             solution.Placements = boxPlacements;
  341.             solution.ProblemId = ProblemId;
  342.             solution.ProfileId = Profile.Id;
  343.             return solution;
  344.  
  345.            
  346.         }
  347.  
  348.         public override Solution Solve(Problem problem) {
  349.             Boxes = problem.Boxes;
  350.             ContainerDimensions = problem.ContainerDimensions;
  351.             ExtraPreferences = problem.ExtraPreferences;
  352.             ProblemId = problem.Id;
  353.  
  354.             bestOrientation = Boxes;
  355.            
  356.             for (int i = 0; i <50; i++) {
  357.                 List<List<Box>> boxOrientations = GetRandomBoxeOrientations(bestOrientation, 100, 50, 25);
  358.                 foreach (List<Box> boxOrientation in boxOrientations) {
  359.                     Solution solution = SolveForOrientation(problem, boxOrientation);
  360.                     if (solution != null) {
  361.                         return solution;
  362.                     }
  363.                 }
  364.             }
  365.             throw new Exception("Boxes do not fit in container");
  366.         }
  367.     }
  368. }
  369.  
Add Comment
Please, Sign In to add comment