private int[,] BuildTimeMap() { if (PathToNextPositionLength == 0) { return Tail.Length > 1 ? BuildOutsideTimeMap() : BuildInsideTimeMap(); } if (Tail.Length == 0 || Territory.Contains(Position.MoveLogic(Direction.Value))) // Возможно, когда ход закончится следующая клетка будет уже не территорией игрока, но мы выбираем худший для нас вариант { return BuildInsideTimeMap(); } return BuildOutsideTimeMap(); }
private unsafe int[,] BuildOutsideTimeMap() { var timeMap = Game.GetNewMap<int>(); Utils.FastCopyArray(Game.NoEnemiesDangerousMap, timeMap, GameParams.MapSize.Width*GameParams.MapSize.Height); var distanceMap = stackalloc int[GameParams.MapSize.Width*GameParams.MapSize.Height]; var visited = stackalloc bool[GameParams.MapSize.Width*GameParams.MapSize.Height]; var timeMapAfterHome = stackalloc int[GameParams.MapSize.Width*GameParams.MapSize.Height]; var distanceMapAfterHome = stackalloc int[GameParams.MapSize.Width*GameParams.MapSize.Height]; var visitedAfterHome = stackalloc bool[GameParams.MapSize.Width*GameParams.MapSize.Height]; Point startPoint; int currentTime; int currentDistance; if (PathToNextPositionLength > 0) { startPoint = Position.MoveLogic(Direction.Value); currentTime = (GameParams.CellSize - PathToNextPositionLength)/GetSpeed(0); currentDistance = 1; } else { startPoint = Position; currentTime = 0; currentDistance = 0; } int startPointCoord = startPoint.X + startPoint.Y*GameParams.MapSize.Width; timeMap[startPoint.X, startPoint.Y] = currentTime; distanceMap[startPointCoord] = currentDistance; visited[startPointCoord] = true; var queue = new Queue<(Point Point, bool AfterHome, Direction? VisitHomeDirection)>(GameParams.MapSize.Width*GameParams.MapSize.Height); queue.Enqueue((startPoint, false, null)); bool visitHome = false; while (queue.Count > 0) { (var currentPoint, bool afterHome, var visitHomeDirection) = queue.Dequeue(); int currentCoord = currentPoint.X + currentPoint.Y*GameParams.MapSize.Width; if (!afterHome) { currentTime = timeMap[currentPoint.X, currentPoint.Y]; currentDistance = distanceMap[currentCoord]; foreach (var direction in EnumValues.GetAll<Direction>()) { var neighbor = currentPoint.MoveLogic(direction); int neighborCoord = neighbor.X + neighbor.Y*GameParams.MapSize.Width; if (!GameParams.MapSize.ContainsPoint(neighbor) || Tail.AsPointsSet().Contains(neighbor)) { continue; } if (Territory.Contains(neighbor) && !Territory.Contains(currentPoint) && !visitedAfterHome[neighborCoord]) { queue.Enqueue((neighbor, true, direction)); distanceMapAfterHome[neighborCoord] = currentDistance + 1; timeMapAfterHome[neighborCoord] = currentTime + GameParams.CellSize/GetSpeed(currentDistance); visitHome = true; } if (visited[neighborCoord]) { continue; } distanceMap[neighborCoord] = currentDistance + 1; timeMap[neighbor.X, neighbor.Y] = currentTime + GameParams.CellSize/GetSpeed(currentDistance); visited[neighborCoord] = true; queue.Enqueue((neighbor, false, null)); } } else { currentTime = timeMapAfterHome[currentCoord]; currentDistance = distanceMapAfterHome[currentCoord]; foreach (var direction in EnumValues.GetAll<Direction>()) { var neighbor = currentPoint.MoveLogic(direction); int neighborCoord = neighbor.X + neighbor.Y*GameParams.MapSize.Width; if (!GameParams.MapSize.ContainsPoint(neighbor) || visitedAfterHome[neighborCoord] || visitHomeDirection == direction.GetOpposite()) { continue; } distanceMapAfterHome[neighborCoord] = currentDistance + 1; timeMapAfterHome[neighborCoord] = currentTime + GameParams.CellSize/GetSpeed(currentDistance); visitedAfterHome[neighborCoord] = true; queue.Enqueue((neighbor, true, null)); } } } if (!visitHome) { return timeMap; } for (int y = 0; y < GameParams.MapSize.Height; y++) { for (int x = 0; x < GameParams.MapSize.Width; x++) { timeMap[x, y] = Math.Min(timeMap[x, y], timeMapAfterHome[x + y*GameParams.MapSize.Width]); } } return timeMap; }