Ejemplo n.º 1
0
        IEnumerator Pathfind()
        {
            frontier.Enqueue(new InternalPathNode(startPos, ActionType.WALK), 0);

            movementCosts.Set(startPos, 0);
            parents.Set(startPos, new InternalPathNode(startPos, ActionType.WALK));
            closestDistance = int.MaxValue;

            InternalPathNode current;

            var cycles = 0;

            while (frontier.Count > 0)
            {
                ++cycles;

                current = frontier.Dequeue();


                var adj = GetAdjacent(current.coord);
                foreach (var pos in adj)
                {
                    if (!IsClosed(pos.coord))
                    {
                        if (!frontier.Contains(pos))
                        {
                            movementCosts.Set(pos.coord, Mathf.Infinity);                             // so (new < orig) comparison works
                        }

                        UpdateNode(current, pos);

                        if (pos.coord == endPos)
                        {
                            ReconstructPath(pos);
                            yield break;
                        }

                        if (HexUtil.DistanceFlat(pos.coord, endPos) < closestDistance)
                        {
                            closestDistance = HexUtil.DistanceFlat(pos.coord, endPos);
                            closestPoint    = pos;
                        }
                    }
                }

                if (cycles >= cyclesPerFrame)
                {
                    cycles = 0;
                    yield return(null);
                }
            }


            // endpos was not on connected graph; return closest node
            ReconstructPath(closestPoint);
        }
Ejemplo n.º 2
0
        private void Update()
        {
            var adjacencyRule = (AdjacencyRule)_baseMap.DistanceMeasurement;
            var openSet       = new GenericPriorityQueue <PositionNode, double>(Width * Height);

            foreach (var point in _baseMap.Walkable)
            {
                var newPoint = _baseMap[point] * -Magnitude;
                _goalMap[point] = newPoint;

                openSet.Enqueue(_nodes[point], newPoint.Value);
            }
            var edgeSet   = new HashSet <Coord>();
            var closedSet = new HashSet <Coord>();

            while (openSet.Count > 0) //multiple runs are needed to deal with islands
            {
                var minNode = openSet.Dequeue();
                closedSet.Add(minNode.Position);

                foreach (var openPoint in adjacencyRule.Neighbors(minNode.Position))
                {
                    if ((!closedSet.Contains(openPoint)) && _baseMap.BaseMap[openPoint] != GoalState.Obstacle)
                    {
                        edgeSet.Add(openPoint);
                    }
                }
                while (edgeSet.Count > 0)
                {
                    foreach (var coord in edgeSet.ToArray())
                    {
                        var current = _goalMap[coord].Value;
                        foreach (var openPoint in adjacencyRule.Neighbors(coord))
                        {
                            if (closedSet.Contains(openPoint) || _baseMap.BaseMap[openPoint] == GoalState.Obstacle)
                            {
                                continue;
                            }
                            var neighborValue = _goalMap[openPoint].Value;
                            var newValue      = current + _baseMap.DistanceMeasurement.Calculate(coord, openPoint);
                            if (newValue < neighborValue)
                            {
                                _goalMap[openPoint] = newValue;
                                openSet.UpdatePriority(_nodes[openPoint], newValue);
                                edgeSet.Add(openPoint);
                            }
                        }
                        edgeSet.Remove(coord);
                        closedSet.Add(coord);
                        openSet.Remove(_nodes[coord]);
                    }
                }
            }
        }
Ejemplo n.º 3
0
    /// <summary>
    /// Enqueue the item with the given priority, without calling lock(_queue) or AddToNodeCache(node)
    /// </summary>
    /// <param name="item"></param>
    /// <param name="priority"></param>
    /// <returns></returns>
    private SimpleNode EnqueueNoLockOrCache(TItem item, TPriority priority)
    {
        SimpleNode node = new SimpleNode(item);

        if (_queue.Count == _queue.MaxSize)
        {
            _queue.Resize(_queue.MaxSize * 2 + 1);
        }
        _queue.Enqueue(node, priority);
        return(node);
    }
Ejemplo n.º 4
0
 /// <summary>
 /// Enqueue a node to the priority queue.  Lower values are placed in front. Ties are broken by first-in-first-out.
 /// This queue automatically resizes itself, so there's no concern of the queue becoming 'full'.
 /// Duplicates are allowed.
 /// O(log n)
 /// </summary>
 public void Enqueue(TItem item, TPriority priority)
 {
     lock (_queue)
     {
         SimpleNode node = new SimpleNode(item);
         if (_queue.Count == _queue.MaxSize)
         {
             _queue.Resize(_queue.MaxSize * 2 + 1);
         }
         _queue.Enqueue(node, priority);
     }
 }
