A* bug(A星搜索算法)
我已经开始学习算法和软件开发,作为一个小型自我评估项目,我决定用 C++ 编写 A* 搜索算法。它使用 Qt 和 OpenGL 来实现视觉部分(但这并不重要)。
主要使用这个来源: A* 初学者寻路< /a>
我写了一个小应用程序,但是我发现了一个无法修复的错误。似乎由于某种原因,靠近墙壁的节点的父节点被设置为墙壁。(?)并且由于我存储信息的方式,墙壁的父节点被设置为起点(?)。
我使用了 stateMatrix[][],其中
1 = entrance green;
2 = exit;
3 = wall and;
4 = path;
我还使用矩阵来表示 openNodes 和 closeNodes。 closeNodes 矩阵是 bool 矩阵 openNode 矩阵还存储一些信息:
指令是:
openNodes[100][100][6];
0 - bool open or closed
1 - F
2 - G
3 - H
4 - parentX
5 - parentY
我知道有更好的方法来编码,但我还没有学习本课;)
这是 astar 文件的代码:
#include <math.h>
#include "apath.h"
aPath::aPath()
{
gridSize = 100;
int i, j, k;
for(i = 0; i < gridSize; i++)
for(j = 0; j < gridSize; j++)
{
stateMatrix[i][j] = 0;
for(int k = 0; k < 6; k++) openNodes[i][j][k] = 0;
closedNodes[i][j] = 0;
}
targetX = targetY =
openX = openY = entranceX = entranceY = 0;
}
void aPath::start()
{
bool testOK = false;
int G = 0;
openNodes[entranceX][entranceY][0] = 1;
openNodes[entranceX][entranceY][2] = 14;
openNodes[entranceX][entranceY][3] = euclidean(entranceX,
entranceY);
openNodes[entranceX][entranceY][1] =
openNodes[entranceX][entranceY][2] +
openNodes[entranceX][entranceY][3];
openNodes[entranceX][entranceY][4] = entranceX;
openNodes[entranceX][entranceY][5] = entranceY;
int i, j, x, y;
while(closedNodes[targetX][targetY] == 0)
{
searchLessOpen();
closedNodes[openX][openY] = 1;
openNodes[openX][openY][0] = 0;
//Check the 8 squares around
for(i = openX - 1; i <= openX + 1; i++)
for(j = openY - 1; j <= openY + 1; j++)
{
//check if the square is in the limits,
//is not a wall and is not in the closed list
if((i >= 0) && (j >= 0) &&
(i < gridSize) && (j < gridSize) &&
(stateMatrix[i][j] != 3) &&
(closedNodes[i][j] == 0))
{
//G calculus. If it is in the edge it costs more
x = i - openX + 1;
y = j - openY + 1;
if((x == 0 && y == 0) ||
(x == 0 && y == 2) ||
(x == 2 && y == 0) ||
(x == 2 && y == 2))
{
G = 14;
}
else G = 10;
//check if node is already open
if(openNodes[i][j][0] == 0)
{
openNodes[i][j][0] = 1;
openNodes[i][j][2] = G;
openNodes[i][j][3] = euclidean(i,j);
openNodes[i][j][1] = openNodes[i][j][2] + openNodes[i][j][3];
openNodes[i][j][4] = openX;
openNodes[i][j][5] = openY;
}
else //if node is open, check if this path is better
{
if(G < openNodes[i][j][2])
{
openNodes[i][j][2] = G;
openNodes[i][j][1] = openNodes[i][j][2] + openNodes[i][j][3];
openNodes[i][j][4] = openX;
openNodes[i][j][5] = openY;
}
}
}
}
}
reconstruct();
}
void aPath::reconstruct()
{
bool test = false;
int x = openNodes[targetX][targetY][4];
int y = openNodes[targetX][targetY][5];
do
{
stateMatrix[x][y] = 4;
x = openNodes[x][y][4];
y = openNodes[x][y][5];
if(x == entranceX && y == entranceY) test = true;
} while(test == false);
}
int aPath::euclidean(int currentX, int currentY)
{
int dx = targetX - currentX;
int dy = targetY - currentY;
return 10*sqrt((dx*dx)+(dy*dy));
}
void aPath::searchLessOpen()
{
int F = 1000000;
int i, j;
for(i = 0; i < gridSize; i++)
for(j = 0; j < gridSize; j++)
{
if(openNodes[i][j][0] == 1)
{
if(openNodes[i][j][1] <= F)
{
F = openNodes[i][j][1];
openX = i;
openY = j;
}
}
}
}
openNodes 有人知道我做错了什么吗?
谢谢。 编辑:这里有一些图片:
I have started to study algorithms and software development and, as a small self evaluation project I have decided to write the A* search algorithm in C++. It uses Qt and OpenGL for the visual part (but that is not important).
Using mostly this source:
A* Pathfinding for Beginners
I have write a small app, however I am have found a bug that I cant fix. It appears that for some reason the parent of a node close to the wall is set to the wall.(?) And the parent of the wall is set to the the start point(?) because of the way I am storing the info.
I have used a stateMatrix[][] where
1 = entrance green;
2 = exit;
3 = wall and;
4 = path;
I have also used matrix to represent openNodes and closedNode. The closedNodes matrix is bool matrix the openNode matrix also stores some info:
The openNodes instructions are:
openNodes[100][100][6];
0 - bool open or closed
1 - F
2 - G
3 - H
4 - parentX
5 - parentY
I know that there are better ways to code this but I have not yet got to this lesson ;)
Here is the code of the astar file:
#include <math.h>
#include "apath.h"
aPath::aPath()
{
gridSize = 100;
int i, j, k;
for(i = 0; i < gridSize; i++)
for(j = 0; j < gridSize; j++)
{
stateMatrix[i][j] = 0;
for(int k = 0; k < 6; k++) openNodes[i][j][k] = 0;
closedNodes[i][j] = 0;
}
targetX = targetY =
openX = openY = entranceX = entranceY = 0;
}
void aPath::start()
{
bool testOK = false;
int G = 0;
openNodes[entranceX][entranceY][0] = 1;
openNodes[entranceX][entranceY][2] = 14;
openNodes[entranceX][entranceY][3] = euclidean(entranceX,
entranceY);
openNodes[entranceX][entranceY][1] =
openNodes[entranceX][entranceY][2] +
openNodes[entranceX][entranceY][3];
openNodes[entranceX][entranceY][4] = entranceX;
openNodes[entranceX][entranceY][5] = entranceY;
int i, j, x, y;
while(closedNodes[targetX][targetY] == 0)
{
searchLessOpen();
closedNodes[openX][openY] = 1;
openNodes[openX][openY][0] = 0;
//Check the 8 squares around
for(i = openX - 1; i <= openX + 1; i++)
for(j = openY - 1; j <= openY + 1; j++)
{
//check if the square is in the limits,
//is not a wall and is not in the closed list
if((i >= 0) && (j >= 0) &&
(i < gridSize) && (j < gridSize) &&
(stateMatrix[i][j] != 3) &&
(closedNodes[i][j] == 0))
{
//G calculus. If it is in the edge it costs more
x = i - openX + 1;
y = j - openY + 1;
if((x == 0 && y == 0) ||
(x == 0 && y == 2) ||
(x == 2 && y == 0) ||
(x == 2 && y == 2))
{
G = 14;
}
else G = 10;
//check if node is already open
if(openNodes[i][j][0] == 0)
{
openNodes[i][j][0] = 1;
openNodes[i][j][2] = G;
openNodes[i][j][3] = euclidean(i,j);
openNodes[i][j][1] = openNodes[i][j][2] + openNodes[i][j][3];
openNodes[i][j][4] = openX;
openNodes[i][j][5] = openY;
}
else //if node is open, check if this path is better
{
if(G < openNodes[i][j][2])
{
openNodes[i][j][2] = G;
openNodes[i][j][1] = openNodes[i][j][2] + openNodes[i][j][3];
openNodes[i][j][4] = openX;
openNodes[i][j][5] = openY;
}
}
}
}
}
reconstruct();
}
void aPath::reconstruct()
{
bool test = false;
int x = openNodes[targetX][targetY][4];
int y = openNodes[targetX][targetY][5];
do
{
stateMatrix[x][y] = 4;
x = openNodes[x][y][4];
y = openNodes[x][y][5];
if(x == entranceX && y == entranceY) test = true;
} while(test == false);
}
int aPath::euclidean(int currentX, int currentY)
{
int dx = targetX - currentX;
int dy = targetY - currentY;
return 10*sqrt((dx*dx)+(dy*dy));
}
void aPath::searchLessOpen()
{
int F = 1000000;
int i, j;
for(i = 0; i < gridSize; i++)
for(j = 0; j < gridSize; j++)
{
if(openNodes[i][j][0] == 1)
{
if(openNodes[i][j][1] <= F)
{
F = openNodes[i][j][1];
openX = i;
openY = j;
}
}
}
}
Does anyone know what I am doing wrong?
Thanks.
Edit: Here are some pictures:
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
在
aPath::start()
中,您有:为什么下标
[1]
没有值?为什么要给下标[3]
分配两个不同的值?另外,说实话,entranceX
和entranceY
名称对于他们正在执行的工作来说太长了;它们使代码的可读性较差(尽管我确信您被告知要使用有意义的名称)。对于这些数组索引,我可能只使用x
和y
。在代码中:
我可能会确保
i
和j
都不会采用以下代码的无效值:我不确定您是否需要显式检查以下情况:
i == openX && j == openY
(当前单元格);它不是当前单元格周围的 8 个单元格之一(因为它是当前单元格),但其他条件可能已经解决了这个问题。如果没有:我注意到我们没有
openX
和openY
或许多其他非局部变量的定义。这使得很难确定它们是类成员变量还是某种全局变量。我们也看不到它们是如何初始化的,也看不到它们所代表的内容的文档。最可能的麻烦来源
在
aPath::SearchLessOpen()
中,您有:您在描述中指出,最后一个位置
openNodes
上的下标范围超过 0..5 ;但是,您的代码正在访问下标 6 和 7。这很容易导致您所描述的那种混乱 - 您正在访问越界数据。我认为这很容易成为你麻烦的根源。当您访问 openNodes[i][j][6] 时,这在技术上是未定义的行为,但最可能的结果是它读取的数据与您编写 openNodes 时相同的数据[i][j+1][0](当j < gridsize - 1
时)。同样,openNodes[i][j][7]
相当于访问openNodes[i][j+1][1]
,但有相同的注意事项。In
aPath::start()
, you have:Why is there no value for subscript
[1]
? And why do you assign two different values to subscript[3]
? Also, to be honest, theentranceX
andentranceY
names are too long for the job they're doing; they make the code less readable (though I'm sure you were told to use good meaningful names). For these array indexes, I'd probably use justx
andy
.At the code:
I would probably ensure that neither
i
norj
took on invalid values with code such as:I am not sure whether you need to explicitly check for the case where
i == openX && j == openY
(the current cell); it is not one of the 8 cells around the current cell (because it is the current cell), but the other conditions may already deal with that. If not:I note that we have no definitions of
openX
andopenY
or a number of other non-local variables. This makes it hard to work out whether they are class member variables or global variables of some sort. We also can't see how they're initialized, nor the documentation on what they represent.Most plausible source of trouble
In
aPath::SearchLessOpen()
, you have:You indicated in your description that the subscripts on
openNodes
in the last place ranged over 0..5; your code, though, is accessing subscripts 6 and 7. This could easily lead to the sort of confusion you describe - you are accessing data out of bounds. I think this might easily be the root of your trouble. When you accessopenNodes[i][j][6]
, this is technically undefined behaviour, but the most likely result is that it is reading the same data as if you'd writtenopenNodes[i][j+1][0]
(whenj < gridsize - 1
). Similarly,openNodes[i][j][7]
is equivalent to accessingopenNodes[i][j+1][1]
, with the same caveats.