public void FindAll() { var materials = new WoodList(); materials.Load("materials.csv"); var parts = new WoodList(); parts.Load("parts.csv"); foreach (string dimension in parts.Keys) { var dimensionMaterials = materials[dimension]; var dimensionParts = parts[dimension]; if (dimensionMaterials.Distinct().Count() == 1) { CutOrder cutOrder = FillLongestToShortest(dimension, dimensionMaterials.First(), dimensionParts); if (CutOrderFound != null) { CutOrderFound(this, new CutOrderEventArgs(cutOrder)); } } else { throw new NotSupportedException("Cannot calculate optimal for varying material lengths"); } } }
private static void Main(string[] args) { CutOrder cutOrder = CutListCalculator.FindOptimal(); const string outFile = "out.csv"; File.WriteAllText(outFile, cutOrder.ToString()); }
public static CutOrder FindOptimal() { var calculator = new CutListCalculator(); var dimensionOptimals = new Dictionary <string, CutOrder>(); var dimensionWasteLengths = new Dictionary <string, decimal>(); calculator.CutOrderFound += (sender, e) => { string dimension = e.CutOrder.First().Key.Dimension; lock (dimensionOptimals) { lock (dimensionWasteLengths) { CutOrder optimalCutOrder; if (!dimensionOptimals.TryGetValue(dimension, out optimalCutOrder)) { dimensionOptimals.Add(dimension, e.CutOrder); return; } decimal optimalWasteLength; if (!dimensionWasteLengths.TryGetValue(dimension, out optimalWasteLength)) { optimalWasteLength = optimalCutOrder.ComputeWaste(); dimensionWasteLengths.Add(dimension, optimalWasteLength); } // Compute the waste length fo the current cut order decimal wasteLength = e.CutOrder.ComputeWaste(); // If the waste length of the current is better than the best, then use current as the best going forward if (wasteLength < optimalWasteLength) { dimensionWasteLengths[dimension] = wasteLength; dimensionOptimals[dimension] = e.CutOrder; } } } }; calculator.FindAll(); var optimal = new CutOrder(); foreach (string dimension in dimensionOptimals.Keys) { foreach (Board board in dimensionOptimals[dimension].Keys) { optimal.Add(board, dimensionOptimals[dimension][board]); } } return(optimal); }
public object Clone() { var cutOrder = new CutOrder(); foreach (Board board in Keys) { var boardCopy = new Board { Dimension = board.Dimension, Length = board.Length }; var cutListCopy = new List <decimal>(this[board]); cutOrder.Add(boardCopy, cutListCopy); } return(cutOrder); }
private CutOrder FillLongestToShortest(string dimension, decimal boardLength, List <decimal> parts) { if (parts.Any(x => x > boardLength)) { throw new ArgumentException("parts cannot contain any lengths longer than boardLength", "parts"); } var cutOrder = new CutOrder(); decimal currentBoardLength = 0M; var currentBoardCuts = new List <decimal>(); bool isFirst = true; var remainingParts = new List <decimal>(parts); while (remainingParts.Count > 0) { if (isFirst) { decimal firstCut = remainingParts[0]; currentBoardCuts.Add(firstCut); remainingParts.RemoveAt(0); currentBoardLength = boardLength - firstCut; isFirst = false; continue; } // Advanced strategy: for the last two cuts on the board when we have three or more cuts to go, // find the max two-cut sum that will fit on the current board from the list of available boards PartPair lastCutPair = GetLongestPartPair(remainingParts, currentBoardLength); if (lastCutPair != null) { remainingParts.Remove(lastCutPair.LargerPart); remainingParts.Remove(lastCutPair.SmallerPart); currentBoardCuts.Add(lastCutPair.LargerPart); currentBoardCuts.Add(lastCutPair.SmallerPart); cutOrder.Add(new Board { Dimension = dimension, Length = boardLength }, currentBoardCuts); currentBoardLength = boardLength; currentBoardCuts = new List <decimal>(); isFirst = true; continue; } // Normal strategy: select the longest cut from the remaining parts that will fit on the current board decimal cut = remainingParts.FirstOrDefault(x => currentBoardLength >= (x + Settings.Default.BladeWidth)); if (cut != 0M) { currentBoardCuts.Add(cut); remainingParts.Remove(cut); cut += Settings.Default.BladeWidth; currentBoardLength -= cut; continue; } cutOrder.Add(new Board { Dimension = dimension, Length = boardLength }, currentBoardCuts); currentBoardCuts = new List <decimal> (); currentBoardLength = boardLength; isFirst = true; } if (currentBoardCuts.Count > 0) { cutOrder.Add(new Board { Dimension = dimension, Length = boardLength }, currentBoardCuts); } return(cutOrder); }
public CutOrderEventArgs(CutOrder cutOrder) { CutOrder = cutOrder; }