internal override async Task <PlacementResult> OnSelectActivation(
            PlacementStrategy strategy, GrainId target, IPlacementContext context)
        {
            List <ActivationAddress> places = await context.Lookup(target);

            if (places.Count <= 0)
            {
                // we return null to indicate that we were unable to select a target from places activations.
                return(null);
            }

            if (places.Count == 1)
            {
                return(PlacementResult.IdentifySelection(places[0]));
            }

            // places.Count > 0
            // Choose randomly if there is one, else make a new activation of the target
            // pick local if available (consider making this a purely random assignment of grains).
            var here  = context.LocalSilo;
            var local = places.Where(a => a.Silo.Equals(here)).ToList();

            if (local.Count > 0)
            {
                return(PlacementResult.IdentifySelection(local[random.Next(local.Count)]));
            }
            if (places.Count > 0)
            {
                return(PlacementResult.IdentifySelection(places[random.Next(places.Count)]));
            }
            // we return null to indicate that we were unable to select a target from places activations.
            return(null);
        }
Example #2
0
        private async ValueTask <PlacementResult> GetOrPlaceActivationAsync(
            ValueTask <PlacementResult> selectActivationTask,
            PlacementTarget target,
            PlacementStrategy strategy,
            IPlacementRuntime placementRuntime,
            IPlacementDirector director)
        {
            var placementResult = await selectActivationTask;

            if (placementResult is object)
            {
                return(placementResult);
            }

            var siloAddress = await director.OnAddActivation(strategy, target, placementRuntime);

            ActivationId activationId;

            if (strategy.IsDeterministicActivationId)
            {
                // Use the grain id as the activation id.
                activationId = ActivationId.GetDeterministic(target.GrainIdentity);
            }
            else
            {
                activationId = ActivationId.NewId();
            }

            return(PlacementResult.SpecifyCreation(
                       siloAddress,
                       activationId,
                       strategy));
        }
Example #3
0
        OnAddActivation(PlacementStrategy strategy, GrainId grain, IPlacementContext context)
        {
            var grainType = context.GetGrainTypeName(grain);

            return(Task.FromResult(
                       PlacementResult.SpecifyCreation(context.LocalSilo, strategy, grainType)));
        }
        private async Task <PlacementResult> AddActivation(
            PlacementTarget target,
            IPlacementRuntime context,
            PlacementStrategy strategy)
        {
            if (target.IsClient)
            {
                throw new InvalidOperationException("Client grains are not activated using the placement subsystem.");
            }

            var director    = ResolveDirector(strategy);
            var siloAddress = await director.OnAddActivation(strategy, target, context);

            var grainTypeName = context.GetGrainTypeName(((LegacyGrainId)target.GrainIdentity).TypeCode);

            ActivationId activationId;

            if (strategy.IsDeterministicActivationId)
            {
                // Use the grain id as the activation id.
                activationId = ActivationId.GetDeterministic(target.GrainIdentity);
            }
            else
            {
                activationId = ActivationId.NewId();
            }

            return(PlacementResult.SpecifyCreation(
                       siloAddress,
                       activationId,
                       strategy,
                       grainTypeName));
        }
        public Task <PlacementResult> OnAddActivation(PlacementStrategy strategy, PlacementTarget target, IPlacementContext context)
        {
            var grainType = context.GetGrainTypeName(target.GrainId);

            return(Task.FromResult(
                       PlacementResult.SpecifyCreation(context.LocalSilo, strategy, grainType)));
        }
Example #6
0
        public virtual Task <PlacementResult> OnAddActivation(
            PlacementStrategy strategy, GrainId grain, IPlacementContext context)
        {
            var grainType = context.GetGrainTypeName(grain);
            var allSilos  = context.AllActiveSilos;

            return(Task.FromResult(
                       PlacementResult.SpecifyCreation(allSilos[random.Next(allSilos.Count)], strategy, grainType)));
        }
Example #7
0
        public virtual Task <PlacementResult> OnAddActivation(
            PlacementStrategy strategy, PlacementTarget target, IPlacementContext context)
        {
            var grainType = context.GetGrainTypeName(target.GrainId);
            var allSilos  = context.GetCompatibleSiloList(target);

            return(Task.FromResult(
                       PlacementResult.SpecifyCreation(allSilos[random.Next(allSilos.Count)], strategy, grainType)));
        }
Example #8
0
        internal override Task <PlacementResult> OnSelectActivation(
            PlacementStrategy strategy, GrainId target, IPlacementContext context)
        {
            if (target.IsClient)
            {
                throw new InvalidOperationException("Cannot use StatelessWorkerStrategy to route messages to client grains.");
            }

            // Returns an existing activation of the grain or requests creation of a new one.
            // If there are available (not busy with a request) activations, it returns the first one
            // that exceeds the MinAvailable limit. E.g. if MinAvailable=1, it returns the second available.
            // If MinAvailable is less than 1, it returns the first available.
            // If the number of local activations reached or exceeded MaxLocal, it randomly returns one of them.
            // Otherwise, it requests creation of a new activation.
            List <ActivationData> local;

            if (!context.LocalLookup(target, out local) || local.Count == 0)
            {
                return(Task.FromResult((PlacementResult)null));
            }

            var placement = (StatelessWorkerPlacement)strategy;
            List <ActivationId> available = null;

            foreach (var activation in local)
            {
                ActivationData info;
                if (!context.TryGetActivationData(activation.ActivationId, out info) ||
                    info.State != ActivationState.Valid || !info.IsInactive)
                {
                    continue;
                }

                if (placement.MinAvailable < 1 || (available != null && available.Count >= placement.MinAvailable))
                {
                    return(Task.FromResult(PlacementResult.IdentifySelection(ActivationAddress.GetAddress(context.LocalSilo, target, activation.ActivationId))));
                }

                if (available == null)
                {
                    available = new List <ActivationId>();
                }
                available.Add(info.ActivationId);
            }

            if (local.Count >= placement.MaxLocal)
            {
                var id = local[local.Count == 1 ? 0 : random.Next(local.Count)].ActivationId;
                return(Task.FromResult(PlacementResult.IdentifySelection(ActivationAddress.GetAddress(context.LocalSilo, target, id))));
            }

            return(Task.FromResult((PlacementResult)null));
        }
        private Task <PlacementResult> MakePlacement(PlacementStrategy strategy, GrainId grain, IPlacementContext context, CachedLocalStat minLoadedSilo)
        {
            // Increment placement by number of silos instead of by one.
            // This is our trick to get more balanced placement, accounting to the probable
            // case when multiple silos place on the same silo at the same time, before stats are refreshed.
            minLoadedSilo.IncrementActivationCount(localCache.Count);

            return(Task.FromResult(PlacementResult.SpecifyCreation(
                                       minLoadedSilo.Address,
                                       strategy,
                                       context.GetGrainTypeName(grain))));
        }
Example #10
0
        public bool TrySelectActivationSynchronously(
            PlacementStrategy strategy, GrainId target, IPlacementRuntime context, out PlacementResult placementResult)
        {
            if (context.FastLookup(target, out var addresses))
            {
                placementResult = ChooseRandomActivation(addresses, context);
                return(true);
            }

            placementResult = null;
            return(false);
        }
