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); }
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)); }
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))); }
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))); }
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))); }
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)))); }
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); }
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))); }
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) ); } }
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))); }
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))); }
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)); }
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; } }
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); }
/// <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}"; } } }
/// <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)); }
/// <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); }
public bool TrySelectActivationSynchronously( PlacementStrategy strategy, GrainId target, IPlacementRuntime context, out PlacementResult placementResult) { placementResult = SelectActivationCore(strategy, target, context); return(placementResult != null); }
/// <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); }
/// <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); }