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>
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user