public void CardinalFirstDirections(AdjacencyRule rule)
        {
            Direction[] cardsFirst   = rule.DirectionsOfNeighbors().ToArray();
            Direction[] expectedDirs = rule.DirectionsOfNeighborsClockwise().ToArray();
            Assert.Equal(expectedDirs.Length, cardsFirst.Length);

            int index = Array.FindIndex(cardsFirst, i => !i.IsCardinal());

            if (index == -1)
            {
                Assert.Equal(4, cardsFirst.Length);
            }
            else
            {
                for (int i = 0; i < cardsFirst.Length; i++)
                {
                    if (cardsFirst[i].IsCardinal())
                    {
                        Assert.True(i < index);
                    }
                    else
                    {
                        Assert.True(i >= index);
                    }
                }
            }
        }
Beispiel #2
0
        /// <summary>
        /// Gets the direction of the neighbor with the minimum goal-map value from the given position.
        /// </summary>
        /// <param name="goalMap" />
        /// <param name="position">The position to get the minimum value for.</param>
        /// <param name="adjacencyRule">The adjacency rule to use to determine neighbors.</param>
        /// <returns>
        /// The direction that has the minimum value in the goal-map, or <see cref="SadRogue.Primitives.Direction.None" /> if the
        /// neighbors are all obstacles.
        /// </returns>
        public static Direction GetDirectionOfMinValue(this IGridView <double?> goalMap, Point position,
                                                       AdjacencyRule adjacencyRule)
        {
            var min    = goalMap[position].HasValue ? goalMap[position] !.Value : double.MaxValue;
            var minDir = Direction.None;

            for (int i = 0; i < adjacencyRule.DirectionsOfNeighborsCache.Length; i++)
            {
                var newPosition = position + adjacencyRule.DirectionsOfNeighborsCache[i];

                if (!goalMap.Contains(newPosition) || !goalMap[newPosition].HasValue)
                {
                    continue;
                }

                // <= to prefer movement over non movement; known to be not null thanks to above continue
                if (goalMap[newPosition] !.Value <= min)
                {
                    min    = goalMap[newPosition] !.Value; // Again known to be not null thanks to above continue
                    minDir = adjacencyRule.DirectionsOfNeighborsCache[i];
                }
            }

            return(minDir); // Direction.None if all obstacles
        }
Beispiel #3
0
        /// <summary>
        /// Connects the areas by determining all unique areas on the map given using a <see cref="MapAreaFinder"/>,
        /// and then, if <paramref name="randomizeOrder"/> is true, performing a Fisher Yates shuffle of that
        /// list of areas found. It then simply connects areas adjacent to each other in that list,
        /// using the methods specified to determine points within two areas to connect, and how to
        /// create the tunnel between the two points.
        /// </summary>
        /// <param name="map">The map to connect.</param>
        /// <param name="adjacencyRule">
        /// Method of adjacency to respect when determining map areas. Cannot be diagonal.
        /// </param>
        /// <param name="areaConnector">
        /// The method to use to determine the points from two areas to make a tunnel between, in
        /// order to connect those two areas. If null is specified, a <see cref="RandomConnectionPointSelector"/>
        /// is used, that uses the RNG passed into this function.
        /// </param>
        /// <param name="tunnelCreator">
        /// The tunnel creation strategy to use. If null is specified,
        /// <see cref="HorizontalVerticalTunnelCreator"/> that utilizes the RNG passed into this function is used.
        /// </param>
        /// <param name="rng">The rng to use. If null is specified, the default rng is assumed.</param>
        /// <param name="randomizeOrder">
        /// Whether or not to randomize which room is connected to which -- if this is set to false,
        /// they will be conencted in the exact order they are returned from the <see cref="MapAreaFinder"/>.
        /// </param>
        static public void Connect(ISettableMapView <bool> map, AdjacencyRule adjacencyRule, IAreaConnectionPointSelector areaConnector = null,
                                   ITunnelCreator tunnelCreator = null, IGenerator rng = null, bool randomizeOrder = true)
        {
            if (adjacencyRule == AdjacencyRule.DIAGONALS)
            {
                throw new System.ArgumentException("Cannot specify diagonal adjacency for map connections.", nameof(adjacencyRule));
            }
            if (rng == null)
            {
                rng = SingletonRandom.DefaultRNG;
            }
            if (areaConnector == null)
            {
                areaConnector = new RandomConnectionPointSelector(rng);
            }
            if (tunnelCreator == null)
            {
                tunnelCreator = new HorizontalVerticalTunnelCreator(rng);
            }

            var areas = MapAreaFinder.MapAreasFor(map, adjacencyRule).ToList();

            if (randomizeOrder)
            {
                areas.FisherYatesShuffle(rng);
            }

            Connect(map, areas, areaConnector, tunnelCreator);
        }
        public void NeighborsUnordered(Point point, AdjacencyRule rule)
        {
            Point[] result   = rule.Neighbors(point).ToArray();
            Point[] expected = rule.DirectionsOfNeighbors().Select(i => point + i).ToArray();

            TestUtils.AssertElementEquals(result, expected);
        }
