Ejemplo n.º 1
0
 public void InitNode(int index, int cost, AStarNode predecessor)
 {
     this.routeCost   = cost;
     this.predecessor = predecessor;
     this.index       = index;
 }
Ejemplo n.º 2
0
        public (int, int[]) AStar(int x, int y, SortedList <int, List <int> > constraints, int beginTime, bool reverseSearch)
        {
            if (reverseSearch)
            {
                var tmp = x;
                x = y;
                y = tmp;
            }
            var queue = aStarQueue;

            EnqueueNode(x, 0, 0, null);

            while (queue.Count != 0)
            {
                var currNode = queue.Dequeue();
                queueCacheA[currNode.index] = null;
                var currRouteCost = currNode.routeCost;

                // If goal node.
                if (currNode.index == y)
                {
                    var result = new int[currNode.routeCost + 1];
                    result[currNode.routeCost] = currNode.index;
                    for (int i = currNode.routeCost; i > 0; i--)
                    {
                        currNode      = currNode.predecessor;
                        result[i - 1] = currNode.index;
                    }
                    if (reverseSearch)
                    {
                        ReverseRoute(result);
                    }
                    CleanUpQueueCache();
                    return(currRouteCost, result);
                }

                int heuristicCost;
                int neighborRouteCost = currNode.routeCost + 1;
                int targetOffsetTime  = 0;

                // Stay at node for another time step, if not constrained
                //TODO: Only before a blocked vertex?
                if (constraints != null)
                {
                    targetOffsetTime = reverseSearch == false ? beginTime + neighborRouteCost : beginTime - neighborRouteCost;
                    if (constraints.ContainsKey(targetOffsetTime))
                    {
                        foreach (var constraint in constraints[targetOffsetTime])
                        {
                            if (constraint == currNode.index)
                            {
                                goto Neighbors;
                            }
                        }
                    }
                    heuristicCost = neighborRouteCost + distancesCache[currNode.index][y];
                    EnqueueNode(currNode.index, neighborRouteCost, heuristicCost, currNode);
                }

Neighbors:
                // Add all neighbors into queue, if edge is not constrained.
                foreach (var neighbor in vertices[currNode.index].edges)
                {
                    int neighborIdx = neighbor.x == currNode.index ? neighbor.y : neighbor.x;

                    // No return edges.
                    if (currNode.predecessor != null)
                    {
                        if (neighborIdx == currNode.predecessor.index)
                        {
                            continue;
                        }
                        else if (currNode.predecessor.index == currNode.index)
                        {
                            var tmp = currNode.predecessor;
                            while (tmp.predecessor != null && tmp.index == currNode.index)
                            {
                                tmp = tmp.predecessor;
                            }
                            if (tmp.index == neighborIdx)
                            {
                                continue;
                            }
                        }
                    }

                    heuristicCost = neighborRouteCost + distancesCache[neighborIdx][y];

                    // Check if constraints are not violated.
                    if (constraints != null && constraints.ContainsKey(targetOffsetTime))
                    {
                        foreach (var constrainedVertexIdx in constraints[targetOffsetTime])
                        {
                            if (constrainedVertexIdx == neighborIdx)
                            {
                                goto SkipEnqueue;
                            }
                        }
                    }
                    EnqueueNode(neighborIdx, neighborRouteCost, heuristicCost, currNode);
SkipEnqueue:
                    ;
                }
            }
            throw new ArgumentException("Shortest path not found, check the arguments.");

            void EnqueueNode(int nodeIndex, int routeCost, int heuristicCost, AStarNode prevNode)
            {
                AStarNode nextNode = queueCacheA[nodeIndex];

                // newCost invariants - route with longer optimal length will always have higher newCost
                //                    - of routes with the same optimal cost the one furthest from beginnig is preferred
                float newCost = (heuristicCost << 10) - routeCost;

                if (nextNode != null)                 // update value if better cost and node is not requeued already
                {
                    if (nextNode.routeCost > routeCost && nextNode.index != nextNode.predecessor.index)
                    {
                        nextNode.routeCost   = routeCost;
                        nextNode.predecessor = prevNode;
                        queue.UpdatePriority(nextNode, newCost);
                    }
                }
                else                                  // first visiting the vertex or requeue the current vertex
                {
                    nextNode = nodeFactory.GetNode(nodeIndex, routeCost, prevNode);
                    queueCacheA[nodeIndex] = nextNode;
                    queue.Enqueue(nextNode, newCost);
                }
            }

            void CleanUpQueueCache()
            {
                queue.Clear();
                Array.Copy(emptyArr, queueCacheA, queueCacheA.Length);
                nodeFactory.ResetIndex();
            }