【问题标题】:path-finding (in a grid) with The Boost Graph Library使用 Boost Graph Library 进行路径查找(在网格中)
【发布时间】:2011-10-23 16:07:59
【问题描述】:

我正在将我的 Google AI Challenge 机器人从 Python 重写为 C++,我想使用 boost 的图形库来处理路径查找,而不是像以前在 Python 中那样滚动我自己的图形和搜索代码.

地图是一个简单的方形网格,围绕着边缘。

我之前没有使用过 boost 或 C++(我确实非常了解 C),而且我发现 boost 图形文档真的很难理解,所以我需要一点帮助。

我遇到问题的具体文档:

这是一个运行 python 代码的 sn-p:

def do_turn(self, ants):
    # update path-finding graph
    for row in range(ants.rows):
        for col in range(ants.cols):
            key = (row, col)
            self.graph[key] = []

            def append_if_unoccupied(coord):
                if ants.passable(coord) and coord not in ants.my_hills():
                    self.graph[key].append(coord)

            if row - 1 >= 0:
                append_if_unoccupied((row - 1, col))
            else:
                append_if_unoccupied((ants.rows + (row - 1), col))

            if col - 1 >= 0:
                append_if_unoccupied((row, col - 1))
            else:
                append_if_unoccupied((row, ants.cols + (col - 1)))

            if row + 1 < ants.rows:
                append_if_unoccupied((row + 1, col))
            else:
                append_if_unoccupied((row + 1 - ants.rows, col))

            if col + 1 < ants.cols:
                append_if_unoccupied((row, col + 1))
            else:
                append_if_unoccupied((row, col + 1 - ants.cols))

然后我稍后使用shortest_path(self.graph, loc, dest)(使用曼哈顿启发式搜索)来获取包含到其他地方的最短路径的列表。在 C++ 中,我想要类似的东西(具有最短路径的向量)。这是我到目前为止的代码(我只需要帮助让它在没有任何障碍的基本网格上工作,我可以做剩下的):

#include <vector>

#include <boost/config.hpp>
#include <boost/graph/graph_traits.hpp>
#include <boost/graph/adjacency_list.hpp>
//#include <boost/graph/astar_search.hpp>
#include <boost/graph/dijkstra_shortest_paths.hpp>

// struct with .row and .col
#include "Location.h"

// might not be necessary
struct Edge {};

typedef boost::adjacency_list<
    boost::listS,       // container for edges
    boost::vecS,        // container for vertices
    boost::undirectedS, // directed or undirected edges
    Location,           // vertex type
    Edge                // edge type
> Graph;

typedef Graph::vertex_descriptor VertexID;
typedef Graph::edge_descriptor   EdgeID;

const int rows = 100;
const int cols = 100;

int main() {
    Graph graph;

    // this is probably useless since the graph stores everything
    // haven't looked for a way around it yet
    std::vector<std::vector<VertexID>> grid;

    // create the grid/graph
    for (int row = 0; row < rows; row++) {
        grid.resize(rows);
        for (int col = 0; col < cols; col++) {
            grid[row].resize(cols);

            VertexID vID = boost::add_vertex(graph);
            graph[vID].row = row;
            graph[vID].col = col;

            grid[row][col] = vID;
        }
    }

    // add the edges
    for (int row = 0; row < rows; row++) {
        for (int col = 0; col < cols; col++) {
            // add edges for the squares in the grid (it wraps around)
            // right now all the squares are traversable but that won't always
            // be the case
            int c_row, c_col;

            if (row - 1 >= 0) {
                c_row = row - 1;
                c_col = col;
            } else {
                c_row = rows + (row - 1);
                c_col = col;
            }
            boost::add_edge(grid[c_row][c_col], grid[row][col], graph);

            if (col - 1 >= 0) {
                c_row = row;
                c_col = col - 1;
            } else {
                c_row = row;
                c_col = cols + (col - 1);
            }
            boost::add_edge(grid[c_row][c_col], grid[row][col], graph);

            if (row + 1 < rows) {
                 c_row = row + 1;
                 c_col = col;
            } else {
                c_row = row + 1 - rows;
                c_col = col;
            }
            boost::add_edge(grid[c_row][c_col], grid[row][col], graph);

            if (col + 1 < cols) {
                c_row = row;
                c_col = col + 1;
            } else {
                c_row = row;
                c_col = col + 1 - cols;
            }
            boost::add_edge(grid[c_row][c_col], grid[row][col], graph);
        }
        // having trouble figuring out use these
        //boost::astar_search(graph, grid[c]
        //auto indexmap = get(vertex_index, graph);
        //dijkstra_shortest_paths(graph, grid[0][0], &p[0], &d[0], weightmap, indexmap, 
                          //std::less<int>(), closed_plus<int>(), 
                          //(std::numeric_limits<int>::max)(), 0,
                          //default_dijkstra_visitor());
    }
    return 0;
}

