Files
CutList/CutList.Core/Nesting/Pipeline/DuplicateBinsStep.cs
AJ Isaacs b19ecf3610 refactor: Redesign nesting engines with pipeline pattern and add exhaustive search
- Rename Result to PackResult to avoid confusion with Result<T>
- Add PackingRequest as immutable configuration replacing mutable engine state
- Add PackingStrategy enum (AdvancedFit, BestFit, Exhaustive)
- Implement pipeline pattern for composable packing steps
- Rewrite AdvancedFitEngine as stateless using pipeline
- Rewrite BestFitEngine as stateless
- Add ExhaustiveFitEngine with symmetry breaking for optimal solutions
  - Tries all bin assignments to find minimum bins
  - Falls back to AdvancedFit for >20 items
  - Configurable threshold via constructor
- Update IEngine/IEngineFactory interfaces for new pattern
- Add strategy parameter to MCP tools

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 15:16:40 -05:00

61 lines
2.0 KiB
C#

namespace CutList.Core.Nesting.Pipeline
{
/// <summary>
/// Creates duplicate bins when the same packing pattern can be repeated.
/// If there are enough remaining items to fill another bin identically,
/// creates copies to reduce iteration overhead.
/// </summary>
public class DuplicateBinsStep : IPackingStep
{
public void Execute(PackingContext context)
{
// Process bins that were created before this step
// We need a copy since we'll be adding new bins
var originalBins = context.Bins.ToList();
foreach (var originalBin in originalBins)
{
CreateDuplicateBins(originalBin, context);
}
}
private static void CreateDuplicateBins(Bin originalBin, PackingContext context)
{
int duplicateCount = GetDuplicateCount(originalBin, context.RemainingItems);
for (int i = 0; i < duplicateCount; i++)
{
if (!context.CanAddMoreBins())
break;
var newBin = context.CreateBin();
foreach (var item in originalBin.Items)
{
var matchingItem = context.RemainingItems.FirstOrDefault(a => a.Length == item.Length);
if (matchingItem != null)
{
newBin.AddItem(matchingItem);
context.RemainingItems.Remove(matchingItem);
}
}
context.Bins.Add(newBin);
}
}
private static int GetDuplicateCount(Bin bin, List<BinItem> remainingItems)
{
int count = int.MaxValue;
foreach (var lengthGroup in bin.Items.GroupBy(i => i.Length))
{
int availableCount = remainingItems.Count(i => i.Length == lengthGroup.Key);
count = Math.Min(count, availableCount / lengthGroup.Count());
}
return count == int.MaxValue ? 0 : count;
}
}
}