Example #11
0
        public static List <StepTracingLog> Trace(Scheme sch, PlacementResult plc, out string err)
        {
            // обязательно создаём лог действий
            var log = new List <StepTracingLog>();

            // при возникновении критической ошибки её нужно занести в эту переменную и сделать return null
            err = "";

            // формируем список плат, в котором хранится список слоёв (для каждого проводника свой слой ДРП)
            var boards = new List <List <Matrix <Cell> > >();

            // считываем список плат, в каждой плате хранится список проводников (Wire) соединяют всего 2 контакта
            List <List <Wire> > boardsWiresPositions = plc.BoardsWiresPositions;


            // ниже я тупо добавляю в слой каждой платы её ДРП с размещёнными на ней контактами элементов и разъёма, никакой логики тут нет
            for (int numBoard = 0; numBoard < plc.BoardsMatrices.Count; numBoard++)
            {
                var layers = new List <Matrix <Cell> >();
                // в свойстве BoardsDRPs хранится матрица с расставленными контактами разъёма и элементов
                layers.Add(plc.BoardsDRPs[numBoard]);
                boards.Add(layers);
                log.Add(new StepTracingLog(boards, "Здесь могла быть ваша реклама..."));
            }


            // тестировка отображения веса
            log.Last().BoardsDRPs.Last().Last()[2, 2].Weight = 3;
            log.Last().BoardsDRPs.Last().Last()[3, 3].Weight = 3;
            log.Last().BoardsDRPs.Last().Last()[4, 4].Weight = 3;
            log.Last().BoardsDRPs.Last().Last()[4, 4].State  = CellState.ArrowRight;
            log.Last().BoardsDRPs.Last().Last()[3, 3].State  = CellState.ArrowUp;
            log.Last().BoardsDRPs.Last().Last()[2, 2].State  = CellState.ArrowDown;
            // тестировка отображения св..номера элемента
            log.Last().BoardsDRPs.Last().Last()[5, 5].State       = CellState.WireCross;
            log.Last().BoardsDRPs.Last().Last()[4, 5].State       = CellState.WireVertical;
            log.Last().BoardsDRPs.Last().Last()[6, 5].State       = CellState.WireVertical;
            log.Last().BoardsDRPs.Last().Last()[5, 4].State       = CellState.WireHorizontal;
            log.Last().BoardsDRPs.Last().Last()[5, 6].State       = CellState.WireHorizontal;
            log.Last().BoardsDRPs.Last().Last()[3, 5].State       = CellState.WireBottomRight;
            log.Last().BoardsDRPs.Last().Last()[7, 5].State       = CellState.WireTopLeft;
            log.Last().BoardsDRPs.Last().Last()[5, 3].State       = CellState.WireTopRight;
            log.Last().BoardsDRPs.Last().Last()[5, 7].State       = CellState.WireBottomLeft;
            log.Last().BoardsDRPs.Last().Last()[3, 6].State       = CellState.WireHorizontal;
            log.Last().BoardsDRPs.Last().Last()[7, 4].State       = CellState.WireHorizontal;
            log.Last().BoardsDRPs.Last().Last()[4, 3].State       = CellState.WireVertical;
            log.Last().BoardsDRPs.Last().Last()[6, 7].State       = CellState.WireVertical;
            log.Last().BoardsDRPs.Last().Last()[5, 5].Description = "D1";
            log.Last().BoardsDRPs.Last().Last()[5, 7].Description = "D3";
            log.Last().BoardsDRPs.Last().Last()[5, 7].Weight      = 3;
            return(log);
        }
        OnAddActivation(PlacementStrategy strategy, GrainId grain, IPlacementContext context)
        {
            // if local silo is not active or does not support this type of grain, revert to random placement
            if (context.LocalSiloStatus != SiloStatus.Active || !context.GetCompatibleSiloList(grain).Contains(context.LocalSilo))
            {
                return(base.OnAddActivation(strategy, grain, context));
            }

            var grainType = context.GetGrainTypeName(grain);

            return(Task.FromResult(
                       PlacementResult.SpecifyCreation(context.LocalSilo, strategy, grainType)));
        }
Example #13
0
 private void DrawBox(PlacementResult boxLocation, Color color)
 {
     if (boxLocation != null)
     {
         _lineBoxList.Add(
             new BoxDrawer.Box(
                 boxLocation.Position,
                 Quaternion.LookRotation(boxLocation.Normal, Vector3.up),
                 color,
                 boxLocation.Dimensions * 0.5f)
             );
     }
 }
Example #14
0
        OnAddActivation(PlacementStrategy strategy, GrainId grain, IPlacementContext context)
        {
            // if local silo is not active, revert to random placement
            if (context.LocalSiloStatus != SiloStatus.Active)
            {
                return(base.OnAddActivation(strategy, grain, context));
            }

            var grainType = context.GetGrainTypeName(grain);

            return(Task.FromResult(
                       PlacementResult.SpecifyCreation(context.LocalSilo, strategy, grainType)));
        }
Example #15
0
        private async Task <PlacementResult> AddActivation(
            PlacementTarget target,
            IPlacementRuntime context,
            PlacementStrategy strategy)
        {
            if (target.IsClient)
            {
                throw new InvalidOperationException("Client grains are not activated using the placement subsystem.");
            }

            var director = ResolveDirector(strategy);

            return(PlacementResult.SpecifyCreation(
                       await director.OnAddActivation(strategy, target, context),
                       strategy,
                       context.GetGrainTypeName(target.GrainIdentity.TypeCode)));
        }
Example #16
0
        private async ValueTask <PlacementResult> GetOrPlaceActivationAsync(
            PlacementTarget target,
            PlacementStrategy strategy,
            IPlacementRuntime placementRuntime,
            IActivationSelector selector,
            IPlacementDirector director)
        {
            var placementResult = await selector.OnSelectActivation(strategy, target.GrainIdentity, placementRuntime);

            if (placementResult is object)
            {
                return(placementResult);
            }

            var siloAddress = await director.OnAddActivation(strategy, target, placementRuntime);

            string grainTypeName;

            if (LegacyGrainId.TryConvertFromGrainId(target.GrainIdentity, out var legacyId))
            {
                grainTypeName = placementRuntime.GetGrainTypeName(legacyId.TypeCode);
            }
            else
            {
                grainTypeName = null;
            }

            ActivationId activationId;

            if (strategy.IsDeterministicActivationId)
            {
                // Use the grain id as the activation id.
                activationId = ActivationId.GetDeterministic(target.GrainIdentity);
            }
            else
            {
                activationId = ActivationId.NewId();
            }

            return(PlacementResult.SpecifyCreation(
                       siloAddress,
                       activationId,
                       strategy,
                       grainTypeName));
        }
Example #17
0
 public void PlacePiece(PlacementResult res)
 {
     if ((team.color == TeamColor.Red && position.y < board.goalAreaHeight) ||
         (team.color == TeamColor.Blue && position.y >= board.boardHeight - board.goalAreaHeight))
     {
         Cell cell = board.GetCell(position);
         if (res == PlacementResult.Correct)
         {
             cell.SetCellState(CellState.Goal);
         }
         else
         {
             cell.SetCellState(CellState.NoGoal);
         }
         piece       = false;
         pieceIsSham = false;
     }
 }
Example #18
0
        private PlacementResult SelectActivationCore(PlacementStrategy strategy, GrainId target, IPlacementRuntime context)
        {
            if (target.IsClient())
            {
                throw new InvalidOperationException("Cannot use StatelessWorkerStrategy to route messages to client grains.");
            }

            // If there are available (not busy with a request) activations, it returns the first one.
            // If all are busy and the number of local activations reached or exceeded MaxLocal, it randomly returns one of them.
            // Otherwise, it requests creation of a new activation.
            List <ActivationData> local;

            if (context.LocalSiloStatus.IsTerminating())
            {
                return(null);
            }

            if (!context.LocalLookup(target, out local) || local.Count == 0)
            {
                return(null);
            }

            var placement = (StatelessWorkerPlacement)strategy;

            foreach (var activation in local)
            {
                ActivationData info;
                if (!context.TryGetActivationData(activation.ActivationId, out info) ||
                    info.State != ActivationState.Valid || !info.IsInactive)
                {
                    continue;
                }

                return(PlacementResult.IdentifySelection(ActivationAddress.GetAddress(context.LocalSilo, target, activation.ActivationId)));
            }

            if (local.Count >= placement.MaxLocal)
            {
                var id = local[local.Count == 1 ? 0 : random.Next(local.Count)].ActivationId;
                return(PlacementResult.IdentifySelection(ActivationAddress.GetAddress(context.LocalSilo, target, id)));
            }

            return(null);
        }
Example #19
0
 /// <summary>
 /// Метод для записи результатов размещения в файла (сериализация)
 /// </summary>
 public static void WritePlacement(PlacementResult plc, out string errWrite)
 {
     errWrite = "";
     if (FileName != "")
     {
         try
         {
             using (StreamWriter file = File.CreateText(FileName + ".plc"))
             {
                 JsonSerializer serializer = new JsonSerializer();
                 serializer.Serialize(file, plc);
             }
         }
         catch (Exception exc)
         {
             errWrite = $"При записи в файл размещения произошла ошибка: {exc.Message}";
         }
     }
 }
