public static Zakaz LoadFile() { OpenFileDialog dlg = new OpenFileDialog(); dlg.DefaultExt = "txt"; dlg.Filter = "текстові файли (*.txt)|*.txt|всі файли (*.*)|*.*"; dlg.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Desktop); if (dlg.ShowDialog() == DialogResult.OK) { Zakaz result = new Zakaz(); StreamReader sr = new StreamReader(dlg.OpenFile(), Encoding.GetEncoding(1251)); int idCounter = 0; while (!sr.EndOfStream) { idCounter++; string ts = sr.ReadLine(); string rawRun; string etName; if (ts.Contains("\t") || ts.Contains(" ")) { int delimeter = ts.LastIndexOf("\t"); if (delimeter < ts.LastIndexOf(" ")) { delimeter = ts.LastIndexOf(" "); } rawRun = ts.Substring(delimeter); etName = ts.Substring(0, delimeter); } else { rawRun = ts; etName = "Et_" + ts; } int run = 0; try { run = int.Parse(rawRun); } catch (FormatException) { if (MessageBox.Show("Помилка у наданому текстовому файлі. Не можу прочитати наклад з текстового рядка: \n" + ts + "\nПродовжити читання файлу?", "Помилка", MessageBoxButtons.OKCancel, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1) == DialogResult.Cancel) { sr.Close(); return(null); } } Etyketka et = new Etyketka(idCounter, etName, run); result.Add(et); } sr.Close(); if (result.Count < 1) { return(null); } return(result); } return(null); }
}//end:FirstPass /// <summary> /// Splits ets list based on 'MagicNumbers' and processes produced sublists /// </summary> public static StatsList FindBestRunWithShifting(Zakaz ets) { //Given ets become immutable, because NormalizeAndSort() returns new object, //and sorted from max to min by ryn Zakaz _ets = ets.NormalizeAndSort(); //For small Zakaz just find the best run if (_ets.Count <= Constants.ETS_ON_SHEET) { return(new StatsList() { FindBestRun(_ets) }); } StatsList result = new StatsList(); Zakaz tmpEts = new Zakaz(); List <int> magicNumbers = _ets.SplitMarkers; for (int i = 0; i < _ets.Count; i++) { if (!magicNumbers.Contains(i)) { tmpEts.Add(_ets[i]); } else { result.Add(FindBestRun(tmpEts)); tmpEts = new Zakaz() { _ets[i] }; } }//end:for if (tmpEts.Count > 0 && tmpEts.Count <= Constants.ETS_ON_SHEET) { result.Add(FindBestRun(tmpEts)); } else if (tmpEts.Count <= Constants.ETS_ON_SHEET * 2) { result.AddRange(TwoPartsRebalancer(tmpEts)); } else if (tmpEts.Count > Constants.ETS_ON_SHEET * 2) { result.AddRange(SplitFromMinToMax(tmpEts)); } return(result); }//end:FindBestRunWithShifting
}//end:GetMinValidRun /// <summary> /// Sorts given ets, splits them into two groups /// and optimizes these groups via rebalancing them /// </summary> /// <param name="ets">Ets count has to be > 2 and < 2xETS_ON_SHEET</param> protected static StatsList TwoPartsRebalancer(Zakaz ets) { //Ets count has to be > 2 and < 2xETS_ON_SHEET if (ets.Count <= 2 || ets.Count >= Constants.ETS_ON_SHEET * 2) { throw new ArgumentOutOfRangeException(); } //Make given ets immutable Zakaz _ets = new Zakaz(ets); StatsList result = new StatsList(); _ets.Sort(new CompareEtsByRunMinToMax()); //When we have _ets less than for two sheets, //split them into two parts //Take the first ETS_ON_SHEET ets to the first part Zakaz part1 = new Zakaz(_ets.GetRange(0, Constants.ETS_ON_SHEET)); //Take all remained ets to the second part Zakaz part2 = new Zakaz(_ets.GetRange(Constants.ETS_ON_SHEET, _ets.Count - 1 - Constants.ETS_ON_SHEET)); //Calculate stats for both parts result.Add(GetStatsForRun(part1, GetMinValidRun(part1))); result.Add(GetStatsForRun(part2, GetMinValidRun(part2))); //Try to rebalance Part1 and Part2 to obtain the best stats StatsList tmpResult; while (part2.Count < Constants.ETS_ON_SHEET) { part2.Add(part1[part1.Count - 1]); part1.RemoveAt(part1.Count - 1); tmpResult = new StatsList(); tmpResult.Add(GetStatsForRun(part1, GetMinValidRun(part1))); tmpResult.Add(GetStatsForRun(part2, GetMinValidRun(part2))); if (tmpResult < result) { result = tmpResult; } }//while return(result); }//end:PackIntoSheet
}//end:PackIntoSheet /// <summary> /// Splits given ets to groups based on GCD. /// </summary> protected static List <Zakaz> SplitByGcdToGroups(Zakaz ets) { //Sort ets by run from max to min ets.Sort(new CompareEtsByRunMaxToMin()); //Take every et and collect all other ets which runs are GCD of this et run List <Zakaz> gcdGroups = new List <Zakaz>(); foreach (Etyketka et in ets) { Zakaz group = new Zakaz(from e in ets where IsGcd(et, e) select e); if (group.Count > 0 && !gcdGroups.Contains(group)) { gcdGroups.Add(group); } } //Remove dublicated ets, so that result returned //would have only one instance of each et List <Zakaz> result = new List <Zakaz>(); Zakaz garbage = new Zakaz(); bool present; //Indicates if current et is already present in the result //Take every group from gcdGroups sorted by number of ets from max to min foreach (Zakaz group in (from z in gcdGroups orderby z.Count descending select z)) { present = false; foreach (Etyketka et in group) { foreach (Zakaz resultGroup in result) { //If current et is already in the result, then drop this group if (resultGroup.Contains(et)) { present = true; goto FIN; //Exit from inner and outer for-loops } } } FIN: if (!present) { //If all ets of current group are not present in the result, //add this group to the result result.Add(group); } else { //Add current group to garbage foreach (Etyketka et in group) { if (!garbage.Contains(et)) { garbage.Add(et); } } } //else } //foreach if (garbage.Count > 0) { result.Add(garbage); } return(result); }//end:SplitByGcdToGroups
}//end:FindBestRun ///<summary> ///Splits provided list of ets and applies FirstPass on each sublist. ///Collects OutStats from each FirstPass and returns them as single list. ///</summary> protected static StatsList SplitFromMinToMax(Zakaz ets) { //Make given ets immutable Zakaz _ets = new Zakaz(ets); //Order ets by runs _ets.Sort(new CompareEtsByRunMinToMax()); int runIncrement = 0; StatsList TheBestResult = null; Zakaz zakazForMinRun = null; OutStats statsForMinRun = null; do { //Split ets to groups with the sum count on the sheet <= Constants.ETS_ON_SHEET //and build temporary stats list statsForMinRun = GetStatsForRun(_ets, _ets.MinRun + runIncrement); //For now statsForMinRun are not valid, but we don't bother, //because we would split ets later zakazForMinRun = statsForMinRun.Ets; StatsList tmpResult = new StatsList(); Zakaz part1; Zakaz part2; do { part1 = new Zakaz(); part2 = new Zakaz(); int count = 0; foreach (Etyketka et in zakazForMinRun) { if (count + et.CountOnSheet <= Constants.ETS_ON_SHEET) { //Select first ets group that fits at one sheet part1.Add(et); } else { //Add all other ets to the second group part2.Add(et); } count += et.CountOnSheet; }//foreach //Part1 is valid, as far as previous if-expression is true OutStats os = GetStatsForRun(part1, part1.MinRun + runIncrement); if (!os.IsValid) { if (TheBestResult != null) { return(TheBestResult); } else { throw new Exception("Invalid Algorithm!"); } } tmpResult.Add(os); //For second group recalculating stats with its MinRun if (part2.Count > 0) { statsForMinRun = GetStatsForRun(part2, part2.MinRun + runIncrement); //For now statsForMinRun are not valid, but we don't bother, //because we would split part2 in the next loop zakazForMinRun = statsForMinRun.Ets; } } while (part2.Count > 0); //Select the best result as the final result returned if (TheBestResult == null) { TheBestResult = tmpResult; } if (TheBestResult > tmpResult) { TheBestResult = tmpResult; } runIncrement += 100; } while (_ets.MinRun + runIncrement <= _ets.MaxRun); return(TheBestResult); }//end:SplitFromMinToMax