/// <inheritdoc /> public FinalAnswer Solve(Model model, IDirectTaskSolver checker) { _model = model; _answer = Model.Copy(model); _checker = checker; Best = new FinalAnswer(_answer, _checker.Solve(_answer)); _chain = RailwayChain.FromModel(_answer, reduceCount: true); _current = _chain; try { Main(); } catch (OperationCanceledException) { Console.WriteLine("Алгоритм AmplifierFinalSolver остановлен"); } catch (Exception e) { Console.WriteLine($"Ошибка в AmplifierFinalSolver: {e}"); } finally { var ans = Model.Copy(Best.Model); ans.Blocks.Clear(); ans.Blocks.AddRange(_model.Blocks); Best = new FinalAnswer(ans, _checker.Solve(ans)); } return(Best); }
/// <summary> /// Решить обратную задачу /// </summary> /// <param name="model">Неполная модель исходных данных (только блоки DATA и ROUTE)</param> /// <param name="checker">Алгоритм решения прямой задачи - для вычисления стоимости</param> /// <returns>Полная модель (включая блоки ORDER и TOP)</returns> public FinalAnswer Solve(Model model, IDirectTaskSolver checker) { _model = model; _answer = Model.Copy(model); _checker = checker; var chain = RailwayChain.FromModel(_answer, true); _current1 = _chain = new Railway(RailwayType.L0); foreach (var railway in chain.GetRailways()) { if (railway.IsHead()) { continue; } _current1.Append(railway); _current1 = _current1.Next; } _current1 = _current2 = _chain; Context = new DrawableContext(); Context.BotsRating = "Управление:\n" + "W: Add L3\n" + "A: Add 2xT4L\n" + "S: Remove\n" + "D: Add 2xT4R\n" + "B: Add Bridge\n" + "Q: Prev item\n" + "E: Next item\n" + "Shift+W: L1\n" + "Shift+A: T4L\n" + "Shift+D: T4R\n" + "Z: Sync curs\n" + "X: Swap curs\n" + "C: Change mode\n" + "V: Insert tmpl\n" + ""; SendAnswer(); while (!Token.IsCancellationRequested) { Thread.Sleep(500); } _answer.Blocks.Clear(); _answer.Blocks.AddRange(_model.Blocks); Context = new DrawableContext(); SendAnswer(); return(new FinalAnswer() { Model = _answer, Price = checker.Solve(_answer) }); }
public void Test_1_SubTemplate_L6T2R() { var chain = new RailwayChain(Railway.L3, Railway.L3, Railway.T4R, Railway.T4R); var head = new Railway(RailwayType.L0); head.Append(chain); var destination = new Point(3, 9, -Math.PI / 2); var indexes = chain.FindSubTemplate(destination); Assert.IsNotNull(indexes); Assert.AreEqual(chain[0], indexes?.start); Assert.AreEqual(chain[3], indexes?.end); }
public void Test_3_SubTemplate_L6T2L_Rotated() { var chain = new RailwayChain(Railway.L3, Railway.L3, Railway.T4L, Railway.T4L); var head = new Railway(RailwayType.L0); var last = head.Append(Railway.T4R); last = last.Append(Railway.T4R); last.Append(chain); var destination = new Point(-3, 9, Math.PI / 2); var indexes = chain.FindSubTemplate(destination); Assert.IsNotNull(indexes); Assert.AreEqual(chain[0], indexes?.start); Assert.AreEqual(chain[3], indexes?.end); }
private void Main() { var library = new List <string> { "L1L1L1", "L1L1", "L2", "L3", "L4", "t2", "T2", "T2L1", "t2L1", "T2L2", "t2L2", "T2L3", "t2L3", "L6t2t2L6", "L6T2T2L6", }; library.AddRange(RailwayTemplates.Library); // Перебираем каждый шаблон библиотеки //foreach (var blueprint in library) Parallel.ForEach(library, blueprint => { var answer = Model.Copy(_answer); if (!RailwayFactory.Default.TryBuildTemplate(out var template, out var error, blueprint, answer)) { //continue; return; } var chain = RailwayChain.FromModel(answer); // Все под-шаблоны исходной цепочки, которые можно заменить на подходящий шаблон var subTemplates = chain.FindSubTemplates(template.Dimensions.Output); template.ReturnBlocksToModel(answer); var cur = chain[0]; for (var j = 0; j < subTemplates.Count; j++) { //TODO chain = chain.Copy; if (!RailwayFactory.Default.TryBuildTemplate(out template, out _, blueprint, answer)) { break; } var(length, start, end) = subTemplates[j]; var finish = true; while (cur != null) { if (cur == start) { finish = false; } if (cur == end) { break; } cur = cur.Next; if (cur is Railway r && r.IsHead()) { break; } } if (finish) { continue; } // Присоединяем новый шаблон { if (start.Prev != null) { start.Prev.Next = template; } template.Prev = start.Prev; if (end.Next != null) { end.Next.Prev = template; } template.Next = end.Next; template.Start = start.Start; } var result = chain.ConvertToModel(answer); var price = _checker.Solve(result); lock (_sync) { if (price.Result > Best.Price.Result) { // Проверяем на пересечения: if (RailwayChain.FromModel(result).FindCrosses().Count == 0) { Best = new FinalAnswer(result, price); OnStepEvent?.Invoke(this, Best); } } } } });
public bool TryBuildTemplate(out IRailwayTemplate template, out string error, string blueprint, Model model) { // Копируем список блоков var blocks = model?.Blocks.Select(block => (Block)block.Clone()).ToList(); error = null; var regex = new Regex("((?'type'L|T|t|B)(?'lenght'\\d+))"); var railways = new List <Railway>(); foreach (Match match in regex.Matches(blueprint)) { var type = match.Groups["type"].Value; var length = int.Parse(match.Groups["lenght"].Value); switch (type) { case "L": { for (var k = 4; k > 0; k--) { var lineBlocks = blocks?.FirstOrDefault(_ => _.Name == $"L{k}"); while (lineBlocks?.Count > 0 && length >= k) { length -= k; lineBlocks.Count--; var railway = k == 4 ? Railway.L4 : k == 3 ? Railway.L3 : k == 2 ? Railway.L2 : Railway.L1; railways.Add(railway); } } break; } case "T": case "t": { var amount = 0; switch (length) { case 1: amount = 8; break; // T1 = 8 x T8 case 2: amount = 4; break; // T2 = 4 x T8 case 4: amount = 2; break; // T4 = 2 x T8 case 8: amount = 1; break; // T8 = 1 x T8 default: error = $"Некорректная длина блока {type}{length} в шаблоне {blueprint}"; template = null; return(false); } var t4Blocks = blocks?.FirstOrDefault(_ => _.Name == "T4"); var t8Blocks = blocks?.FirstOrDefault(_ => _.Name == "T8"); if (t8Blocks?.Price < t4Blocks?.Price) { while (t8Blocks?.Count > 0 && amount >= 1) { if (t8Blocks?.Count == 1 && amount == 2) { break; } amount -= 1; t8Blocks.Count--; railways.Add(type == "T" ? Railway.T8R : Railway.T8L); } } while (t4Blocks?.Count > 0 && amount >= 2) { amount -= 2; t4Blocks.Count--; railways.Add(type == "T" ? Railway.T4R : Railway.T4L); } while (t8Blocks?.Count > 0 && amount > 0) { amount -= 1; t8Blocks.Count--; railways.Add(type == "T" ? Railway.T8R : Railway.T8L); } if (amount == 0) { length = 0; } break; } case "B": { if (length != 1) { throw new ArgumentException( $"Некорректная длина блока {type}{length} в шаблоне {blueprint}"); } var bridgeBlocks = blocks?.FirstOrDefault(_ => _.Name == "B1"); if (bridgeBlocks?.Count > 0) { length--; bridgeBlocks.Count--; railways.Add(Railway.B1); } break; } } if (length != 0) { error = $"Недостаточно блоков для производства {match.Value} в шаблоне {blueprint}"; template = null; return(false); } } var chain = new RailwayChain(railways.Cast <IRailwayTemplate>().ToArray()); // Создаём автоматические связи симметрии // TODO переделать var directions = chain.GetDirections(); if (directions.ContainsKey(Direction.N) && directions.ContainsKey(Direction.S)) { foreach (var block in directions[Direction.N]) { block.Symmetric = directions[Direction.S].First(); } } if (directions.ContainsKey(Direction.W) && directions.ContainsKey(Direction.E)) { foreach (var block in directions[Direction.W]) { block.Symmetric = directions[Direction.E].First(); } } // Если произвести блок удалось // применяем изменение количества блоков model?.Blocks.Clear(); model?.Blocks.AddRange(blocks); if (chain.GetRailways().Count == 1) { template = chain[0]; return(true); } template = chain; return(true); }