Example #20
0
        /// <summary>
        /// Метод для трассировки
        /// </summary>
        /// <returns>Список логов шагов</returns>
        public static List <StepTracingLog> Trace(Scheme sch, PlacementResult plc, out string err)
        {
            // обязательно создаём лог действий
            var log = new List <StepTracingLog>();

            // при возникновении критической ошибки её нужно занести в эту переменную и сделать return null
            err = "";

            // формируем список плат, в котором хранится список слоёв (для каждого проводника свой слой ДРП)
            var boards = new List <List <Matrix <Cell> > >();

            // считываем список плат, в каждой плате хранится список проводников (Wire) соединяют всего 2 контакта
            List <List <Wire> > boardsWiresPositions = plc.BoardsWiresPositions;

            // тут выполняете действия по алгоритму используя список проводков и обязательно логируете действия
            // пример логирования в классе TestTracing


            return(log);
        }
        protected PlacementResult ChooseRandomActivation(List<ActivationAddress> places, IPlacementRuntime context)
        {
            if (places.Count <= 0)
            {
                // we return null to indicate that we were unable to select a target from places activations.
                return null;
            }
            if (places.Count == 1)
            {
                return PlacementResult.IdentifySelection(places[0]);
            }
            // places.Count >= 2
            // Choose randomly if there is one, else make a new activation of the target
            // pick local if available (consider making this a purely random assignment of grains).
            var here = context.LocalSilo;
            var local = places.Where(a => a.Silo.Equals(here)).ToList();
            if (local.Count > 0)
                return PlacementResult.IdentifySelection(local[random.Next(local.Count)]);

            return PlacementResult.IdentifySelection(places[random.Next(places.Count)]);
        }
        public bool TrySelectActivationSynchronously(
            ActivationAddress sendingAddress,
            PlacementTarget targetGrain,
            IPlacementRuntime context,
            PlacementStrategy strategy,
            out PlacementResult placementResult)
        {
            if (targetGrain.IsClient)
            {
                return(clientObserversPlacementDirector.TrySelectActivationSynchronously(
                           strategy,
                           (GrainId)targetGrain.GrainIdentity,
                           context,
                           out placementResult));
            }

            var actualStrategy = strategy ?? defaultPlacementStrategy;
            var director       = ResolveSelector(actualStrategy);

            return(director.TrySelectActivationSynchronously(strategy, (GrainId)targetGrain.GrainIdentity, context, out placementResult));
        }