Beispiel #5
0
 /// <summary>
 /// Constructor. Takes the distance calculation to use, which determines whether <see cref="Lines.Algorithm.ORTHO"/>
 /// or <see cref="Lines.Algorithm.BRESENHAM"/> is used to create the tunnel.
 /// </summary>
 /// <param name="adjacencyRule">
 /// Method of adjacency to respect when creating tunnels. Cannot be diagonal.
 /// </param>
 public DirectLineTunnelCreator(AdjacencyRule adjacencyRule)
 {
     if (adjacencyRule == AdjacencyRule.DIAGONALS)
     {
         throw new System.ArgumentException("Cannot use diagonal adjacency to create tunnels", nameof(adjacencyRule));
     }
     this.adjacencyRule = adjacencyRule;
 }
        public void AdjacencyRuleToType()
        {
            AdjacencyRule original = AdjacencyRule.Diagonals;

            AdjacencyRule.Types expressive = (AdjacencyRule.Types)original;
            AdjacencyRule       converted  = (AdjacencyRule)expressive;

            Assert.Equal(original, converted);
        }
Beispiel #7
0
 /// <summary>
 /// Constructor. Takes the distance calculation to use, which determines whether <see cref="Lines.Algorithm.Orthogonal" />
 /// or <see cref="Lines.Algorithm.Bresenham" /> is used to create the tunnel.
 /// </summary>
 /// <param name="adjacencyRule">
 /// Method of adjacency to respect when creating tunnels. Cannot be diagonal.
 /// </param>
 /// <param name="doubleWideVertical">Whether or not to create vertical tunnels as 2-wide.</param>
 public DirectLineTunnelCreator(AdjacencyRule adjacencyRule, bool doubleWideVertical = true)
 {
     if (adjacencyRule == AdjacencyRule.Diagonals)
     {
         throw new ArgumentException("Cannot use diagonal adjacency to create tunnels", nameof(adjacencyRule));
     }
     _adjacencyRule      = adjacencyRule;
     _doubleWideVertical = doubleWideVertical;
 }
Beispiel #8
0
        public Coord GetClosestAvailablePoint(Coord coord)
        {
            FastPriorityQueue <DijkstraNode> frontier = new FastPriorityQueue <DijkstraNode>(AvailabilityMap.Height * AvailabilityMap.Width);

            DijkstraNode[] explored = new DijkstraNode[AvailabilityMap.Height * AvailabilityMap.Width];

            AdjacencyRule adjacencyRule = Distance;

            DijkstraNode initial = new DijkstraNode(coord, null);

            initial.Distance = 0;

            frontier.Enqueue(initial, 0);

            while (frontier.Count > 0)
            {
                DijkstraNode current = frontier.Dequeue();

                if (AvailabilityMap[current.Position])
                {
                    return(current.Position);
                }

                foreach (Coord neighbor in adjacencyRule.Neighbors(current.Position))
                {
                    if (!WalkabilityMap[neighbor])
                    {
                        continue;
                    }

                    int   neighborIndex    = neighbor.ToIndex(AvailabilityMap.Width);
                    bool  neighborExplored = explored[neighborIndex] != null;
                    float neighborDistance = (float)Distance.Calculate(current.Position, neighbor) + current.Distance;

                    DijkstraNode neighborNode =
                        neighborExplored ? explored[neighborIndex] : new DijkstraNode(neighbor, current);

                    explored[neighborIndex] = neighborNode;

                    if (neighborExplored && neighborDistance < neighborNode.Distance)
                    {
                        neighborNode.Distance = neighborDistance;
                        frontier.UpdatePriority(neighborNode, neighborNode.Distance);
                    }
                    else
                    {
                        neighborNode.Distance = neighborDistance;
                        frontier.Enqueue(neighborNode, neighborDistance);
                    }
                }
            }

            return(Coord.NONE);
        }
