在C ++中应用寻路算法(塔防)

时间:2013-01-12 22:02:01

标签: c++ path-finding flood-fill

我实现了泛洪填充算法,该算法将数组[15 * 15]与路径一起使用,并生成他在填充路径时所采取的步骤队列。 tl; dr看起来像这样

std::queue <int> f_path;

void Enemy::find_path(int *map, int *grid, int node) {

    if (grid[node] == 1) // colored-grid
        return;
    if (map[node] == 0) // grid with defined map (0 - no path, 1 path)
        return;

    f_path.push(node);
    grid[node] = 1;

    if ((node + 1) % 15 != 0) this->find_path(map, grid, node + 1); // go right
    if (node % 15 != 0) this->find_path(map, grid, node - 1); // go left
    if (node - 15 > 0) this->find_path(map, grid, node - 15); // go up
    if (node + 15 < 15*15) this->find_path(map, grid, node + 15); // go down
}

但是现在我有一个填充网格所需的步骤队列,但是我不知道如何将这些信息应用于我的对象以跟随并从头到尾获取。我的意思是,一条路径很简单,但如果它像这样分裂(9是退出):
0 0 1 0 0
0 1 1 1 0
0 1 0 1 0
0 1 1 1 0
0 0 9 0 0
我将左右两个路径都排在队列中,所以如果我做一个简单的go(f_path.front())它会让上帝知道什么。我如何过滤它,所以它只是退出然后停止?我无法绕过它。

3 个答案:

答案 0 :(得分:3)

我不知道算法的确切内部结构,但您可以通过将每个节点与当前路径请求的起始节点的最小距离相关联,轻松获得到达目的地的最短路径。

这样,只要你找到另一条从同一个单元格传来的路径,如果距离低于存储距离,则此路径优于上一条,否则你可以忽略它并跳到下一条路径。

通过这种方式,您最终可以拥有多条到达目标的路径,但它们都具有相同的长度(因此您可以选择其中一条)。到达目标节点后,您可以回溯:对于距离 x 的每个节点,从目标搜索开始,距离 x-1 的邻居。

只是为了让你了解我的意思:

enter image description here

请注意,这不是最快的解决方案,它只适用于小型瓷砖地图,对于较大的地图,您需要比breadth first search更好的算法。

答案 1 :(得分:2)

Deith,我会说你走在正确的轨道上!

现在你的代码将简单地遍历所有内容而无处可去。你忘记了几件事。
首先,Enemy::find_path必须返回一个布尔值:它是否到达目的地。所以,在顶部你有

if (grid[node] == 1) // colored-grid
    return;
if (map[node] == 0) // grid with defined map (0 - no path, 1 path)
    return;

我注意到第一个是阻止它自行回溯。
第二个很清楚:它撞到墙上。因此,在return false之后显示它已达到死胡同。但是你需要第三个,所以,如果它到达目的地,它将返回真。

然后,当您调用四向迭代时,请测试它们是否返回true。如果他们在达到目标后再次进行return true,那么搜索,查找并压缩回来源了!

请注意拉回源头部分,因为这是你可以使用的部分。现在你的队列将填满随处可见的垃圾。它走错了之后就不会空了。但是,拉链部分是完美的 - 而不是队列,使用堆栈,一旦到达目的地,在拉回到堆栈时推送每个节点,从而提供从头到尾的完整路径!

希望我能提供帮助; - )

编辑:好的,所以我必须提到一个更重要的事情:工作,但路径效率低。
你的算法找到一个路径,但是并不总是最短的路径 - 实际上有时它甚至会找到非常长的路径。幸运的是,解决这个问题有点简单。首先,您需要拥有目的地的坐标。然后,在find_path函数的每次迭代中,重新排序方向迭代器。首先你选择正确,然后向左,然后向上,然后向下。相反,看看朝向目标方向的方向。然后检查那个方向。如果失败,请尝试下一个最接近的。如果失败了,那就试试下一个最近的,下一个最近的(好吧,现在是最远的)。
是的,我知道这不会是最短的距离,因为它通常倾向于墙壁拥抱,但它肯定比完全随机的方向更好。

答案 2 :(得分:0)

在最终网格上进行深度优先搜索(dfs)。

http://en.wikipedia.org/wiki/Depth-first_search

您将获得个人路径。如果你想选择最短的,你可以做的优化很少。

  • 保持最大限制,如果dfs看起来更远,则跳过该路径。
  • 如果找到长度小于最大限制的路径。将max-limit设置为。

希望这会有所帮助。

编辑:我写了这段代码,它应该适合你。它将给出最短路径,在矢量&lt;对&gt;作为x,y坐标。

#include <iostream>
#include <fstream>
#include <vector>
#include <cstring>

using namespace std;

ifstream fin("map.txt");

int width, height;
int map[10][10];
// Start (x,y), End (x,y)
int sy, sx, ey, ex;

bool visited[10][10];

vector<pair<int, int> > final_path;
int max_size = 9999;

void getInput() {
  fin >> width >>  height;

  for (int i = 0; i < height; i++) {
    for (int j = 0; j < width; j++) {
        int x;
        fin >> x;
        map[i][j] = x; 

        if(x == 8){
          sy = i;
          sx = j;
        }

        if(x == 9){
          ey = i;
          ex = j;
        }
    }
  }
}

void dfs(int x, int y, vector<pair<int, int> > path) {
  if(path.size() > max_size){
    cout << "Returning : path size too big" << endl;
    return;
  }

  if(x < 0 || x >= width || y < 0 || y >= height){
    cout << "Returning : bounds" << endl;
    return;
  }

  // If the tile is blocked, can't go there
  if(map[y][x] == 0){
    cout << "Returning : blocked" << endl;
    return;
  }

  if(visited[y][x]){
    cout << "Returning : visited" << endl;
    return;
  }

  // We don't want to revisit a tile
  visited[y][x] = true;

  cout << "Visiting " << x << " " << y << endl;

  path.push_back(make_pair(x, y));
  if(map[y][x] == 9) {
    final_path = path;
    visited[y][x] = false;
    return;
  }

  dfs(x, y - 1, path);
  dfs(x + 1, y, path);
  dfs(x, y + 1, path);
  dfs(x - 1, y, path);

  visited[y][x] = false;

  return;
}

int main() {

  getInput();
  cout << "Got Input" << endl;
  cout << width << " " << height << endl;

  memset(visited, 0, sizeof(visited));
  vector<pair<int, int> > starting_path;

  cout << sx << " " << sy << endl;

  dfs(sx, sy, starting_path);

  cout << "Path size is " << final_path.size() << endl;

  for(int i = 0; i < final_path.size(); i++){
    cout << final_path[i].first << " " << final_path[i].second << endl;
  }

  return 0;
}

map.txt包含您在问题中提供的地图。