поиск пути — Применение алгоритма поиска пути (Tower Defense) в переполнении стека

Я реализовал алгоритм заливки, который берет массив [15 * 15] с путем и генерирует очередь шагов, которые он сделал, заполняя путь. тл; др это выглядит так

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
У меня будет и левый, и правый путь в очереди, так что, если я сделаю простой переход (f_path.front ()), он поймет, что Бог знает. Как мне его отфильтровать, чтобы он только выходил, а потом останавливался? Я не могу обернуть голову вокруг этого.

4

Решение

Дейт, скажу, ты на правильном пути!

Прямо сейчас ваш код будет просто перебирать все и никуда не денется. Вы забыли пару вещей.
Первый, 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 снова, так как цель была достигнута, таким образом, поиск, поиск и отправка обратно к источнику!

Обратите внимание, что обратно к источнику часть, потому что это часть, которую вы можете использовать. Прямо сейчас ваша очередь заполнится случайным мусором, идущим повсюду. Он не опустошается после того, как идет неправильным путем. Тем не менее, эта часть zip-back идеальна — вместо очереди используйте стек и, как только вы достигнете места назначения, проталкивайте каждый узел при возврате в стек, таким образом обеспечивая полный путь от начала до конца!

Надеюсь, я мог помочь 😉

РЕДАКТИРОВАТЬ: Хорошо, поэтому я должен упомянуть еще одну важную вещь: рабочие, но неэффективные пути.
Ваш алгоритм будут находить путь, но не всегда самый короткий путь — на самом деле иногда он даже найдет очень долго дорожка. К счастью, исправить это несколько просто. Вы должны сначала получить координату пункта назначения. Затем на каждой итерации find_path функция, изменить порядок ваших итераторов направления. Сначала вы выбираете направо, затем налево, затем вверх, затем вниз. Вместо этого посмотрите, какое направление пойдет в направлении цели. Затем проверьте это направление. Если это не удается, попробуйте следующий ближайший. Если это не помогло, попробуйте следующий ближайший и следующий ближайший (ну, теперь самый дальний).

Да я знаю это не будет самый короткий расстояние, так как оно обычно стремится к объятию стен, но это определенно лучше, чем идти в совершенно случайных направлениях.

2

Другие решения

Я не знаю точных внутренних элементов вашего алгоритма, но вы можете легко получить кратчайший путь к месту назначения, сопоставив каждому узлу минимальное расстояние от начального узла, найденного для текущего запроса пути.

Таким образом, всякий раз, когда вы находите другой путь, который проходит из той же ячейки, если расстояние меньше сохраненного, тогда этот путь лучше предыдущего, в противном случае вы можете проигнорировать его и перейти к следующему.

Таким образом, вы можете получить более одного пути, который достигает цели, но все они имеют одинаковую длину (таким образом, вы можете просто выбрать один из них). Достигнув узла цели, вы можете вернуться назад: для каждого узла на расстоянии Икс начиная с цели поиска соседа на расстоянии х-1.

Просто чтобы дать вам графическое представление о том, что я имею в виду:

введите описание изображения здесь

Имейте в виду, что это не самое быстрое решение, и оно подойдет только для небольших мозаичных карт, для более крупных вам потребуются более качественные алгоритмы, чем поиск в ширину.

3

Выполните поиск в глубину (dfs) по окончательной сетке, которую вы получите.

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

Вы получите индивидуальные пути. Если вы хотите выбрать самый короткий, есть несколько вариантов оптимизации, которые вы можете сделать.

  • Сохраняйте максимальный лимит, если dfs смотрит дальше, пропустите этот путь.
  • Если вы найдете путь длиной меньше максимального предела. Установите максимальный предел для этого.

Надеюсь, это поможет.

РЕДАКТИРОВАТЬ: Я написал этот код, и он должен работать для вас. Это даст кратчайший путь, в векторе< pair> как координаты 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 содержит карту, которую вы дали в вопросе.

0
По вопросам рекламы [email protected]