Ejemplo n.º 5
0
    private static Path shortestPath(Tile a, Tile b, Map m)
    {
        //If runtime is too high, use a hash table to store indices
        dijkstraNode[] nodes   = new dijkstraNode[moveList.Count];
        index[]        indices = new index[moveList.Count];
        for (int i = 0; i < moveList.Count; ++i)
        {
            nodes[i].found    = false;
            nodes[i].dist     = 999;
            nodes[i].previous = -1;
            indices[i]        = new index(i);
        }
        int start = moveList.IndexOf(a);
        int end   = moveList.IndexOf(b);
        //<index,weight>
        GenericPriorityQueue <index, int> queue = new GenericPriorityQueue <index, int>(moveList.Count);

        nodes[start].dist = 0;
        for (int i = 0; i < moveList.Count; i++)
        {
            if (i == start)
            {
                queue.Enqueue(indices[i], 0);
            }
            else
            {
                queue.Enqueue(indices[i], 999);
            }
        }

        index tempi;
        int   x, y, r;

        while (queue.Count != 0)
        {
            //for(int k = 0; k<queue.Count; k++) {
            tempi = queue.Dequeue();
            nodes[tempi.i].found = true;
            if (tempi.i == end)
            {
                break;
            }
            x = moveList[tempi.i].getX();
            y = moveList[tempi.i].getY();
            //ideally we shorten this; maybe do some sin/cos stuff in UserMath
            //east
            r = moveList.IndexOf(m.findTile(x + 1, y));
            if (x < m.getMapWidth() - 1 && r != -1 && !nodes[r].found)
            {
                if (!nodes[r].found && nodes[r].dist > movementCosts[moveList[r].getType()] + nodes[tempi.i].dist)
                {
                    nodes[r].dist     = movementCosts[moveList[r].getType()] + nodes[tempi.i].dist;
                    nodes[r].previous = tempi.i;
                    queue.UpdatePriority(indices[r], nodes[r].dist);
                }
            }
            //north
            r = moveList.IndexOf(m.findTile(x, y + 1));
            if (r != -1 && !nodes[r].found && y < m.getMapHeight() - 1)
            {
                if (!nodes[r].found && nodes[r].dist > movementCosts[moveList[r].getType()] + nodes[tempi.i].dist)
                {
                    nodes[r].dist     = movementCosts[moveList[r].getType()] + nodes[tempi.i].dist;
                    nodes[r].previous = tempi.i;
                    queue.UpdatePriority(indices[r], nodes[r].dist);
                }
            }
            //west
            r = moveList.IndexOf(m.findTile(x - 1, y));
            if (r != -1 && !nodes[r].found && x > 0)
            {
                if (!nodes[r].found && nodes[r].dist > movementCosts[moveList[r].getType()] + nodes[tempi.i].dist)
                {
                    nodes[r].dist     = movementCosts[moveList[r].getType()] + nodes[tempi.i].dist;
                    nodes[r].previous = tempi.i;
                    queue.UpdatePriority(indices[r], nodes[r].dist);
                }
            }
            //south
            r = moveList.IndexOf(m.findTile(x, y - 1));
            if (r != -1 && !nodes[r].found && y > 0)
            {
                if (!nodes[r].found && nodes[r].dist > movementCosts[moveList[r].getType()] + nodes[tempi.i].dist)
                {
                    nodes[r].dist     = movementCosts[moveList[r].getType()] + nodes[tempi.i].dist;
                    nodes[r].previous = tempi.i;
                    queue.UpdatePriority(indices[r], nodes[r].dist);
                }
            }
        }        //end of while-loop
        Path ret = new Path();

        if (nodes[end].previous == -1)
        {
            return(null);
        }
        for (int i = end; i != start;)
        {
            ret.insertHead(moveList[i], movementCosts[moveList[i].getType()]);
            i = nodes[i].previous;
        }
        //To impelement; high runtimes might result in reworking this algorithm
        return(ret);
    }
Ejemplo n.º 6
0
        public static List <IPathNode> FindPath(IPathNode start, IPathNode finish)
        {
            if (start == finish)
            {
                return(new List <IPathNode>());
            }

            var frontier = new GenericPriorityQueue <IPathNode, int>(1000);

            frontier.Enqueue(start, 0);
            var              cameFrom  = new Dictionary <IPathNode, IPathNode>();
            var              costSoFar = new Dictionary <IPathNode, int>();
            IPathNode        current;
            IPathNode        next;
            List <IPathNode> neighbours;
            int              newCost;
            int              priority;

            cameFrom[start]  = null;
            costSoFar[start] = 0;


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

                if (current == finish)
                {
                    break;
                }

                neighbours = current.GetNeighbours();

                for (int i = 0; i < neighbours.Count; i++)
                {
                    next    = neighbours[i];
                    newCost = costSoFar[current] + (next == finish || next.IsWalkable ? 1 : 10000);

                    if (!costSoFar.ContainsKey(next) || newCost < costSoFar[next])
                    {
                        if (costSoFar.ContainsKey(next))
                        {
                            costSoFar[next] = newCost;
                        }
                        else
                        {
                            costSoFar.Add(next, newCost);
                        }

                        priority = newCost + finish.GetHeuristic(next);
                        if (frontier.Contains(next))
                        {
                            frontier.UpdatePriority(next, priority);
                        }
                        else
                        {
                            frontier.Enqueue(next, priority);
                        }


                        cameFrom[next] = current;
                    }
                }
            }

            var path = new List <IPathNode>();

            if (cameFrom.ContainsKey(finish))
            {
                IPathNode last = finish;
                path.Add(finish);
                while (cameFrom[last] != start)
                {
                    path.Add(cameFrom[last]);
                    last = cameFrom[last];
                }

                path.Reverse();
            }

            return(path);
        }
