コード例 #1
0
        public void TestMeanWeight()
        {
            var box   = Factory.CreateBox("Box", 10, 10, 10, 0, 10, 10, 10, 100);
            var itemA = Factory.CreateItem("Item A", 5, 10, 10, 10, true);
            var itemB = Factory.CreateItem("Item B", 5, 10, 10, 20, true);

            var packedItemA = new PackedItem(itemA, 0, 0, 0, 5, 10, 10);
            var packedItemB = new PackedItem(itemB, 0, 0, 0, 5, 10, 10);

            var packedItemListA = new PackedItemList();

            packedItemListA.Insert(packedItemA);
            var packedBoxA = new PackedBox(box, packedItemListA);

            var packedItemListB = new PackedItemList();

            packedItemListB.Insert(packedItemB);
            var packedBoxB = new PackedBox(box, packedItemListB);

            var pBoxArray = new PackedBox[] { packedBoxA, packedBoxB };

            var packedBoxList = new PackedBoxList();

            packedBoxList.Insert(packedBoxA);
            packedBoxList.Insert(packedBoxB);

            Assert.Equal(15, packedBoxList.GetMeanWeight());
        }
コード例 #2
0
        /// <summary>
        /// Given a solution set of packed boxes, repack them to achieve optimum weight distribution.
        /// </summary>
        /// <param name="originalBoxes"></param>
        /// <returns></returns>
        public PackedBoxList RedistributeWeight(PackedBoxList originalBoxes)
        {
            var targetWeight = originalBoxes.GetMeanWeight();

            var redistrebutedBoxes = originalBoxes.ToList();

            redistrebutedBoxes.OrderByDescending(box => box.TotalWeight);

            var iterationSuccessful = false;

            do
            {
                iterationSuccessful = false;

                var a = redistrebutedBoxes.Count;
                while (a - 1 >= 0)
                {
                    a -= 1;
                    var boxA = redistrebutedBoxes[a];

                    var b = redistrebutedBoxes.Count;
                    while (b - 1 >= 0)
                    {
                        b -= 1;
                        var boxB = redistrebutedBoxes[b];

                        if (b <= a || boxA.TotalWeight == boxB.TotalWeight)
                        {
                            continue; //no need to evaluate
                        }

                        iterationSuccessful   = EqualiseWeight(ref boxA, ref boxB, targetWeight);
                        redistrebutedBoxes[a] = boxA;
                        redistrebutedBoxes[b] = boxB;

                        if (iterationSuccessful)
                        {
                            //remove any now-empty boxes from the list
                            redistrebutedBoxes = redistrebutedBoxes
                                                 .Where(box => box != null)
                                                 .OrderByDescending(box => box.TotalWeight)
                                                 .ToList();

                            goto LEAVE_LOOPS;
                        }
                    }
                }

                LEAVE_LOOPS :;
            } while (iterationSuccessful);

            //Combine back into a single list
            var packedBoxes = new PackedBoxList();

            packedBoxes.InsertFromArray(redistrebutedBoxes.ToArray());

            return(packedBoxes);
        }