Beispiel #9
0
        public static IEnumerable <Direction> GetImprovingDirections(this IMapView <double?> goalMap, Coord position,
                                                                     AdjacencyRule adjacencyRule)
        {
            double current = goalMap[position].HasValue ? goalMap[position].Value : double.MaxValue;

            List <(Direction, double)> improvements = new List <(Direction, double)>();

            improvements.Add((Direction.NONE, current));

            foreach (Direction dir in adjacencyRule.DirectionsOfNeighbors())
            {
                Coord newPosition = position + dir;
                if (!goalMap[newPosition].HasValue)
                {
                    continue;
                }

                // Consider orthogonal movement in order to "slip" around obstacles (less than 1 extra distance)
                if (goalMap[newPosition].Value - current < 1)
                {
                    improvements.Add((dir, goalMap[newPosition].Value));
Beispiel #10
0
        /// <summary>
        /// Convenience function that creates a MapAreaFinder and returns the result of that
        /// instances <see cref="MapAreas"/> function. Intended to be used for cases in which the area finder
        /// will never be re-used.
        /// </summary>
        /// <param name="map">
        /// Map view indicating which cells should be considered part of a map area and which should not.
        /// </param>
        /// <param name="adjacencyMethod">The method used for determining connectivity of the grid.</param>
        /// <returns>An IEnumerable of each (unique) map area.</returns>
        static public IEnumerable <MapArea> MapAreasFor(IMapView <bool> map, AdjacencyRule adjacencyMethod)
        {
            var areaFinder = new MapAreaFinder(map, adjacencyMethod);

            return(areaFinder.MapAreas());
        }
Beispiel #11
0
 /// <summary>
 /// Constructor.
 /// </summary>
 /// <param name="map">
 /// Map view indicating which cells should be considered part of a map area and which should not.
 /// </param>
 /// <param name="adjacencyMethod">The method used for determining connectivity of the grid.</param>
 public MapAreaFinder(IMapView <bool> map, AdjacencyRule adjacencyMethod)
 {
     Map             = map;
     visited         = null;
     AdjacencyMethod = adjacencyMethod;
 }
        public static IEnumerable <Area> MapAreasFor(IGridView <bool> map, AdjacencyRule adjacencyMethod)
        {
            var areaFinder = new HashSetSizeHashMapAreaFinder(map, adjacencyMethod);

            return(areaFinder.MapAreas());
        }
 public HashSetSizeHashMapAreaFinder(IGridView <bool> areasView, AdjacencyRule adjacencyMethod)
 {
     AreasView       = areasView;
     _visited        = new HashSet <Point>(new KnownSizeHasher(areasView.Width));
     AdjacencyMethod = adjacencyMethod;
 }
Beispiel #14
0
 /// <summary>
 /// Gets the direction of the neighbor with the minimum goal-map value from the given position.
 /// </summary>
 /// <param name="goalMap"/>
 /// <param name="positionX">The x-value of the position to get the minimum value for.</param>
 /// <param name="positionY">The y-value of the position to get the minimum value for.</param>
 /// <param name="adjacencyRule">The adjacency rule to use to determine neighbors.</param>
 /// <returns>
 /// The direction that has the minimum value in the goal-map, or <see cref="Direction.NONE"/> if the
 /// neighbors are all obstacles.
 /// </returns>
 public static Direction GetDirectionOfMinValue(this IMapView <double?> goalMap, int positionX, int positionY, AdjacencyRule adjacencyRule)
 => goalMap.GetDirectionOfMinValue(new Coord(positionX, positionY), adjacencyRule);
Beispiel #15
0
        /// <summary>
        /// Gets the direction of the neighbor with the minimum goal-map value from the given position.
        /// </summary>
        /// <param name="goalMap"/>
        /// <param name="position">The position to get the minimum value for.</param>
        /// <param name="adjacencyRule">The adjacency rule to use to determine neighbors.</param>
        /// <returns>
        /// The direction that has the minimum value in the goal-map, or <see cref="Direction.NONE"/> if the
        /// neighbors are all obstacles.
        /// </returns>
        public static Direction GetDirectionOfMinValue(this IMapView <double?> goalMap, Coord position, AdjacencyRule adjacencyRule)
        {
            double    min    = double.MaxValue;
            Direction minDir = Direction.NONE;

            foreach (var dir in adjacencyRule.DirectionsOfNeighbors())
            {
                Coord newPosition = position + dir;
                if (!goalMap[newPosition].HasValue)
                {
                    continue;
                }

                if (goalMap[newPosition].Value < min)
                {
                    min    = goalMap[newPosition].Value;
                    minDir = dir;
                }
            }

            return(minDir);            // Direction.NONE if all obstacles
        }
        public void AdjacencyRuleTypeConversion(AdjacencyRule.Types type, AdjacencyRule expectedRule)
        {
            AdjacencyRule dir = type;

            Assert.Equal(expectedRule, dir);
        }
Beispiel #17
0
        private void Update()
        {
            int           width         = Width;
            AdjacencyRule adjacencyRule = _baseMap.DistanceMeasurement;

            var mapBounds = _goalMap.Bounds();

            var walkable = _baseMap.Walkable;

            for (int i = 0; i < walkable.Count; i++)
            {
                var point = walkable[i];

                // Value won't be null as null only happens for non-walkable squares
                var newPoint = _baseMap[point] !.Value * -Magnitude;
                _goalMap[point] = newPoint;

                _openSet.Enqueue(_nodes[point], newPoint);
            }

            _edgeSet.Clear();
            _closedSet.SetAll(false);

            while (_openSet.Count > 0) // Multiple runs are needed to deal with islands
            {
                var minNode = _openSet.Dequeue();
                _closedSet[minNode.Position.ToIndex(width)] = true;

                for (int i = 0; i < adjacencyRule.DirectionsOfNeighborsCache.Length; i++)
                {
                    var openPoint = minNode.Position + adjacencyRule.DirectionsOfNeighborsCache[i];
                    if (!mapBounds.Contains(openPoint))
                    {
                        continue;
                    }

                    if (!_closedSet[openPoint.ToIndex(width)] && _baseMap.BaseMap[openPoint] != GoalState.Obstacle)
                    {
                        _edgeSet.Enqueue(openPoint);
                    }
                }

                while (_edgeSet.Count > 0)
                {
                    var point      = _edgeSet.Dequeue();
                    var pointIndex = point.ToIndex(width);
                    if (!mapBounds.Contains(point) || _closedSet[pointIndex])
                    {
                        continue;
                    }

                    var current = _goalMap[point] !.Value; // Never added non-nulls so this is fine

                    for (int j = 0; j < adjacencyRule.DirectionsOfNeighborsCache.Length; j++)
                    {
                        var openPoint = point + adjacencyRule.DirectionsOfNeighborsCache[j];
                        if (!mapBounds.Contains(openPoint))
                        {
                            continue;
                        }
                        if (_closedSet[openPoint.ToIndex(width)] || _baseMap.BaseMap[openPoint] == GoalState.Obstacle)
                        {
                            continue;
                        }

                        var neighborValue = _goalMap[openPoint] !.Value; // Never added non-nulls so this is fine
                        var newValue      = current + _baseMap.DistanceMeasurement.Calculate(point, openPoint);
                        if (newValue < neighborValue)
                        {
                            _goalMap[openPoint] = newValue;
                            _openSet.UpdatePriority(_nodes[openPoint], newValue);
                            _edgeSet.Enqueue(openPoint);
                        }
                    }

                    _closedSet[pointIndex] = true;
                    _openSet.Remove(_nodes[point]);
                }
            }
        }
 public HashSetDefaultHashMapAreaFinder(IGridView <bool> areasView, AdjacencyRule adjacencyMethod)
 {
     AreasView       = areasView;
     _visited        = new HashSet <Point>();
     AdjacencyMethod = adjacencyMethod;
 }
 public OriginalMapAreaFinder(IGridView <bool> areasView, AdjacencyRule adjacencyMethod)
 {
     AreasView       = areasView;
     _visited        = null;
     AdjacencyMethod = adjacencyMethod;
 }
        public void Init(MyObjectBuilder_CubeBlock block, string piece, IEnumerable <string> args)
        {
            Piece                = piece;
            MountDirection6      = Base6Directions.GetOppositeDirection(Base6Directions.GetCross(block.BlockOrientation.Up, block.BlockOrientation.Forward));
            AnchorLocation       = block.Min;
            AdjacencyRule        = AdjacencyRule.Any;
            BiasDirection6       = null;
            SecondBiasDirection6 = null;

            var blockOrientation = new MatrixI(block.BlockOrientation);

            foreach (var arg in args)
            {
                if (arg.StartsWithICase(PartDummyUtils.ArgumentMountDirection))
                {
                    Base6Directions.Direction tmpMountDirection;
                    if (Enum.TryParse(arg.Substring(PartDummyUtils.ArgumentMountDirection.Length), out tmpMountDirection))
                    {
                        MountDirection6 = blockOrientation.GetDirection(tmpMountDirection);
                    }
                    else
                    {
                        Logging.Error("Failed to parse mount point direction argument \"{0}\"", arg);
                    }
                }
                else if (arg.StartsWithICase(PartDummyUtils.ArgumentBiasDirection))
                {
                    Base6Directions.Direction tmpBiasDirection;
                    if (Enum.TryParse(arg.Substring(PartDummyUtils.ArgumentBiasDirection.Length), out tmpBiasDirection))
                    {
                        BiasDirection6 = blockOrientation.GetDirection(tmpBiasDirection);
                    }
                    else
                    {
                        Logging.Error("Failed to parse bias direction argument \"{0}\"", arg);
                    }
                }
                else if (arg.StartsWithICase(PartDummyUtils.ArgumentSecondBiasDirection))
                {
                    Base6Directions.Direction tmpBiasDirection;
                    if (Enum.TryParse(arg.Substring(PartDummyUtils.ArgumentSecondBiasDirection.Length), out tmpBiasDirection))
                    {
                        SecondBiasDirection6 = blockOrientation.GetDirection(tmpBiasDirection);
                    }
                    else
                    {
                        Logging.Error("Failed to parse second bias direction argument \"{0}\"", arg);
                    }
                }
                else if (arg.StartsWithICase(PartDummyUtils.ArgumentAnchorPoint))
                {
                    Vector3I anchor;
                    if (PartDummyUtils.TryParseVector(arg.Substring(PartDummyUtils.ArgumentAnchorPoint.Length), out anchor))
                    {
                        AnchorLocation = block.Min + anchor;
                        continue;
                    }
                    Logging.Error("Failed to parse anchor location argument \"{0}\"", arg);
                }
                else if (arg.StartsWithICase(PartDummyUtils.ArgumentAdjacencyRule)) // Adjacency Rule
                {
                    AdjacencyRule rule;
                    if (Enum.TryParse(arg.Substring(PartDummyUtils.ArgumentAdjacencyRule.Length), out rule))
                    {
                        AdjacencyRule = rule;
                    }
                    else
                    {
                        Logging.Error("Failed to parse adjacency rule argument \"{0}\"", arg);
                    }
                }
                else
                {
                    Logging.Error("Failed to parse mount point argument \"{0}\"", arg);
                }
            }
            // ReSharper disable once InvertIf
            if (SecondBiasDirection6.HasValue && !BiasDirection6.HasValue)
            {
                BiasDirection6       = SecondBiasDirection6;
                SecondBiasDirection6 = null;
            }
        }
Beispiel #21
0
 public AreaContainsDefaultHashMapAreaFinder(IGridView <bool> areasView, AdjacencyRule adjacencyMethod)
 {
     AreasView       = areasView;
     AdjacencyMethod = adjacencyMethod;
     _foundAreas     = new MultiArea();
 }