Ejemplo n.º 7
0
        /// <summary>
        /// A* search
        /// </summary>
        /// <param name="allowReverse"></param>
        /// <param name="carsToIgnore"></param>
        /// <param name="consistLength"></param>
        protected async System.Threading.Tasks.Task Astar(bool allowReverse, HashSet <string> carsToIgnore, double consistLength, List <TrackTransition> bannedTransitions)
        {
            await Await.BackgroundSyncContext();

            cameFrom  = new Dictionary <RailTrack, RailTrack>();
            costSoFar = new Dictionary <RailTrack, double>();

            //var queue = new PriorityQueue<RailTrack>();
            var queue = new GenericPriorityQueue <RailTrackNode, double>(10000);

            queue.Enqueue(new RailTrackNode(start), 0.0);

            cameFrom.Add(start, start);
            costSoFar.Add(start, 0.0);

            RailTrack current = null;


            while (queue.Count > 0)
            {
                current = queue.Dequeue().track;

                RailTrack prev = null;
                cameFrom.TryGetValue(current, out prev);

                string debug = $"ID: {current.logicTrack.ID.FullID} Prev: {prev?.logicTrack.ID.FullID}";

                List <RailTrack> neighbors = new List <RailTrack>();

                if (current.outIsConnected)
                {
                    neighbors.AddRange(current.GetAllOutBranches().Select(b => b.track));
                }

                if (current.inIsConnected)
                {
                    neighbors.AddRange(current.GetAllInBranches().Select(b => b.track));
                }
                string branches = DumpNodes(neighbors, current);
                debug += "\n" + $"all branches: {branches}";

#if DEBUG2
                Terminal.Log(debug);
#endif

                foreach (var neighbor in neighbors)
                {
                    if (bannedTransitions != null && bannedTransitions.All(t => t.track == current && t.nextTrack == neighbor))
                    {
                        Terminal.Log($"{current.logicTrack.ID.FullID}->{neighbor.logicTrack.ID.FullID} banned");
                        continue;
                    }

                    //if non start/end track is not free omit it
                    if (neighbor != start && neighbor != goal && !neighbor.logicTrack.IsFree(carsToIgnore))
                    {
                        Terminal.Log($"{neighbor.logicTrack.ID.FullID} not free");
                        continue;
                    }

                    //if we could go through junction directly (without reversing)
                    bool isDirect = current.CanGoToDirectly(prev, neighbor);

                    if (!allowReverse && !isDirect)
                    {
                        Terminal.Log($"{neighbor.logicTrack.ID.FullID} reverse needed");
                        continue;
                    }

                    // compute exact cost
                    //double newCost = costSoFar[current] + neighbor.logicTrack.length;
                    double newCost = costSoFar[current] + neighbor.logicTrack.length / neighbor.GetAverageSpeed();

                    if (!isDirect)
                    {
                        // if we can't fit consist on this track to reverse, drop this neighbor
                        if (prev != null && !current.IsDirectLengthEnough(prev, consistLength))
                        {
                            Terminal.Log($"{neighbor.logicTrack.ID.FullID} not long enough to reverse");
                            continue;
                        }

                        //add penalty when we must reverse

                        //newCost += 2.0 * consistLength + 30.0;
                    }

                    // If there's no cost assigned to the neighbor yet, or if the new
                    // cost is lower than the assigned one, add newCost for this neighbor
                    if (!costSoFar.ContainsKey(neighbor) || newCost < costSoFar[neighbor])
                    {
                        // If we're replacing the previous cost, remove it
                        if (costSoFar.ContainsKey(neighbor))
                        {
                            costSoFar.Remove(neighbor);
                            cameFrom.Remove(neighbor);
                        }

                        //Terminal.Log($"neighbor {neighbor.logicTrack.ID.FullID} update {newCost}");

                        costSoFar.Add(neighbor, newCost);
                        cameFrom.Add(neighbor, current);
                        double priority = newCost + Heuristic(neighbor, goal)
                                          / 20.0f; //convert distance to time (t = s / v)
                        queue.Enqueue(new RailTrackNode(neighbor), priority);
                    }
                }
            }

            await Await.UnitySyncContext();
        }
Ejemplo n.º 8
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]);
                }
            }
        }