Example #23
0
        /// <summary>
        /// Метод для чтения результатов размещения в файла (десериализация)
        /// </summary>
        public static PlacementResult ReadPlacement(out string msg)
        {
            msg = "";
            PlacementResult plc = null;

            if (IsFileExists(".plc", out msg))
            {
                try
                {
                    using (StreamReader file = File.OpenText(FileName + ".plc"))
                    {
                        JsonSerializer serializer = new JsonSerializer();
                        plc = (PlacementResult)serializer.Deserialize(file, typeof(PlacementResult));
                    }
                }
                catch (Exception exp)
                {
                    msg = $"Произошла ошибка при попытке чтения файла {FileName}.plc: {exp.Message}";
                }
            }
            return(plc);
        }
        /// <summary>
        /// Метод для трассировки
        /// </summary>
        /// <returns>Список логов шагов</returns>
        public static List <StepTracingLog> Trace(Scheme sch, PlacementResult plc, bool isOptimized, out string err)
        {
            // обязательно создаём лог действий
            var log = new List <StepTracingLog>();

            // при возникновении критической ошибки её нужно занести в эту переменную и сделать return null
            err = "";

            // формируем список плат, в котором хранится список слоёв (для каждого проводника свой слой ДРП)
            var boards = new List <List <Matrix <Cell> > >();

            // считываем список плат, в каждой плате хранится список проводников (Wire) соединяют всего 2 контакта
            List <List <Wire> > boardsWiresPositions = plc.BoardsWiresPositions;

            for (int boardNum = 0; boardNum < boardsWiresPositions.Count; boardNum++)
            {
                // получаем список проводов, которые необходимо развести на этой плате
                // элемент списка объект класса Wire, который хранит координаты точки А и Б на ДРП
                var boardWiresPositions = boardsWiresPositions[boardNum];

                // список ДРП текущей платы, в который будет заносится ДРП для каждого провода
                var boardDRPs = new List <Matrix <Cell> >();

                // добавляем этот список в список всех плат
                boards.Add(boardDRPs);

                // первым слоем будет являтся ДРП на котором просто отмечены места контактов платы
                boardDRPs.Add(plc.BoardsDRPs[boardNum]);

                // запускаем цикл по проводам
                foreach (var wire in boardWiresPositions)
                {
                    // ДРП для провода формируем на основе шаблона ДРП, на котором просто отмечены контакты. Оно уже имеет необходимые размеры.
                    var currentDRP = new Matrix <Cell>(plc.BoardsDRPs[boardNum].RowsCount, plc.BoardsDRPs[boardNum].ColsCount);

                    // добавляем это ДРП в список ДРП платы
                    boardDRPs.Add(currentDRP);

                    // заполняем ДРП пустыми ячейками
                    for (int i = 0; i < currentDRP.RowsCount; i++)
                    {
                        for (int j = 0; j < currentDRP.ColsCount; j++)
                        {
                            currentDRP[i, j] = new Cell();
                        }
                    }

                    // дрп, в котором будут объединены все слои с проводами (для определения гдле занята ячейка - где нет)
                    Matrix <Cell> fullDrp;

                    // получаем из провода стартовую и конечную позицию
                    var startPos = wire.A.PositionContact;
                    var endPos   = wire.B.PositionContact;

                    // список, в котором будут хранится приоритеты (смещение относительно текущей ячейки)
                    // если это стрелочка вверх, значит должна анализироваться верхняя ячейка
                    // смещение верхней ячейки относительно текущей: на строку выше, значит -1, а столбец тот же, значит 0
                    // если это стрелочка влево, значит относительно текущей ячейки это будет столбец левее, значит -1, а строка та же, значит 0
                    List <Position> prioritetsPos = new List <Position>();

                    // вычисляем разницу между значениями строк и столбцов точек А и Б
                    int rowsDiff = endPos.Row - startPos.Row;
                    int colsDiff = endPos.Column - startPos.Column;

                    // а это модули этих значений, тоже понадобятся
                    int rowsDiffModul = Math.Abs(rowsDiff);
                    int colsDiffModul = Math.Abs(colsDiff);

                    // определяем как раз таки позиции приоритетов, логику которых я чуть выше описывал
                    Position top    = new Position(-1, 0);
                    Position bottom = new Position(1, 0);
                    Position left   = new Position(0, -1);
                    Position right  = new Position(0, 1);

                    // далее идёт задание приоритетов на основе подсчитанных разниц позиций
                    // логическому объяснению не поддаётся, только по результату моделирования на бумаге
                    if (colsDiff > rowsDiff)
                    {
                        if (colsDiffModul > rowsDiffModul)
                        {
                            if (rowsDiff < 0)
                            {
                                prioritetsPos = getPrioritets(0, false); // первый приоритет - стрелочка влево, остальные против часовой стрелки назначаем
                            }
                            else
                            {
                                prioritetsPos = getPrioritets(0, true); // первый приоритет - стрелочка влево, остальные по часовой стрелке назначаем
                            }
                        }
                        else
                        {
                            if (colsDiff > 0)
                            {
                                prioritetsPos = getPrioritets(90, true); // первый приоритет - стрелочка вниз, остальные по часовой стрелке назначаем
                            }
                            else
                            {
                                prioritetsPos = getPrioritets(90, false); // первый приоритет - стрелочка вниз, остальные против часовой стрелки назначаем
                            }
                        }
                    }
                    else
                    {
                        if (colsDiffModul > rowsDiffModul)
                        {
                            if (rowsDiff > 0)
                            {
                                prioritetsPos = getPrioritets(180, false); // первый приоритет - стрелочка вправо, остальные против часовой стрелки назначаем
                            }
                            else
                            {
                                prioritetsPos = getPrioritets(180, true); // первый приоритет - стрелочка вправо, остальные по часовой стрелке назначаем
                            }
                        }
                        else
                        {
                            if (colsDiff < 0)
                            {
                                prioritetsPos = getPrioritets(270, true); // первый приоритет - стрелочка вверх, остальные по часовой стрелке назначаем
                            }
                            else
                            {
                                prioritetsPos = getPrioritets(270, false); // первый приоритет - стрелочка вверх, остальные против часовой стрелки назначаем
                            }
                        }
                    }

                    // помечаем буквами стартовую и конечную позицию на текущем слое провода
                    currentDRP[startPos.Row, startPos.Column].State  = CellState.PointA;
                    currentDRP[startPos.Row, startPos.Column].Weight = 0;
                    currentDRP[endPos.Row, endPos.Column].State      = CellState.PointB;

                    // сообщаем о начале трассировки нового провода и печатаем сформированные приоритеты
                    string stepMsg = $"Начинаем трассировку {boardDRPs.Count - 1}-го проводника в {boardNum + 1} узле\n";
                    stepMsg += "Сформированы следующие приоритеты: ";
                    int iterator = 1;
                    foreach (var prioritet in prioritetsPos)
                    {
                        stepMsg += $"{iterator}: ";
                        switch (getArrowByPrioritet(prioritet.Row, prioritet.Column))
                        {
                        case CellState.ArrowUp:
                            stepMsg += "(\u2191) ";
                            break;

                        case CellState.ArrowDown:
                            stepMsg += "(\u2193) ";
                            break;

                        case CellState.ArrowLeft:
                            stepMsg += "(\u2190) ";
                            break;

                        case CellState.ArrowRight:
                            stepMsg += "(\u2192) ";
                            break;
                        }
                        iterator++;
                    }
                    log.Add(new StepTracingLog(boards, stepMsg));

                    // список позиций соседних ячеек
                    var neighbors = new List <Position>();

                    // объединяем все слои с проводами платы, чтобы на основе этого ДРП получить список именно незанятых соседей
                    fullDrp = ApplicationData.MergeLayersDRPs(boardDRPs);

                    // получаем список незанятых соседей у стартовой точки
                    neighbors = getNeighbors(fullDrp, startPos);

                    // запускаем цикл, пока не закончатся свободные соседи или в списке соседей будет точка А
                    do
                    {
                        // проходим по всем соседним ячейкам чтобы поставить в них стрелочку в какую-то сторону
                        foreach (var neighbor in neighbors)
                        {
                            int minWeight = int.MaxValue;

                            // для этого проходим по всем приоритетам
                            foreach (var prioritet in prioritetsPos)
                            {
                                // определяем позицию, которую нужно проверить на основе текущего приоритета
                                // если первый приоритет стрелочка вверх - значит мы сначала должна проверить верхнюю ячейку на наличие стрелочки
                                // если она там обнаружится, то поставить в текущей ячейке стрелочку вверх, если нет, то перейти к следующему приоритету, проверить наличие стрелочки в ячейке по этому приоритету и т.д.
                                Position checkingPos = new Position(neighbor.Row + prioritet.Row, neighbor.Column + prioritet.Column);

                                // определяем находится ли проверяемая позиция ваще в дрп, вдруг мы вылезли за какой-то край
                                if (checkingPos.Row >= 0 && checkingPos.Row < currentDRP.RowsCount)
                                {
                                    if (checkingPos.Column >= 0 && checkingPos.Column < currentDRP.ColsCount)
                                    {
                                        // если в проверяемой позиции есть стрелочка или точка А (к нему тоже нужно провести стрелочки на первом шаге)
                                        if (fullDrp[checkingPos.Row, checkingPos.Column].isArrow || fullDrp[checkingPos.Row, checkingPos.Column].State == CellState.PointA)
                                        {
                                            // устанавливаем необходимую стрелочку по значениям смещения этой стрелочки
                                            int currentWeight = currentDRP[neighbor.Row + prioritet.Row, neighbor.Column + prioritet.Column].Weight + getCountWiresNear(fullDrp, neighbor);
                                            if (currentWeight < minWeight)
                                            {
                                                minWeight = currentWeight;
                                                currentDRP[neighbor.Row, neighbor.Column].State  = getArrowByPrioritet(prioritet.Row, prioritet.Column);
                                                currentDRP[neighbor.Row, neighbor.Column].Weight = currentWeight;
                                                fullDrp[neighbor.Row, neighbor.Column].State     = getArrowByPrioritet(prioritet.Row, prioritet.Column);
                                                fullDrp[neighbor.Row, neighbor.Column].Weight    = currentWeight;
                                            }
                                        }
                                    }
                                }
                            }
                        }

                        if (!isOptimized)
                        {
                            log.Add(new StepTracingLog(boards, $"Распроcтраняем волну для {boardDRPs.Count - 1}-го проводника в {boardNum + 1} узле"));
                        }

                        neighbors = getNeighbors(fullDrp, neighbors);
                    } while (neighbors.Count > 0 && !neighbors.Any(x => x.Column == endPos.Column && x.Row == endPos.Row));

                    // если незанятых соседей не оказалось, значит трассировка невозможна
                    if (neighbors.Count == 0)
                    {
                        // очищаем текущее дрп
                        for (int i = 0; i < currentDRP.RowsCount; i++)
                        {
                            for (int j = 0; j < currentDRP.ColsCount; j++)
                            {
                                currentDRP[i, j] = new Cell();
                            }
                        }
                        // оставляем только 2 контакта, которые должны быть соеденены
                        currentDRP[startPos.Row, startPos.Column].State = CellState.Contact;
                        currentDRP[endPos.Row, endPos.Column].State     = CellState.Contact;
                        log.Add(new StepTracingLog(boards, $"Невозможно выполнить трассировку {boardDRPs.Count - 1}-го проводника в {boardNum + 1} узле"));
                        continue;
                    }

                    if (isOptimized)
                    {
                        log.Add(new StepTracingLog(boards, $"Волна {boardDRPs.Count - 1}-го проводника достигла точки Б в {boardNum + 1} узле"));
                    }


                    // теперь начинаем с точки Б
                    // находим соседние ячейки точки Б в которых есть стрелочка и берём первую попавшуюся (это не важно)
                    var currentPos = getNeighborWithMinWeight(currentDRP, endPos);

                    // запускаем цикл, пока мы по этим стрелочкам не дойдём то точки А
                    do
                    {
                        // запомним какая стрелочка была в текущей ячейке, т.к. сейчас перезапишем состояние ячейки
                        var bufCellState = currentDRP[currentPos.Row, currentPos.Column].State;

                        // указываем что в этой позиции будет провод, а какой именно - вертикальный, горизонтальный это определим потом
                        currentDRP[currentPos.Row, currentPos.Column].State = CellState.Wire;

                        // теперь на основе стрелочки определяем в какую ячейку мы смещаемся. если это стрелочка влево - то столбец будет меньше на 1
                        // если вправо - то столбец на 1 больше, если стрелочка вверх, то на 1 строку выше
                        currentPos = getNextPosByCurrentArrow(currentPos, bufCellState);
                    } while (currentDRP[currentPos.Row, currentPos.Column].State != CellState.PointA);

                    // очищаем всё дрп от стрелочек и веса
                    for (int i = 0; i < currentDRP.RowsCount; i++)
                    {
                        for (int j = 0; j < currentDRP.ColsCount; j++)
                        {
                            currentDRP[i, j].Weight = -1;
                            if (currentDRP[i, j].isArrow)
                            {
                                currentDRP[i, j].State = CellState.Empty;
                            }
                        }
                    }

                    log.Add(new StepTracingLog(boards, $"Волна достигла точки Б. Определяем точки, где будет проходить проводник №{boardDRPs.Count - 1} в {boardNum + 1} узле"));

                    // начинаем долгую и мучительную спец операцию по определению какой формы проводник должен стоять в ячейке
                    // запускаем цикл по всем ячейкам дрп
                    for (int i = 0; i < currentDRP.RowsCount; i++)
                    {
                        for (int j = 0; j < currentDRP.ColsCount; j++)
                        {
                            // объявляем соседей, от них нам нужно будет только состояние
                            Cell leftCell   = new Cell();
                            Cell rightCell  = new Cell();
                            Cell topCell    = new Cell();
                            Cell bottomCell = new Cell();

                            // блок, который присвоит пустое состояние ячейке, если она находится вне дрп, если находится в дрп, то присвоит нужную позицию
                            if (j > 0)
                            {
                                leftCell = currentDRP[i, j - 1];
                            }
                            else
                            {
                                leftCell.State = CellState.Empty;
                            }

                            if (j < currentDRP.ColsCount - 1)
                            {
                                rightCell = currentDRP[i, j + 1];
                            }
                            else
                            {
                                rightCell.State = CellState.Empty;
                            }

                            if (i > 0)
                            {
                                topCell = currentDRP[i - 1, j];
                            }
                            else
                            {
                                topCell.State = CellState.Empty;
                            }

                            if (i < currentDRP.RowsCount - 1)
                            {
                                bottomCell = currentDRP[i + 1, j];
                            }
                            else
                            {
                                bottomCell.State = CellState.Empty;
                            }
                            // конец блока

                            var currentCell = currentDRP[i, j];

                            // если текущая ячейка должна быть каким-то кабелем
                            // определяем значения ячеек вокруг и на основе этих данных узнаём какой имеено должен быть кабель
                            // идущим вертикально или слева вверх или горизонтальным и т.д.
                            if (currentCell.State == CellState.Wire)
                            {
                                // если есть кабель сверху и кабель в ячейке снизу, то в текущей ячейке должен стоять вертикальный проводник
                                if (topCell.isConnectible && bottomCell.isConnectible)
                                {
                                    currentDRP[i, j].State = CellState.WireVertical;
                                } // и т.д. для остальных видов проводника
                                else if (leftCell.isConnectible && rightCell.isConnectible)
                                {
                                    currentDRP[i, j].State = CellState.WireHorizontal;
                                }
                                else if (topCell.isConnectible && leftCell.isConnectible)
                                {
                                    currentDRP[i, j].State = CellState.WireTopLeft;
                                }
                                else if (topCell.isConnectible && rightCell.isConnectible)
                                {
                                    currentDRP[i, j].State = CellState.WireTopRight;
                                }
                                else if (bottomCell.isConnectible && leftCell.isConnectible)
                                {
                                    currentDRP[i, j].State = CellState.WireBottomLeft;
                                }
                                else if (bottomCell.isConnectible && rightCell.isConnectible)
                                {
                                    currentDRP[i, j].State = CellState.WireBottomRight;
                                }
                            }
                        }
                    }

                    // заменяем буквы просто контактами
                    currentDRP[startPos.Row, startPos.Column].State = CellState.Contact;
                    currentDRP[endPos.Row, endPos.Column].State     = CellState.Contact;
                    log.Add(new StepTracingLog(boards, $"Построили на базе точек проводник №{boardDRPs.Count - 1} в {boardNum + 1} узле"));
                }
            }



            return(log);
        }
        private List <StepPlacementLog> DoPlacement()
        {
            var steps = new List <StepPlacementLog>();

            string err_msg = "";

            Composition.CompositionResult cmp = null;
            Scheme       sch   = null;
            Matrix <int> matrR = null;

            if (ComboBox_Method.SelectedIndex != 6)
            {
                cmp = ApplicationData.ReadComposition(out err_msg);

                if (err_msg != "")
                {
                    MessageBox.Show(err_msg, "Revolution CAD", MessageBoxButton.OK, MessageBoxImage.Error);
                    return(steps);
                }

                sch = ApplicationData.ReadScheme(out err_msg);

                if (err_msg != "")
                {
                    MessageBox.Show(err_msg, "Revolution CAD", MessageBoxButton.OK, MessageBoxImage.Error);
                    return(steps);
                }

                matrR = cmp.MatrixR_AfterComposition;
            }



            switch (ComboBox_Method.SelectedIndex)
            {
            case 0:
                steps = PosledMaxLastStepPlaced.Place(cmp, matrR, out err_msg);
                break;

            case 1:
                steps = PosledMaxLastAllStepPlaced.Place(cmp, matrR, out err_msg);
                break;

            case 2:
                steps = PosledMaxPlacedMinUnplaced.Place(cmp, matrR, out err_msg);
                break;

            case 3:
                steps = IterFull.Place(matrR, out err_msg);
                break;

            case 4:
                steps = IterPair.Place(matrR, out err_msg);
                break;

            case 5:
                steps = IterShaffer.Place(matrR, out err_msg);
                break;

            case 6:
                steps = BranchesAndBorders.Place();
                break;

            case 7:
                steps = TestPlacement.Place(cmp, matrR, out err_msg);
                break;
            }

            // если не было ошибки - сериализуем результат
            if (ComboBox_Method.SelectedIndex != 6)
            {
                if (err_msg == "")
                {
                    if (steps.Count != 0)
                    {
                        var result = new PlacementResult();
                        result.BoardsMatrices = steps.Last().BoardsList;

                        var dips = sch.DIPNumbers;

                        result.CreateBoardsDRPs(cmp, dips, out err_msg);
                        result.CreateWires(cmp.BoardsWires);

                        if (err_msg != "")
                        {
                            MessageBox.Show(err_msg, "Revolution CAD", MessageBoxButton.OK, MessageBoxImage.Error);
                            return(null);
                        }

                        ApplicationData.WritePlacement(result, out err_msg);

                        if (err_msg != "")
                        {
                            MessageBox.Show(err_msg, "Revolution CAD", MessageBoxButton.OK, MessageBoxImage.Error);
                            return(null);
                        }

                        string msg;
                        if (ApplicationData.IsFileExists(".trs", out msg))
                        {
                            File.Delete($"{ApplicationData.FileName}.trs");
                        }

                        if (ApplicationData.IsFileExists(".lay", out msg))
                        {
                            File.Delete($"{ApplicationData.FileName}.lay");
                        }

                        mw.TraceControl.Update();
                        mw.LayerControl.Update();
                    }
                }
                else
                {
                    MessageBox.Show(err_msg, "Revolution CAD", MessageBoxButton.OK, MessageBoxImage.Error);
                }
            }
            return(steps);
        }
