private void UpdatePresentItems(MyComponentGroupDefinition group, Dictionary<MyDefinitionId, MyFixedPoint> componentCounts)
 {
     m_presentItems.Clear();
     for (int i = 1; i <= group.GetComponentNumber(); i++)
     {
         var compDef = group.GetComponentDefinition(i);
         MyFixedPoint amount = 0;
         componentCounts.TryGetValue(compDef.Id, out amount);
         m_presentItems[i] = (int)amount;
     }
 }
        private int SplitHelper(MyComponentGroupDefinition group, int splitItemValue, int resultItemValue, int numItemsToSplit, int splitCount)
        {
            int remainder = splitItemValue - (splitCount * resultItemValue);
            MyDefinitionId removedComponentId = group.GetComponentDefinition(splitItemValue).Id;
            if (remainder != 0)
            {
                MyDefinitionId addedComponentId = group.GetComponentDefinition(remainder).Id;
                AddPresentItems(remainder, numItemsToSplit);
                AddChangeToSolution(removedComponentId, addedComponentId, numItemsToSplit);
            }
            else
            {
                AddRemovalToSolution(removedComponentId, numItemsToSplit);
            }

            return splitCount * numItemsToSplit;
        }
        private int TryCreatingItemsByMerge(MyComponentGroupDefinition group, int itemValue, int itemCount)
        {
            // Removal buffer is here so that the method does not do anything until it's clear that the operation can be successful
            List<int> removalBuffer = m_listAllocator.Allocate();
            removalBuffer.Clear();
            for (int i = 0; i <= group.GetComponentNumber(); ++i)
            {
                removalBuffer.Add(0);
            }

            int createdCount = 0;

            // Create the items one-by-one
            for (int i = 0; i < itemCount; ++i)
            {
                // What remains to be found to create this item
                int remainder = itemValue;

                // Fill this item with smaller items as long as possible
                for (int k = itemValue - 1; k >= 1; k--)
                {
                    int amount = 0;
                    if (m_presentItems.TryGetValue(k, out amount))
                    {
                        int removeCount = Math.Min(remainder / k, amount);
                        if (removeCount > 0)
                        {
                            remainder = remainder - k * removeCount;
                            amount -= removeCount;
                            removalBuffer[k] += removeCount;
                        }
                    }
                }

                // The remainder was not reduced by the remaining items, which means that we don't have any items left
                if (remainder == itemValue)
                {
                    Debug.Assert(m_presentItems.Count == 0 || itemValue == 1, "There are still items present in the cutting solver, but they were not used in the solution!");
                    break;
                }

                // There are no more smaller items to fill the remainder. Try to split one of the larger ones
                if (remainder != 0)
                {
                    for (int j = remainder + 1; j <= group.GetComponentNumber(); ++j)
                    {
                        int present = 0;
                        m_presentItems.TryGetValue(j, out present);
                        // If there is some present item that is not planned to be removed, use it
                        if (present > removalBuffer[j])
                        {
                            MyDefinitionId removedComponentId = group.GetComponentDefinition(j).Id;
                            MyDefinitionId addedComponentId = group.GetComponentDefinition(j - remainder).Id;
                            AddChangeToSolution(removedComponentId, addedComponentId, 1);
                            int removed = TryRemovePresentItems(j, 1);
                            AddPresentItems(j - remainder, 1);
                            Debug.Assert(removed == 1);
                            remainder = 0;
                            break;
                        }
                    }
                }

                if (remainder == 0)
                {
                    createdCount++;
                    // Add the buffered removals of the smaller items here
                    for (int k = 1; k <= group.GetComponentNumber(); ++k)
                    {
                        if (removalBuffer[k] > 0)
                        {
                            MyDefinitionId removedComponentId = group.GetComponentDefinition(k).Id;
                            int removed = TryRemovePresentItems(k, removalBuffer[k]);
                            Debug.Assert(removed == removalBuffer[k]);
                            AddRemovalToSolution(removedComponentId, removalBuffer[k]);
                            removalBuffer[k] = 0; // We need to clear the buffer for the next item
                        }
                    }
                } // The item could not be created and neither would be the others
                else if (remainder > 0) break;
            }

            m_listAllocator.Deallocate(removalBuffer);

            return createdCount;
        }
        private int TryCreatingItemsBySplit(MyComponentGroupDefinition group, int itemValue, int itemCount)
        {
            int createdCount = 0;
            // Avoid making too much "mess" by trying to find the best-fitting items first
            for (int k = itemValue + 1; k <= group.GetComponentNumber(); k++)
            {
                int fitNumber = k / itemValue; // How many items fit into k-item

                int wholeCount = itemCount / fitNumber; // How many k-items will be fully split

                int partialFitNumber = itemCount % fitNumber;              // How many items will be created from the last k-item
                int partialCount = partialFitNumber == 0 ? 0 : 1;          // How many k-items will be partially split (either 0 or 1 that is)

                int removedCount = TryRemovePresentItems(k, wholeCount + partialCount);
                if (removedCount > 0)
                {
                    int removedWholeCount = Math.Min(removedCount, wholeCount);
                    if (removedWholeCount != 0)
                    {
                        int created = SplitHelper(group, k, itemValue, removedWholeCount, fitNumber);
                        createdCount += created;
                        itemCount -= created;
                    }

                    if (removedCount - wholeCount > 0)
                    {
                        Debug.Assert(removedCount == wholeCount + partialCount && partialCount == 1, "Calculation problem in cutting solver");
                        int created = SplitHelper(group, k, itemValue, 1, partialFitNumber);
                        createdCount += created;
                        itemCount -= created;
                    }
                }
            }

            return createdCount;
        }