Ticket #1942: short-range_otp.patch

File short-range_otp.patch, 5.7 KB (added by wraitii, 8 years ago)
  • source/simulation2/helpers/PriorityQueue.h

     
    3434{
    3535    bool operator()(const Item& a, const Item& b) const
    3636    {
     37        if (!b.secondPass && a.secondPass) // return to already opened ones last
     38            return true;
     39        if (!a.secondPass && b.secondPass)
     40            return false;
    3741        if (CMP()(b.rank, a.rank)) // higher costs are lower priority
    3842            return true;
    3943        if (CMP()(a.rank, b.rank))
     
    6973        ID id;
    7074        R rank; // f = g+h (estimated total cost of path through here)
    7175        H h; // heuristic cost
     76        bool secondPass;
    7277    };
    7378
    7479    void push(const Item& item)
  • source/simulation2/components/CCmpPathfinder_Vertex.cpp

     
    9090        UNEXPLORED,
    9191        OPEN,
    9292        CLOSED,
     93        UNDERSTUDY,
    9394    };
    9495
    9596    CFixedVector2D p;
     
    795796    PROFILE_START("Short pathfinding - A*");
    796797
    797798    VertexPriorityQueue open;
    798     VertexPriorityQueue::Item qiStart = { START_VERTEX_ID, start.h, start.h };
     799    VertexPriorityQueue::Item qiStart = { START_VERTEX_ID, start.h, start.h, false };
    799800    open.push(qiStart);
    800801
    801802    u16 idBest = START_VERTEX_ID;
    802803    fixed hBest = start.h;
    803804
     805    fixed maxDistFirstPass = entity_pos_t::FromInt(15);
     806    bool hadASecondPass = false;
     807    static u64 totalExam = 0;
     808   
    804809    while (!open.empty())
    805810    {
    806811        // Move best tile from open to closed
    807812        VertexPriorityQueue::Item curr = open.pop();
     813        // If this is the second pass we need to remember it and we'll be closed at the end of this loop.
     814        bool secondPass = (vertexes[curr.id].status == Vertex::UNDERSTUDY);
    808815        vertexes[curr.id].status = Vertex::CLOSED;
     816        if (secondPass)
     817            hadASecondPass = true;
    809818
    810819        // If we've reached the destination, stop
    811820        if (curr.id == GOAL_VERTEX_ID)
     
    828837        // Check the lines to every other vertex
    829838        for (size_t n = 0; n < vertexes.size(); ++n)
    830839        {
    831             if (vertexes[n].status == Vertex::CLOSED)
     840            if (vertexes[n].status == Vertex::CLOSED || vertexes[n].status == Vertex::UNDERSTUDY)
    832841                continue;
    833842
    834843            // If this is the magical goal vertex, move it to near the current vertex
     
    866875                }
    867876            }
    868877
     878            fixed distFromN = (vertexes[curr.id].p - npos).Length();
     879            fixed g = vertexes[curr.id].g + distFromN;
     880           
     881            // Try and be clever based on distance to not check visibility to unwanted points.
     882            // We do not study points we know that wouldn't improve our path anyway
     883            // This first optimization does not change the algorithm itself.
     884            // The second optimization assumes we won't be stuck in a unit-made U-shaped dead-end
     885            // And tries to consider only potentially interesting vertices.
     886            // Those are those closer to the goal than us, and those not too far away
     887            // However sometimes we have to backtrack, usually the overall behavior is either
     888            // much better or about equivalent.
     889            if(g >= vertexes[n].g && vertexes[n].status != Vertex::UNEXPLORED)
     890                continue;
     891           
     892            fixed h =  goal.DistanceToPoint(npos);
     893            if (!hadASecondPass && (h > (hBest + entity_pos_t::FromInt(4)) || distFromN > maxDistFirstPass))
     894            {
     895                if (vertexes[curr.id].status != Vertex::UNDERSTUDY)
     896                {
     897                    // add us back to the list for a second pass if necessary.
     898                    VertexPriorityQueue::Item newMe = curr;
     899                    newMe.secondPass = true;
     900                    open.push(newMe);
     901                    vertexes[curr.id].status = Vertex::UNDERSTUDY;
     902                }
     903                continue;
     904            }
     905           
     906            ++totalExam;
     907
    869908            bool visible =
    870909                CheckVisibilityLeft(vertexes[curr.id].p, npos, edgesLeft) &&
    871910                CheckVisibilityRight(vertexes[curr.id].p, npos, edgesRight) &&
     
    883922            xz.push_back(npos.X.ToFloat());
    884923            xz.push_back(npos.Y.ToFloat());
    885924            SimRender::ConstructLineOnGround(GetSimContext(), xz, m_DebugOverlayShortPathLines.back(), false);
    886             //*/
     925             }//*/
    887926
    888927            if (visible)
    889928            {
    890                 fixed g = vertexes[curr.id].g + (vertexes[curr.id].p - npos).Length();
    891 
    892929                // If this is a new tile, compute the heuristic distance
    893930                if (vertexes[n].status == Vertex::UNEXPLORED)
    894931                {
     
    895932                    // Add it to the open list:
    896933                    vertexes[n].status = Vertex::OPEN;
    897934                    vertexes[n].g = g;
    898                     vertexes[n].h = goal.DistanceToPoint(npos);
     935                    vertexes[n].h = h;
    899936                    vertexes[n].pred = curr.id;
    900937
    901938                    // If this is an axis-aligned shape, the path must continue in the same quadrant
     
    908945                    if (n == GOAL_VERTEX_ID)
    909946                        vertexes[n].p = npos; // remember the new best goal position
    910947
    911                     VertexPriorityQueue::Item t = { (u16)n, g + vertexes[n].h, vertexes[n].h };
     948                    VertexPriorityQueue::Item t = { (u16)n, g + vertexes[n].h, vertexes[n].h, false };
    912949                    open.push(t);
    913950
    914951                    // Remember the heuristically best vertex we've seen so far, in case we never actually reach the target
     
    920957                }
    921958                else // must be OPEN
    922959                {
    923                     // If we've already seen this tile, and the new path to this tile does not have a
    924                     // better cost, then stop now
    925                     if (g >= vertexes[n].g)
    926                         continue;
    927960
    928                     // Otherwise, we have a better path, so replace the old one with the new cost/parent
     961                    // Since this new tile is a better path, replace the old one with the new cost/parent
    929962                    fixed gprev = vertexes[n].g;
    930963                    vertexes[n].g = g;
    931964                    vertexes[n].pred = curr.id;
     
    944977        }
    945978    }
    946979
     980    std::cout << totalExam << std::endl;
    947981    // Reconstruct the path (in reverse)
    948982    for (u16 id = idBest; id != START_VERTEX_ID; id = vertexes[id].pred)
    949983        path.m_Waypoints.emplace_back(Waypoint{ vertexes[id].p.X, vertexes[id].p.Y });