Example #26
0
 public bool TrySelectActivationSynchronously(
     PlacementStrategy strategy, GrainId target, IPlacementRuntime context, out PlacementResult placementResult)
 {
     placementResult = SelectActivationCore(strategy, target, context);
     return(placementResult != null);
 }
Example #27
0
        /// <summary>
        /// Метод для трассировки
        /// </summary>
        /// <returns>Список логов шагов</returns>
        public static List <StepTracingLog> Trace(Scheme sch, PlacementResult plc, bool isOptimized, out string err)
        {
            // обязательно создаём лог действий
            var log = new List <StepTracingLog>();

            // при возникновении критической ошибки её нужно занести в эту переменную и сделать return null
            err = "";

            // формируем список плат, в котором хранится список слоёв (для каждого проводника свой слой ДРП)
            var boards = new List <List <Matrix <Cell> > >();

            // считываем список плат, в каждой плате хранится список проводников (Wire) соединяют всего 2 контакта
            List <List <Wire> > boardsWiresPositions = plc.BoardsWiresPositions;

            for (int boardNum = 0; boardNum < boardsWiresPositions.Count; boardNum++)
            {
                // получаем список проводов, которые необходимо развести на этой плате
                // элемент списка объект класса Wire, который хранит координаты точки А и Б на ДРП
                var boardWiresPositions = boardsWiresPositions[boardNum];

                // список ДРП текущей платы, в который будет заносится ДРП для каждого провода
                var boardDRPs = new List <Matrix <Cell> >();

                // добавляем этот список в список всех плат
                boards.Add(boardDRPs);

                // первым слоем будет являтся ДРП на котором просто отмечены места контактов платы
                boardDRPs.Add(plc.BoardsDRPs[boardNum]);

                // запускаем цикл по проводам
                foreach (var wire in boardWiresPositions)
                {
                    // ДРП для провода формируем на основе шаблона ДРП, на котором просто отмечены контакты. Оно уже имеет необходимые размеры.
                    var currentDRP = new Matrix <Cell>(plc.BoardsDRPs[boardNum].RowsCount, plc.BoardsDRPs[boardNum].ColsCount);

                    // добавляем это ДРП в список ДРП платы
                    boardDRPs.Add(currentDRP);

                    // заполняем ДРП пустыми ячейками
                    for (int i = 0; i < currentDRP.RowsCount; i++)
                    {
                        for (int j = 0; j < currentDRP.ColsCount; j++)
                        {
                            currentDRP[i, j] = new Cell();
                        }
                    }

                    // дрп, в котором будут объединены все слои с проводами (для определения гдле занята ячейка - где нет)
                    Matrix <Cell> fullDrp;

                    // получаем из провода стартовую и конечную позицию
                    var startPos = wire.A.PositionContact;
                    var endPos   = wire.B.PositionContact;

                    List <Beam> prioritetsPosBeamsA = new List <Beam>();
                    List <Beam> prioritetsPosBeamsB = new List <Beam>();

                    Position top    = new Position(-1, 0);
                    Position bottom = new Position(1, 0);
                    Position left   = new Position(0, -1);
                    Position right  = new Position(0, 1);

                    if (startPos.Row < endPos.Row)
                    {
                        prioritetsPosBeamsA.Add(new Beam(left, top));
                        prioritetsPosBeamsA.Add(new Beam(right, top));
                        prioritetsPosBeamsB.Add(new Beam(right, bottom));
                        prioritetsPosBeamsB.Add(new Beam(left, bottom));
                    }
                    else
                    {
                        prioritetsPosBeamsA.Add(new Beam(left, bottom));
                        prioritetsPosBeamsA.Add(new Beam(right, bottom));
                        prioritetsPosBeamsB.Add(new Beam(right, top));
                        prioritetsPosBeamsB.Add(new Beam(left, top));
                    }

                    if (startPos.Column < endPos.Column)
                    {
                        prioritetsPosBeamsA.Add(new Beam(top, left));
                        prioritetsPosBeamsA.Add(new Beam(bottom, left));
                        prioritetsPosBeamsB.Add(new Beam(top, right));
                        prioritetsPosBeamsB.Add(new Beam(bottom, right));
                    }
                    else
                    {
                        prioritetsPosBeamsA.Add(new Beam(top, right));
                        prioritetsPosBeamsA.Add(new Beam(bottom, right));
                        prioritetsPosBeamsB.Add(new Beam(top, left));
                        prioritetsPosBeamsB.Add(new Beam(bottom, left));
                    }



                    // помечаем буквами стартовую и конечную позицию на текущем слое провода
                    currentDRP[startPos.Row, startPos.Column].State = CellState.PointA;
                    currentDRP[endPos.Row, endPos.Column].State     = CellState.PointB;

                    // сообщаем о начале трассировки нового провода и печатаем сформированные приоритеты
                    string stepMsg = $"Начинаем трассировку {boardDRPs.Count - 1}-го проводника в {boardNum + 1} узле\n";
                    stepMsg += "Сформированы следующие приоритеты для лучей:\n";
                    int iterator = 1;
                    foreach (var prioritet in prioritetsPosBeamsA)
                    {
                        stepMsg += $"A{iterator}({getUnicodeArrowByPrioritetPos(prioritet.FirstPrioritetPos)},{getUnicodeArrowByPrioritetPos(prioritet.SecondPrioritetPos)}) ";
                        iterator++;
                    }
                    stepMsg += "\n";
                    iterator = 1;
                    foreach (var prioritet in prioritetsPosBeamsB)
                    {
                        stepMsg += $"B{iterator}({getUnicodeArrowByPrioritetPos(prioritet.FirstPrioritetPos)},{getUnicodeArrowByPrioritetPos(prioritet.SecondPrioritetPos)}) ";
                        iterator++;
                    }
                    log.Add(new StepTracingLog(boards, stepMsg));

                    // объединяем все слои с проводами платы, чтобы на основе этого ДРП получить список именно незанятых соседей
                    fullDrp = ApplicationData.MergeLayersDRPs(boardDRPs);

                    var beamsACurrentPos = new List <Position>();
                    var beamsBCurrentPos = new List <Position>();

                    for (int beamNum = 0; beamNum < prioritetsPosBeamsA.Count; beamNum++)
                    {
                        var posPrioritet = prioritetsPosBeamsA[beamNum].FirstPrioritetPos;
                        var pos          = new Position(startPos.Row - posPrioritet.Row, startPos.Column - posPrioritet.Column);
                        if (pos.isInDRP(fullDrp))
                        {
                            if (fullDrp[pos.Row, pos.Column].isBusyForBeam == false)
                            {
                                beamsACurrentPos.Add(pos);
                                currentDRP[pos.Row, pos.Column].State  = getArrowByPrioritet(posPrioritet.Row, posPrioritet.Column);
                                currentDRP[pos.Row, pos.Column].Weight = 1;
                                fullDrp[pos.Row, pos.Column].State     = getArrowByPrioritet(posPrioritet.Row, posPrioritet.Column);
                                fullDrp[pos.Row, pos.Column].Weight    = 1;
                                continue;
                            }
                        }
                        prioritetsPosBeamsA.RemoveAt(beamNum);
                        beamNum--;
                    }

                    for (int beamNum = 0; beamNum < prioritetsPosBeamsB.Count; beamNum++)
                    {
                        var posPrioritet = prioritetsPosBeamsB[beamNum].FirstPrioritetPos;
                        var pos          = new Position(endPos.Row - posPrioritet.Row, endPos.Column - posPrioritet.Column);
                        if (pos.isInDRP(fullDrp))
                        {
                            if (fullDrp[pos.Row, pos.Column].isBusyForBeam == false)
                            {
                                beamsBCurrentPos.Add(pos);
                                currentDRP[pos.Row, pos.Column].State  = getArrowByPrioritet(posPrioritet.Row, posPrioritet.Column);
                                currentDRP[pos.Row, pos.Column].Weight = 2;
                                fullDrp[pos.Row, pos.Column].State     = getArrowByPrioritet(posPrioritet.Row, posPrioritet.Column);
                                fullDrp[pos.Row, pos.Column].Weight    = 2;
                                continue;
                            }
                        }
                        prioritetsPosBeamsB.RemoveAt(beamNum);
                        beamNum--;
                    }
                    if (!isOptimized)
                    {
                        log.Add(new StepTracingLog(boards, $"Проведены лучи на 1 шаг {boardDRPs.Count - 1}-го проводника в {boardNum + 1} узле. Точек пересечения не найдено. Продолжаем."));
                    }

                    Position collisionPosBeamsA = null;
                    Position collisionPosBeamsB = null;
                    bool     isChanged          = false;

                    do
                    {
                        isChanged = false;

                        for (int beamNum = 0; beamNum < beamsACurrentPos.Count; beamNum++)
                        {
                            var currPos    = beamsACurrentPos[beamNum];
                            var prioritets = new List <Position>();
                            prioritets.Add(prioritetsPosBeamsA[beamNum].FirstPrioritetPos);
                            prioritets.Add(prioritetsPosBeamsA[beamNum].SecondPrioritetPos);
                            foreach (var prioritet in prioritets)
                            {
                                var checkingPos = new Position(currPos.Row - prioritet.Row, currPos.Column - prioritet.Column);
                                if (checkingPos.isInDRP(fullDrp))
                                {
                                    if (fullDrp[checkingPos.Row, checkingPos.Column].isBusyForBeam == false)
                                    {
                                        currentDRP[checkingPos.Row, checkingPos.Column].State  = getArrowByPrioritet(prioritet.Row, prioritet.Column);
                                        currentDRP[checkingPos.Row, checkingPos.Column].Weight = 1;
                                        fullDrp[checkingPos.Row, checkingPos.Column].State     = getArrowByPrioritet(prioritet.Row, prioritet.Column);
                                        fullDrp[checkingPos.Row, checkingPos.Column].Weight    = 1;
                                        isChanged = true;
                                        beamsACurrentPos[beamNum] = checkingPos;
                                        break;
                                    }
                                    else if (fullDrp[checkingPos.Row, checkingPos.Column].isArrow && fullDrp[checkingPos.Row, checkingPos.Column].Weight == 2)
                                    {
                                        isChanged          = true;
                                        collisionPosBeamsA = currPos;
                                        collisionPosBeamsB = checkingPos;
                                        beamNum            = 228;
                                        break;
                                    }
                                }
                            }
                        }

                        if (collisionPosBeamsA != null)
                        {
                            break;
                        }


                        for (int beamNum = 0; beamNum < beamsBCurrentPos.Count; beamNum++)
                        {
                            var currPos    = beamsBCurrentPos[beamNum];
                            var prioritets = new List <Position>();
                            prioritets.Add(prioritetsPosBeamsB[beamNum].FirstPrioritetPos);
                            prioritets.Add(prioritetsPosBeamsB[beamNum].SecondPrioritetPos);
                            foreach (var prioritet in prioritets)
                            {
                                var checkingPos = new Position(currPos.Row - prioritet.Row, currPos.Column - prioritet.Column);
                                if (checkingPos.isInDRP(fullDrp))
                                {
                                    if (fullDrp[checkingPos.Row, checkingPos.Column].isBusyForBeam == false)
                                    {
                                        currentDRP[checkingPos.Row, checkingPos.Column].State  = getArrowByPrioritet(prioritet.Row, prioritet.Column);
                                        currentDRP[checkingPos.Row, checkingPos.Column].Weight = 2;
                                        fullDrp[checkingPos.Row, checkingPos.Column].State     = getArrowByPrioritet(prioritet.Row, prioritet.Column);
                                        fullDrp[checkingPos.Row, checkingPos.Column].Weight    = 2;
                                        isChanged = true;
                                        beamsBCurrentPos[beamNum] = checkingPos;
                                        break;
                                    }
                                    else if (fullDrp[checkingPos.Row, checkingPos.Column].isArrow && fullDrp[checkingPos.Row, checkingPos.Column].Weight == 1)
                                    {
                                        isChanged          = true;
                                        collisionPosBeamsB = currPos;
                                        collisionPosBeamsA = checkingPos;
                                        beamNum            = 228;
                                        break;
                                    }
                                }
                            }
                        }
                        if (!isOptimized)
                        {
                            log.Add(new StepTracingLog(boards, $"Проведены лучи на 1 шаг {boardDRPs.Count - 1}-го проводника в {boardNum + 1} узле. Точек пересечения не найдено. Продолжаем."));
                        }
                    } while (collisionPosBeamsA == null && isChanged == true);

                    if (isChanged == false)
                    {
                        for (int i = 0; i < currentDRP.RowsCount; i++)
                        {
                            for (int j = 0; j < currentDRP.ColsCount; j++)
                            {
                                currentDRP[i, j] = new Cell();
                            }
                        }
                        // оставляем только 2 контакта, которые должны быть соеденены
                        currentDRP[startPos.Row, startPos.Column].State = CellState.Contact;
                        currentDRP[endPos.Row, endPos.Column].State     = CellState.Contact;
                        log.Add(new StepTracingLog(boards, $"Невозможно выполнить трассировку {boardDRPs.Count - 1}-го проводника в {boardNum + 1} узле. Все лучи упёрлись в препятствие и не пересеклись."));
                        continue;
                    }
                    else
                    {
                        if (isOptimized)
                        {
                            log.Add(new StepTracingLog(boards, $"Лучи пересеклись при трассировке {boardDRPs.Count - 1}-го проводника в {boardNum + 1} узле"));
                        }
                    }

                    var currentPos = collisionPosBeamsA;

                    do
                    {
                        var bufCellState = currentDRP[currentPos.Row, currentPos.Column].State;

                        currentDRP[currentPos.Row, currentPos.Column].State  = CellState.Wire;
                        currentDRP[currentPos.Row, currentPos.Column].Weight = -1;

                        currentPos = getNextPosByCurrentArrow(currentPos, bufCellState);
                    } while (currentDRP[currentPos.Row, currentPos.Column].State != CellState.PointA);


                    currentPos = collisionPosBeamsB;

                    do
                    {
                        var bufCellState = currentDRP[currentPos.Row, currentPos.Column].State;

                        currentDRP[currentPos.Row, currentPos.Column].State  = CellState.Wire;
                        currentDRP[currentPos.Row, currentPos.Column].Weight = -1;

                        currentPos = getNextPosByCurrentArrow(currentPos, bufCellState);
                    } while (currentDRP[currentPos.Row, currentPos.Column].State != CellState.PointB);


                    // очищаем всё дрп от стрелочек
                    for (int i = 0; i < currentDRP.RowsCount; i++)
                    {
                        for (int j = 0; j < currentDRP.ColsCount; j++)
                        {
                            if (currentDRP[i, j].isArrow)
                            {
                                currentDRP[i, j].State  = CellState.Empty;
                                currentDRP[i, j].Weight = -1;
                            }
                        }
                    }

                    log.Add(new StepTracingLog(boards, $"Определяем точки, где будет проходить проводник №{boardDRPs.Count - 1} в {boardNum + 1} узле"));

                    for (int i = 0; i < currentDRP.RowsCount; i++)
                    {
                        for (int j = 0; j < currentDRP.ColsCount; j++)
                        {
                            // объявляем соседей, от них нам нужно будет только состояние
                            Cell leftCell   = new Cell();
                            Cell rightCell  = new Cell();
                            Cell topCell    = new Cell();
                            Cell bottomCell = new Cell();

                            // блок, который присвоит пустое состояние ячейке, если она находится вне дрп, если находится в дрп, то присвоит нужную позицию
                            if (j > 0)
                            {
                                leftCell = currentDRP[i, j - 1];
                            }
                            else
                            {
                                leftCell.State = CellState.Empty;
                            }

                            if (j < currentDRP.ColsCount - 1)
                            {
                                rightCell = currentDRP[i, j + 1];
                            }
                            else
                            {
                                rightCell.State = CellState.Empty;
                            }

                            if (i > 0)
                            {
                                topCell = currentDRP[i - 1, j];
                            }
                            else
                            {
                                topCell.State = CellState.Empty;
                            }

                            if (i < currentDRP.RowsCount - 1)
                            {
                                bottomCell = currentDRP[i + 1, j];
                            }
                            else
                            {
                                bottomCell.State = CellState.Empty;
                            }
                            // конец блока

                            var currentCell = currentDRP[i, j];

                            // если текущая ячейка должна быть каким-то кабелем
                            // определяем значения ячеек вокруг и на основе этих данных узнаём какой имеено должен быть кабель
                            // идущим вертикально или слева вверх или горизонтальным и т.д.
                            if (currentCell.State == CellState.Wire)
                            {
                                // если есть кабель сверху и кабель в ячейке снизу, то в текущей ячейке должен стоять вертикальный проводник
                                if (topCell.isConnectible && bottomCell.isConnectible)
                                {
                                    currentDRP[i, j].State = CellState.WireVertical;
                                } // и т.д. для остальных видов проводника
                                else if (leftCell.isConnectible && rightCell.isConnectible)
                                {
                                    currentDRP[i, j].State = CellState.WireHorizontal;
                                }
                                else if (topCell.isConnectible && leftCell.isConnectible)
                                {
                                    currentDRP[i, j].State = CellState.WireTopLeft;
                                }
                                else if (topCell.isConnectible && rightCell.isConnectible)
                                {
                                    currentDRP[i, j].State = CellState.WireTopRight;
                                }
                                else if (bottomCell.isConnectible && leftCell.isConnectible)
                                {
                                    currentDRP[i, j].State = CellState.WireBottomLeft;
                                }
                                else if (bottomCell.isConnectible && rightCell.isConnectible)
                                {
                                    currentDRP[i, j].State = CellState.WireBottomRight;
                                }
                            }
                        }
                    }

                    // заменяем буквы просто контактами
                    currentDRP[startPos.Row, startPos.Column].State = CellState.Contact;
                    currentDRP[endPos.Row, endPos.Column].State     = CellState.Contact;
                    log.Add(new StepTracingLog(boards, $"Построили на базе точек проводник №{boardDRPs.Count - 1} в {boardNum + 1} узле"));
                }
            }

            return(log);
        }
