예제 #1
0
 /// <summary>
 /// Вернуть блоки шаблона железной дороги в модель
 /// </summary>
 /// <param name="template">Шаблон железной дороги</param>
 /// <param name="model">Модель</param>
 public static void ReturnBlocksToModel(this IRailwayTemplate template, Model model)
 {
     foreach (var item in template.GetRailways())
     {
         model.Blocks.Find(_ => _.Name == item.Name).Count++;
     }
 }
예제 #2
0
 private void Next()
 {
     if (Cursor1Enabled)
     {
         if (_current1.Next != null)
         {
             _current1 = _current1.Next;
         }
         else
         {
             _current1 = _chain;
         }
     }
     if (Cursor2Enabled)
     {
         if (_current2.Next != null)
         {
             _current2 = _current2.Next;
         }
         else
         {
             _current2 = _chain;
         }
     }
 }
예제 #3
0
        private void RemoveAt(IRailwayTemplate cursor)
        {
            if (!(cursor is Railway railway && railway.Type == RailwayType.L0))
            {
                // Возвращаем блоки в список доступных
                cursor.ReturnBlocksToModel(_answer);

                if (cursor.Prev != null)
                {
                    cursor.Prev.Next = cursor.Next;
                }
                if (cursor.Next != null)
                {
                    cursor.Next.Prev  = cursor.Prev;
                    cursor.Next.Start = cursor.Prev?.End ?? Point.Zero;
                }

                if (cursor == _current1)
                {
                    _current1 = cursor.Prev;
                }
                else if (cursor == _current2)
                {
                    _current2 = cursor.Prev;
                }
            }
        }
예제 #4
0
        /// <summary>
        /// Преобразовать двусвязный список шаблонов железной дороги в модель по ТЗ
        /// </summary>
        /// <param name="head">Указатель на начало списка</param>
        /// <param name="initial">Исходные данные модели (блоки DATA, ROUTES)</param>
        /// <returns></returns>
        public static Model ConvertToModel(this IRailwayTemplate head, Model initial = null)
        {
            // Копируем исходные данные
            var model = Model.Copy(initial);

            model.Topology.Clear();
            model.Order.Clear();

            var k        = 0;
            var template = head;

            do
            {
                // Разбиваем шаблон железной дороги на отдельные блоки
                var railways = template.GetRailways();
                for (var i = 0; i < railways.Count; i++)
                {
                    var railway = railways[i];

                    if (railway.Type == RailwayType.L0)
                    {
                        continue;
                    }

                    var source      = k + i - 1;
                    var destination = source + 1;

                    // Добавляем каждый блок в модель
                    model.Order.Add(railway.Name);

                    var topology = new TopologyItem(source, destination, railway.Direction);
                    model.Topology.Add(topology);
                }

                template = template.Next;
                k       += railways.Count;

                if (template == null)
                {
                    var topology = new TopologyItem(k - 1, k, railways.Last().Direction);
                    model.Topology.Add(topology);
                }
            }while (template != null);

            model.Topology.Last().SecondBlock = 0;

            return(model);
        }
예제 #5
0
        /// <summary>
        /// Цепочка блоков рельсов
        /// </summary>
        /// <param name="railways">Блоки рельсов</param>
        public RailwayChain(params IRailwayTemplate[] railways)
        {
            for (var i = 0; i < railways.Length; i++)
            {
                if (i == 0)
                {
                    _head = railways[i];
                    _tail = _head;
                    continue;
                }

                _tail = _tail.Append(railways[i]);
            }

            Dimensions = new TemplateDimensions(this, false);
        }