【问题讨论】:

    标签: c++ boost graph path-finding boost-graph


    【解决方案1】:

    应该有帮助:

        boost::astar_search
        (
            m_navmesh, start,
            distance_heuristic(m_navmesh, goal),
            boost::predecessor_map(&p[0])
            .distance_map(&d[0])
            .visitor(astar_goal_visitor(goal))
            .weight_map(get(&NavMeshConnection::dist, m_navmesh))
        );
    

    这个函数需要一个距离启发式,这是一个你必须自己创建的仿函数:

    // euclidean distance heuristic
    class distance_heuristic : public boost::astar_heuristic <NavMeshGraph, float> {
    public:
        distance_heuristic(const NavMeshGraph & l, TriangleDescriptor goal)
        : m_graph(l), m_goal(goal)
        {}
    
        float operator()(TriangleDescriptor u) {
            const NavMeshTriangle & U = m_graph[u];
            const NavMeshTriangle & V = m_graph[m_goal];
            float dx = U.pos.x - V.pos.x;
            float dy = U.pos.y - V.pos.y;
            return ::sqrt(dx * dx + dy * dy);
        }
    
    private:
        const NavMeshGraph & m_graph;
        TriangleDescriptor m_goal;
    };
    

    你还需要一个访客:

    // visitor that terminates when we find the goal
    class astar_goal_visitor : public boost::default_astar_visitor {
    public:
        astar_goal_visitor(TriangleDescriptor goal) : m_goal(goal)
        {}
    
        void examine_vertex(TriangleDescriptor u, const NavMeshGraph & g)
        {
            if (u == m_goal)
                throw found_goal();
        }
    
    private:
        TriangleDescriptor m_goal;
    };
    

    found_gloal 可以是一个简单的结构或更复杂的结构,具体取决于您要返回的内容:

    struct found_goal {};
    

    这样一个对象被抛出到访问者中,所以你必须将 boost::astar_search() 包装在一个 try/catch 块中:

    try {
    
        boost::astar_search
        (
          ...
         );
    
    
    } catch (found_goal fg) { // found a path to the goal
    

    然后在 catch 块中检索最好的方法:

        std::list<TriangleDescriptor> shortest_path;
        for (TriangleDescriptor v = goal;; v = p[v]) {
            shortest_path.push_front(v);
            if (p[v] == v)
                break;
        }
    

    您将需要大量适应,但至少这足以让 Boost 摆脱困境。

    顺便说一句,Djikstra 并不完全相似。它返回所有其他节点的所有可能路径。这不利于速度,但非常适合预处理:如果您的世界是静态的,您可以预先构建一个寻路矩阵,该矩阵将返回 O(1) 中的最佳下一个节点。

    【讨论】:

      【解决方案2】:

      您无需切换到 C++ 即可利用 BGL;有一个 really nicegraph_tool 的形式为 python 包装。当然包括shortest path

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-10-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-03-11
        相关资源
        最近更新 更多