示例#1
0
        internal static Direction DirectionTo(this Map map, MapPos position, MapPos otherPosition)
        {
            var cycle = DirectionCycleCW.CreateDefault();

            foreach (var direction in cycle)
            {
                if (map.Move(position, direction) == otherPosition)
                {
                    return(direction);
                }
            }

            return(Direction.None);
        }
示例#2
0
 public DirectionCycleCW(DirectionCycleCW other)
     : base(other)
 {
 }
示例#3
0
        /// <summary>
        /// Find the shortest path from start to end (using A*) considering that
        /// the walking time for a serf walking in any direction of the path
        /// should be minimized.Returns a malloc'ed array of directions and
        /// the size of this array in length.
        /// </summary>
        /// <param name="map"></param>
        /// <param name="start"></param>
        /// <param name="end"></param>
        /// <param name="buildingRoad"></param>
        /// <returns></returns>
        public static Road FindShortestPath(Map map, MapPos start, MapPos end, Road buildingRoad = null, int maxLength = int.MaxValue, bool endThere = false)
        {
            if (maxLength < 1)
            {
                return(new Road());
            }

            var startTime = DateTime.Now;
            var open      = new PriorityQueue <SearchNode>(new SearchNodeComparer());
            var closed    = new Dictionary <MapPos, SearchNode>();
            var maxCost   = (uint)maxLength * 511u; // 511 is the max road segment cost

            // Create start node
            var node = new SearchNode()
            {
                Position = end,
                GScore   = 0,
                FScore   = HeuristicCost(map, start, end)
            };

            open.Push(node);

            while (open.Count != 0)
            {
                if ((DateTime.Now - startTime).TotalMilliseconds > 2 * Global.TICK_LENGTH)
                {
                    return(new Road()); // tried too long
                }
                node = open.Pop();

                if (node.Position == start)
                {
                    // Construct solution
                    var solution = new Road();
                    solution.Start(start);

                    solution.Cost = node.GScore;

                    while (node.Parent != null)
                    {
                        var direction = node.Direction;
                        solution.Extend(map, direction.Reverse());
                        node = node.Parent;
                    }

                    return(solution);
                }

                // Put current node on closed list.
                closed.Add(node.Position, node);

                var cycle = DirectionCycleCW.CreateDefault();

                foreach (var direction in cycle)
                {
                    var newPosition = map.Move(node.Position, direction);
                    var cost        = ActualCost(map, node.Position, direction);

                    if (node.GScore + cost > maxCost)
                    {
                        continue; // exceeded max length / max cost
                    }
                    // Check if neighbour is valid.
                    if (!map.IsRoadSegmentValid(node.Position, direction, endThere && node.Position == end) ||
                        (map.GetObject(newPosition) == Map.Object.Flag && newPosition != start))
                    {
                        continue;
                    }

                    if (buildingRoad != null && buildingRoad.HasPosition(map, newPosition) &&
                        newPosition != end && newPosition != start)
                    {
                        continue;
                    }

                    // Check if neighbour is in closed list.
                    if (closed.ContainsKey(newPosition))
                    {
                        continue;
                    }

                    // See if neighbour is already in open list.
                    bool inOpen = false;

                    foreach (var n in open)
                    {
                        if (n.Position == newPosition)
                        {
                            inOpen = true;

                            if (n.GScore > node.GScore + cost)
                            {
                                n.GScore    = node.GScore + cost;
                                n.FScore    = n.GScore + HeuristicCost(map, newPosition, start);
                                n.Parent    = node;
                                n.Direction = direction;

                                // Move element to the back and heapify
                                open.Push(open.Pop());
                            }

                            break;
                        }
                    }

                    // If not found in the open set, create a new node.
                    if (!inOpen)
                    {
                        var newNode = new SearchNode();

                        newNode.Position  = newPosition;
                        newNode.GScore    = node.GScore + cost;
                        newNode.FScore    = newNode.GScore + HeuristicCost(map, newPosition, start);
                        newNode.Parent    = node;
                        newNode.Direction = direction;

                        open.Push(newNode);
                    }
                }
            }

            return(new Road());
        }