예제 #6
0
 private void Prev()
 {
     if (Cursor1Enabled)
     {
         if (!(_current1 is Railway railway && railway.Type == RailwayType.L0))
         {
             _current1 = _current1.Prev;
         }
         else
         {
             while (_current1?.Next != null)
             {
                 _current1 = _current1.Next;
             }
         }
     }
예제 #7
0
        /// <summary>
        /// Симметричное добавление шаблона к текущему шаблону
        /// </summary>
        /// <param name="destination">Текущий шаблон (шаблон назначения)</param>
        /// <param name="template">Образец присоединяемого шаблона</param>
        /// <exception cref="InvalidOperationException" />
        public static void AppendSymmetric(this IRailwayTemplate destination, IRailwayTemplate template)
        {
            if (destination.Symmetric == null)
            {
                throw new InvalidOperationException("Отсутствует симметричная точка для назначенного шаблона");
            }

            // Создаём копии шаблона
            var forward  = template.Clone();
            var backward = template.Clone();

            // Добавляем шаблоны в две точки разрыва
            destination.Append(forward);
            destination.Symmetric.Append(backward);
            // Связываем добавленные блоки связью симметрии
            forward.Symmetric  = backward;
            backward.Symmetric = forward;
        }
예제 #8
0
        /// <summary>
        /// Присоединить шаблон железной дороги к существующему шаблону железной дороги
        /// </summary>
        /// <param name="first">Существующий шаблон железной дороги</param>
        /// <param name="second">Присоединяемый шаблон железной дороги</param>
        /// <returns></returns>
        public static IRailwayTemplate Append(this IRailwayTemplate first, IRailwayTemplate second)
        {
            var next = first.Next;

            first.Next  = second;
            second.Prev = first;

            // Если у существующего шаблона было продолжение,
            // то присоединяем его к присоединяемому шаблону
            // TODO: Если у присоединяемого блока есть продолжение, то оно потеряется!
            if (next != null && next != second)
            {
                second.Next      = next;
                second.Next.Prev = second;
            }

            second.Start = first.End;

            return(second);
        }
예제 #9
0
        /// <summary>
        /// Размеры шаблона
        /// </summary>
        /// <param name="railway">Шаблон</param>
        /// <param name="shouldClone">Стоит ли клонировать объект</param>
        public TemplateDimensions(IRailwayTemplate railway, bool shouldClone = true)
        {
            var template = shouldClone ? railway.Clone() : railway;

            var railways = template.GetRailways();
            var points   = railways.Select(_ => _.Start).ToList();

            points.AddRange(railways.Select(_ => _.End));

            if (points.Count > 0)
            {
                Min = new Point(points.Min(_ => _.X), points.Min(_ => _.Y));
                Max = new Point(points.Max(_ => _.X), points.Max(_ => _.Y));
            }

            Output = new Point(
                template.End.X - template.Start.X,
                template.End.Y - template.Start.Y,
                template.End.Angle - template.Start.Angle);

            Width  = Max.X - Min.X;
            Height = Max.Y - Min.Y;
        }
예제 #10
0
        private void Add(string blueprint)
        {
            if (Cursor1Enabled)
            {
                if (RailwayFactory.Default.TryBuildTemplate(out var template, out var error, blueprint, _answer))
                {
                    _current1.Append(template);

                    if (_current1?.Next != null)
                    {
                        _current1 = _current1.Next;
                    }
                }
                else
                {
                    Context.ErrorMessage = error;
                }
            }

            if (Cursor2Enabled)
            {
                if (RailwayFactory.Default.TryBuildTemplate(out var template, out var error, blueprint, _answer))
                {
                    _current2.Append(template);

                    if (_current2?.Next != null)
                    {
                        _current2 = _current2.Next;
                    }
                }
                else
                {
                    Context.ErrorMessage = error;
                }
            }
        }
예제 #11
0
        /// <inheritdoc />
        /// <exception cref="ArgumentNullException" />
        public FinalAnswer Solve(Model model, IDirectTaskSolver checker)
        {
            _model = model; // ?? throw new ArgumentNullException(nameof(model));

            var factory = new RailwayFactory();

            // Разброс точек маршрута
            var routesSize = GetRoutesSize(model);

            // Создать стартовую трассу - кольцо
            var cycle = RailwayTemplates.CreateCircle(RailwayType.T4R);

            // Функция отображения модели
            void DisplayStep(IRailwayTemplate t)
            {
                _answer = t.ConvertToModel(_model);
                OnStepEvent?.Invoke(this, new FinalAnswer(_answer, checker.Solve(_answer)));
            }

            DisplayStep(cycle);

            var compass = RailwayTemplates.Compass(cycle);

            var              l            = 2;
            const int        CYCLES_COUNT = 5;
            IRailwayTemplate head         = cycle;

            for (var k = 0; k < CYCLES_COUNT; k++)
            {
                // Left
                for (var i = 0; i < l; i++)
                {
                    if (!head.TryScale(Direction.E, Railway.L3))
                    {
                        break;
                    }
                    DisplayStep(cycle);
                }

                // Up
                var chain1 = factory.BuildTemplate("t2T1L6", model);
                head.TryMutate(chain1);
                DisplayStep(cycle);

                // Up
                for (var i = 0; i < l; i++)
                {
                    if (!chain1.TryScale(Direction.N, Railway.L3))
                    {
                        break;
                    }
                    DisplayStep(cycle);
                }

                // Right
                var chain2 = factory.BuildTemplate("t2T1L6", model);
                chain1.TryMutate(chain2);
                DisplayStep(cycle);

                l += 3;

                // Right
                for (var i = 0; i < l; i++)
                {
                    if (!chain2.TryScale(Direction.W, Railway.L3))
                    {
                        break;
                    }
                    DisplayStep(cycle);
                }

                // Down
                var chain3 = factory.BuildTemplate("t2T1L6", model);
                chain2.TryMutate(chain3);
                DisplayStep(cycle);

                // Down
                for (var i = 0; i < l; i++)
                {
                    if (!chain3.TryScale(Direction.S, Railway.L3))
                    {
                        break;
                    }
                    DisplayStep(cycle);
                }

                // Right
                var chain4 = factory.BuildTemplate("t2T1L6", model);
                chain3.TryMutate(chain4);
                DisplayStep(cycle);

                head = chain4;
                l   += 3;
            }


            // Первый этап - расширяем кольцо вверх, вниз и в сторону

            /*
             * const int count = 16;
             * for (var i = 0; i < count; i++)
             * {
             *  // Блок, к которому добавляем L1
             *  var dest = compass.W;
             *
             *  // Расширение по сторонам
             *  if (i < count / 4) dest = compass.W;
             *  //else if (i < 2 * count / 4) dest = compass.NW;
             *  else if (i < 3 * count / 4) dest = compass.N;
             *  //else if (i < 4 * count / 4) dest = compass.NE;
             *
             *  // Чередование расширений по сторонам
             *  //if (i % 4 == 0) dest = compass.W;
             *  //else if (i % 4 == 1) dest = compass.NW;
             *  //else if (i % 4 == 2) dest = compass.N;
             *  //else if (i % 4 == 3) dest = compass.NE;
             *
             *  var chain = new RailwayChain(new[]
             *  {
             *      new Railway(RailwayType.T8L),
             *      new Railway(RailwayType.T8R),
             *  });
             *  //dest.AppendSymmetric(chain);
             *
             *  dest.AppendSymmetric(Railway.L1);
             *
             *  DisplayStep(cycle);
             * }
             */

            return(new FinalAnswer
            {
                Model = _answer,
                Price = checker.Solve(_answer),
            });
        }
예제 #12
0
 /// <summary>
 /// Вызвать изменение размера
 /// в указанном или любом направлении
 /// </summary>
 /// <param name="item">Шаблон масштабирования</param>
 /// <param name="direction">Направление</param>
 /// <param name="template">Шаблон для вставки. Если null - то вставить любой блок</param>
 /// <returns>True - если получилось, иначе - false</returns>
 public static bool TryScale(this IRailwayTemplate item, Direction direction, IRailwayTemplate template = null)
 {
     return(item.TryScale(direction.ToAngle(), template));
 }
예제 #13
0
 /// <summary>
 /// Является ли данный элемент начальным (L0)
 /// </summary>
 /// <param name="item"></param>
 /// <returns></returns>
 public static bool IsHead(this IRailwayTemplate item)
 {
     return(item is Railway railway && railway.Type == RailwayType.L0);
 }
예제 #14
0
        /// <summary>
        /// Найти все пересечения блоков рельс
        /// </summary>
        /// <param name="template"></param>
        /// <param name="includeBridges">Включая пересечения под мостами</param>
        /// <returns>Список точек пересечения или пустой список</returns>
        public static List <Point> FindCrosses(this IRailwayTemplate template, bool includeBridges = false)
        {
            var sync   = new object();
            var answer = new List <Point>();

            var railways = template.GetRailways().ToArray();

            Parallel.For(0, railways.Length, (i) =>
            {
                for (var j = i + 2; j < railways.Length; j++)
                {
                    if (railways[i].IsHead() || i == 1 && j == railways.Length - 1)
                    {
                        continue;
                    }

                    if (MathFunctions.CrossPoint(
                            railways[i].Start, railways[i].End,
                            railways[j].Start, railways[j].End) is Point p)
                    {
                        if (!includeBridges)
                        {
                            var bridge =
                                (railways[i].Type == RailwayType.B1) ? railways[i] :
                                (railways[j].Type == RailwayType.B1) ? railways[j] : null;

                            if (bridge == null)
                            {
                                lock (sync)
                                {
                                    answer.Add(p);
                                }
                                continue;
                            }

                            var center = new Point(
                                x: (bridge.Start.X + bridge.End.X) / 2,
                                y: (bridge.Start.Y + bridge.End.Y) / 2
                                );

                            if (p != center)
                            {
                                lock (sync)
                                {
                                    answer.Add(p);
                                }
                            }
                        }
                        else
                        {
                            lock (sync)
                            {
                                answer.Add(p);
                            }
                        }
                    }
                }
            });


            return(answer);
        }
예제 #15
0
        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);
        }