Example #28
0
        /// <summary>
        /// Метод для трассировки
        /// </summary>
        /// <returns>Список логов шагов</returns>
        public static List <StepTracingLog> Trace(Scheme sch, PlacementResult plc, bool isOptimized, out string err)
        {
            // обязательно создаём лог действий
            var log = new List <StepTracingLog>();

            // при возникновении критической ошибки её нужно занести в эту переменную и сделать return null
            err = "";

            // формируем список плат, в котором хранится список слоёв (для каждого проводника свой слой ДРП)
            var boards = new List <List <Matrix <Cell> > >();

            // считываем список плат, в каждой плате хранится список проводников (Wire) соединяют всего 2 контакта
            List <List <Wire> > boardsWiresPositions = plc.BoardsWiresPositions;

            // запускаем цикл по платам
            for (int boardNum = 0; boardNum < boardsWiresPositions.Count; boardNum++)
            {
                // получаем список проводов, которые необходимо развести на этой плате
                // элемент списка объект класса Wire, который хранит координаты точки А и Б на ДРП
                var boardWiresPositions = boardsWiresPositions[boardNum];

                // список ДРП текущей платы, в который будет заносится ДРП для каждого провода
                var boardDRPs = new List <Matrix <Cell> >();

                // добавляем этот список в список всех плат
                boards.Add(boardDRPs);

                // первым слоем будет являтся ДРП на котором просто отмечены места контактов платы
                boardDRPs.Add(plc.BoardsDRPs[boardNum]);

                // запускаем цикл по проводам
                foreach (var wire in boardWiresPositions)
                {
                    // ДРП для провода формируем на основе шаблона ДРП, на котором просто отмечены контакты. Оно уже имеет необходимые размеры.
                    var currentDRP = new Matrix <Cell>(plc.BoardsDRPs[boardNum].RowsCount, plc.BoardsDRPs[boardNum].ColsCount);

                    // добавляем это ДРП в список ДРП платы
                    boardDRPs.Add(currentDRP);

                    // заполняем ДРП пустыми ячейками
                    for (int i = 0; i < currentDRP.RowsCount; i++)
                    {
                        for (int j = 0; j < currentDRP.ColsCount; j++)
                        {
                            currentDRP[i, j] = new Cell();
                        }
                    }

                    // дрп, в котором будут объединены все слои с проводами (для определения гдле занята ячейка - где нет)
                    Matrix <Cell> fullDrp;

                    // получаем из провода стартовую и конечную позицию
                    var startPos = wire.A.PositionContact;
                    var endPos   = wire.B.PositionContact;

                    // помечаем буквами стартовую и конечную позицию на текущем слое провода
                    currentDRP[startPos.Row, startPos.Column].State = CellState.PointA;
                    currentDRP[endPos.Row, endPos.Column].State     = CellState.PointB;

                    log.Add(new StepTracingLog(boards, $"Начинаем трассировку {boardDRPs.Count - 1}-го проводника в {boardNum + 1} узле"));

                    int currentWeight = 0;

                    // у начальной позиции вес 0
                    currentDRP[startPos.Row, startPos.Column].Weight = currentWeight;

                    // объединяем все слои
                    fullDrp = ApplicationData.MergeLayersDRPs(boardDRPs);

                    // и получаем незанятых соседей для начальной точки
                    var neighbors = getNeighbors(fullDrp, startPos);

                    // запускаем цикл пока не будет найдено ни одного незанятого соседа или в списке соседей окажется точка Б
                    do
                    {
                        // увеличиваем вес
                        currentWeight++;

                        // запускаем цикл по всем незанятым соседним ячейкам
                        foreach (var neighbor in neighbors)
                        {
                            // распространяем волну
                            currentDRP[neighbor.Row, neighbor.Column].Weight = currentWeight;
                            currentDRP[neighbor.Row, neighbor.Column].State  = CellState.Wave;
                            fullDrp[neighbor.Row, neighbor.Column].Weight    = currentWeight;
                            fullDrp[neighbor.Row, neighbor.Column].State     = CellState.Wave;
                        }

                        if (!isOptimized)
                        {
                            log.Add(new StepTracingLog(boards, $"Распроcтраняем волну с весом {currentWeight} для {boardDRPs.Count - 1}-го проводника в {boardNum+1} узле"));
                        }

                        // и получаем список незанятых соседей для ячеек текущей волны
                        neighbors = getNeighbors(fullDrp, neighbors);
                    } while (neighbors.Count > 0 && !neighbors.Any(x => x.Equals(endPos)));

                    // если незанятых соседей не оказалось, значит трассировка невозможна
                    if (neighbors.Count == 0)
                    {
                        log.Add(new StepTracingLog(boards, $"Невозможно выполнить трассировку {boardDRPs.Count - 1}-го проводника в {boardNum + 1} узле"));
                        // очищаем текущее дрп
                        for (int i = 0; i < currentDRP.RowsCount; i++)
                        {
                            for (int j = 0; j < currentDRP.ColsCount; j++)
                            {
                                if (currentDRP[i, j].State == CellState.Wave)
                                {
                                    currentDRP[i, j].State = CellState.Empty;
                                }
                                currentDRP[i, j].Weight = -1;
                            }
                        }
                        currentDRP[startPos.Row, startPos.Column].State = CellState.Contact;
                        currentDRP[endPos.Row, endPos.Column].State     = CellState.Contact;
                        continue;
                    }

                    if (isOptimized)
                    {
                        log.Add(new StepTracingLog(boards, $"Волна {boardDRPs.Count - 1}-го проводника достигла точки Б в {boardNum + 1} узле"));
                    }


                    // теперь начинаем обратный крестовый поход от точки Б
                    neighbors = new List <Position>();
                    neighbors.Add(endPos);

                    Position currentPos = endPos.Clone();
                    fullDrp = ApplicationData.MergeLayersDRPs(boardDRPs);
                    do
                    {
                        // получаем список волновых соседей
                        neighbors = getNeighborsOnlyWave(fullDrp, currentPos);

                        foreach (var neighbor in neighbors)
                        {
                            // находим в списке соседей первую ячейку с волной необходимого веса
                            if (currentDRP[neighbor.Row, neighbor.Column].Weight == currentWeight)
                            {
                                // помечаем что в этой ячейке будет находится проводник, но какой имеено определим ниже
                                currentDRP[neighbor.Row, neighbor.Column].State = CellState.Wire;
                                fullDrp[neighbor.Row, neighbor.Column].State    = CellState.Wire;
                                currentPos = neighbor.Clone();
                                break;
                            }
                        }

                        // на каждом шаге уменьшаем вес
                        currentWeight--;
                    } while (currentWeight >= 0);

                    // очищаем всё дрп от веса и ячеек с волной
                    for (int i = 0; i < currentDRP.RowsCount; i++)
                    {
                        for (int j = 0; j < currentDRP.ColsCount; j++)
                        {
                            currentDRP[i, j].Weight = -1;
                            if (currentDRP[i, j].State == CellState.Wave)
                            {
                                currentDRP[i, j].State = CellState.Empty;
                            }
                        }
                    }

                    log.Add(new StepTracingLog(boards, $"Волна достигла точки Б. Определяем точки, где будет проходить проводник №{boardDRPs.Count - 1} в {boardNum + 1} узле"));

                    // начинаем долгую и мучительную спец операцию по определению какой формы проводник должен стоять в ячейке
                    // запускаем цикл по всем ячейкам дрп
                    for (int i = 0; i < currentDRP.RowsCount; i++)
                    {
                        for (int j = 0; j < currentDRP.ColsCount; j++)
                        {
                            // объявляем соседей, от них нам нужно будет только состояние
                            Cell leftCell   = new Cell();
                            Cell rightCell  = new Cell();
                            Cell topCell    = new Cell();
                            Cell bottomCell = new Cell();

                            // блок, который присвоит пустое состояние ячейке, если она находится вне дрп, если находится в дрп, то присвоит нужную позицию
                            if (j > 0)
                            {
                                leftCell = currentDRP[i, j - 1];
                            }
                            else
                            {
                                leftCell.State = CellState.Empty;
                            }

                            if (j < currentDRP.ColsCount - 1)
                            {
                                rightCell = currentDRP[i, j + 1];
                            }
                            else
                            {
                                rightCell.State = CellState.Empty;
                            }

                            if (i > 0)
                            {
                                topCell = currentDRP[i - 1, j];
                            }
                            else
                            {
                                topCell.State = CellState.Empty;
                            }

                            if (i < currentDRP.RowsCount - 1)
                            {
                                bottomCell = currentDRP[i + 1, j];
                            }
                            else
                            {
                                bottomCell.State = CellState.Empty;
                            }
                            // конец блока

                            var currentCell = currentDRP[i, j];

                            // если текущая ячейка должна быть каким-то кабелем
                            // определяем значения ячеек вокруг и на основе этих данных узнаём какой имеено должен быть кабель
                            // идущим вертикально или слева вверх или горизонтальным и т.д.
                            if (currentCell.State == CellState.Wire)
                            {
                                // если есть кабель сверху и кабель в ячейке снизу, то в текущей ячейке должен стоять вертикальный проводник
                                if (topCell.isConnectible && bottomCell.isConnectible)
                                {
                                    currentDRP[i, j].State = CellState.WireVertical;
                                }
                                else if (leftCell.isConnectible && rightCell.isConnectible)
                                {
                                    currentDRP[i, j].State = CellState.WireHorizontal;
                                }
                                else if (topCell.isConnectible && leftCell.isConnectible)
                                {
                                    currentDRP[i, j].State = CellState.WireTopLeft;
                                }
                                else if (topCell.isConnectible && rightCell.isConnectible)
                                {
                                    currentDRP[i, j].State = CellState.WireTopRight;
                                }
                                else if (bottomCell.isConnectible && leftCell.isConnectible)
                                {
                                    currentDRP[i, j].State = CellState.WireBottomLeft;
                                }
                                else if (bottomCell.isConnectible && rightCell.isConnectible)
                                {
                                    currentDRP[i, j].State = CellState.WireBottomRight;
                                }
                            }
                        }
                    }

                    // заменяем буквы просто контактами
                    currentDRP[startPos.Row, startPos.Column].State = CellState.Contact;
                    currentDRP[endPos.Row, endPos.Column].State     = CellState.Contact;
                    log.Add(new StepTracingLog(boards, $"Построили на базе точек проводник №{boardDRPs.Count - 1} в {boardNum + 1} узле"));
                }
            }
            return(log);
        }