示例#4
0
        /// <summary>
        /// Find the shortest existing connection between two arbitrary flags.
        ///
        /// The returned collection contains the directions at each flag on
        /// the path.
        /// </summary>
        /// <param name="map"></param>
        /// <param name="start"></param>
        /// <param name="end"></param>
        /// <returns></returns>
        public static List <Direction> FindShortestRoad(Map map, Flag start, Flag end, out uint totalCost)
        {
            if (start == end)
            {
                totalCost = 0;
                return(new List <Direction>());
            }

            totalCost = uint.MaxValue;
            var startTime = DateTime.Now;
            var open      = new PriorityQueue <FlagSearchNode>(new FlagSearchNodeComparer());
            var closed    = new Dictionary <Flag, FlagSearchNode>();

            // Create start node
            var node = new FlagSearchNode()
            {
                Flag   = end,
                GScore = 0,
                FScore = HeuristicCost(map, start.Position, end.Position)
            };

            open.Push(node);

            while (open.Count != 0)
            {
                if ((DateTime.Now - startTime).TotalMilliseconds > 2 * Global.TICK_LENGTH)
                {
                    return(null); // tried too long
                }
                node = open.Pop();

                if (node.Flag == start)
                {
                    // Construct solution
                    var solution = new List <Direction>();

                    totalCost = node.GScore;

                    while (node.Parent != null)
                    {
                        solution.Add(node.Direction.Reverse());
                        node = node.Parent;
                    }

                    return(solution);
                }

                // Put current node on closed list.
                closed.Add(node.Flag, node);

                var cycle = DirectionCycleCW.CreateDefault();

                foreach (var direction in cycle)
                {
                    var newRoad = node.Flag.GetRoad(direction);
                    var newFlag = node.Flag.GetOtherEndFlag(direction);

                    // Check if neighbour is valid.
                    if (newFlag == null || newRoad == null)
                    {
                        continue;
                    }

                    uint cost = newRoad.Cost;

                    // Check if neighbour is in closed list.
                    if (closed.ContainsKey(newFlag))
                    {
                        continue;
                    }

                    // See if neighbour is already in open list.
                    bool inOpen = false;

                    foreach (var n in open)
                    {
                        if (n.Flag == newFlag)
                        {
                            inOpen = true;

                            if (n.GScore > node.GScore + cost)
                            {
                                n.GScore    = node.GScore + cost;
                                n.FScore    = n.GScore + HeuristicCost(map, newFlag, start);
                                n.Parent    = node;
                                n.Direction = direction;

                                // Move element to the back and heapify
                                open.Push(open.Pop());
                            }

                            break;
                        }
                    }

                    // If not found in the open set, create a new node.
                    if (!inOpen)
                    {
                        var newNode = new FlagSearchNode();

                        newNode.Flag      = newFlag;
                        newNode.GScore    = node.GScore + cost;
                        newNode.FScore    = newNode.GScore + HeuristicCost(map, newFlag, start);
                        newNode.Parent    = node;
                        newNode.Direction = direction;

                        open.Push(newNode);
                    }
                }
            }

            return(null);
        }
示例#5
0
        public static MapPos FindNearestSpot(Map map, MapPos start, Func <Map, MapPos, bool> searchFunc,
                                             Func <Map, MapPos, uint> costFunction = null, int maxDistance = int.MaxValue)
        {
            var startTime = DateTime.Now;
            var open      = new PriorityQueue <SimpleSearchNode>(new SimpleSearchNodeComparer());
            var visited   = new List <MapPos>();

            // Create start node
            var node = new SimpleSearchNode()
            {
                Position = start,
                Distance = 0,
            };

            open.Push(node);

            while (open.Count != 0)
            {
                if ((DateTime.Now - startTime).TotalMilliseconds > 2 * Global.TICK_LENGTH)
                {
                    return(Global.INVALID_MAPPOS); // tried too long
                }
                node = open.Pop();

                if (searchFunc(map, node.Position))
                {
                    return(node.Position);
                }

                // Put current node on closed list.
                visited.Insert(0, node.Position);

                if (node.Distance >= maxDistance)
                {
                    continue;
                }

                var cycle = DirectionCycleCW.CreateDefault();

                foreach (var direction in cycle)
                {
                    var newPosition = map.Move(node.Position, direction);
                    var distance    = node.Distance + 1;

                    // Check if neighbour was already visited.
                    if (visited.Contains(newPosition))
                    {
                        continue;
                    }

                    // See if neighbour is already in open list.
                    bool inOpen = false;

                    foreach (var n in open)
                    {
                        if (n.Position == newPosition)
                        {
                            inOpen = true;

                            if (n.Distance > distance)
                            {
                                n.Distance = distance;
                                n.Parent   = node;

                                // Move element to the back and heapify
                                open.Push(open.Pop());
                            }

                            break;
                        }
                    }

                    // If not found in the open set, create a new node.
                    if (!inOpen)
                    {
                        var newNode = new SimpleSearchNode();

                        newNode.Position = newPosition;
                        newNode.Distance = distance;
                        newNode.Parent   = node;
                        newNode.Cost     = (costFunction == null) ? 0u : costFunction(map, newPosition);

                        open.Push(newNode);
                    }
                }
            }

            return(Global.INVALID_MAPPOS);
        }