コード例 #3
0
        /// <summary>
        /// Given a solution set of packed boxes, repack them to achieve optimum weight distribution
        /// </summary>
        /// <param name="originalPackedBoxList"></param>
        /// <returns></returns>
        public PackedBoxList RedistributeWeight(PackedBoxList originalPackedBoxList)
        {
            var targetWeight = originalPackedBoxList.GetMeanWeight();

            _logger.Log(LogLevel.Debug, "Repacking for weight distribution, weight variance {0}, target weight {1}", originalPackedBoxList.GetWeightVariance(), targetWeight);

            var packedBoxes      = new PackedBoxList();
            var overWeightBoxes  = new List <PackedBox>();
            var underWeightBoxes = new List <PackedBox>();

            var originalPackedBoxes = originalPackedBoxList.ShallowCopy().GetContent().Cast <PackedBox>();

            foreach (var originalPackedBox in originalPackedBoxes)
            {
                var boxWeight = originalPackedBox.GetWeight();

                if (boxWeight > targetWeight)
                {
                    overWeightBoxes.Add(originalPackedBox);
                }
                else if (boxWeight < targetWeight)
                {
                    underWeightBoxes.Add(originalPackedBox);
                }
                else
                {
                    packedBoxes.Insert(originalPackedBox); // Target weight, so we'll keep these
                }
            }


            // Keep moving items from most overweight box to most underweight box
            var tryRepack = false;

            do
            {
                _logger.Log(LogLevel.Debug, "Boxes under/over target: {0}/{1}", underWeightBoxes.Count, overWeightBoxes.Count);

                for (var underWeightBoxIndex = 0; underWeightBoxIndex < underWeightBoxes.Count; underWeightBoxIndex++)
                {
                    var underWeightBox = underWeightBoxes[underWeightBoxIndex];

                    for (var overWeightBoxIndex = 0; overWeightBoxIndex < overWeightBoxes.Count; overWeightBoxIndex++)
                    {
                        var overWeightBox      = overWeightBoxes[overWeightBoxIndex];
                        var overWeightBoxItems = overWeightBox.GetItems().GetContent().Cast <Item>().ToList();

                        foreach (var overWeightBoxItem in overWeightBoxItems)
                        {
                            // If over target weight, just continue as it would hinder rather than help weight distribution
                            var overTargetWeight = (underWeightBox.GetWeight() + overWeightBoxItem.Weight) > targetWeight;
                            if (overTargetWeight)
                            {
                                continue;
                            }

                            var newItemsForLighterBox = underWeightBox.GetItems().ShallowCopy();
                            newItemsForLighterBox.Insert(overWeightBoxItem);

                            // We may need a bigger box
                            var newLighterBoxPacker = new Packer();
                            newLighterBoxPacker.AddBoxes(Boxes);
                            newLighterBoxPacker.AddItems(newItemsForLighterBox);
                            var newLighterBox = newLighterBoxPacker.PackByVolume().ExtractMin();

                            // New item fits!
                            if (newLighterBox.GetItems().GetCount() == newItemsForLighterBox.GetCount())
                            {
                                // Remove from overWeightBoxItems as it is now packed in a different box
                                overWeightBoxItems.Remove(overWeightBoxItem);

                                // We may be able to use a smaller box
                                var newHeavierBoxPacker = new Packer();
                                newHeavierBoxPacker.AddBoxes(Boxes);
                                newHeavierBoxPacker.AddItems(overWeightBoxItems);

                                var newHeavierBoxes = newHeavierBoxPacker.PackByVolume();

                                // Found an edge case in packing algorithm that *increased* box count
                                if (newHeavierBoxes.GetCount() > 1)
                                {
                                    _logger.Log(LogLevel.Info, "[REDISTRIBUTING WEIGHT] Abandoning redistribution, because new packing is less effciient than original");
                                    return(originalPackedBoxList);
                                }

                                // TODO: INDEX BASED ARRAY INSERTION FOR BOTH
                                overWeightBoxes[overWeightBoxIndex]   = newHeavierBoxes.ExtractMin();
                                underWeightBoxes[underWeightBoxIndex] = newLighterBox;

                                // We did some work, so see if we can do even better
                                tryRepack = true;
                                overWeightBoxes.Sort(packedBoxes.ReverseCompareTo);
                                underWeightBoxes.Sort(packedBoxes.ReverseCompareTo);

                                // The devil, but ported from PHP, was originally break 3, but .NET doesn't have a break x command
                                // so we're using a goto statement. It is, however, more readable than break 3.
                                goto MOVINGON;
                            }
                        }
                    }

                    MOVINGON : _logger.Log(LogLevel.Info, "Trying to repack");
                }
            } while (tryRepack);

            packedBoxes.InsertAll(overWeightBoxes);
            packedBoxes.InsertAll(underWeightBoxes);

            return(packedBoxes);
        }