【问题标题】:A* bug (A star search algorithm)A* 错误(A 星搜索算法)
【发布时间】:2011-07-26 04:43:37
【问题描述】:

我已经开始研究算法和软件开发,作为一个小型的自我评估项目,我决定用 C++ 编写 A* 搜索算法。它使用 Qt 和 OpenGL 作为视觉部分(但这并不重要)。

主要使用以下来源: A* Pathfinding for Beginners

我编写了一个小应用程序,但是我发现了一个我无法修复的错误。似乎由于某种原因,靠近墙的节点的父节点设置为墙。(?)墙的父节点设置为起点(?),因为我存储信息的方式。

我在哪里使用了 stateMatrix[][]

1 = entrance green;
2 = exit;
3 = wall and;
4 = path;

我也使用矩阵来表示 openNodes 和 closedNode。 closedNodes 矩阵是 bool 矩阵,openNode 矩阵也存储了一些信息:

openNodes 指令是:

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;
                }
            }
        }
}

有谁知道我做错了什么?

谢谢。 编辑:这里有一些图片:

【问题讨论】:

  • 代码很多。
  • 您可以通过使用数字名称使您的代码更具可读性。例如,enum State { Entrance = 1, Exit, Wall, Path };
  • 同样,openNodes 应该是一个二维结构数组,每个结构有 6 个数据成员。

标签: c++ algorithm a-star


【解决方案1】:

aPath::start(),你有:

openNodes[entranceX][entranceY][0] = 1;
openNodes[entranceX][entranceY][2] = 14;
openNodes[entranceX][entranceY][3] = euclidean(entranceX,
                                               entranceY);
openNodes[entranceX][entranceY][3] =
        openNodes[entranceX][entranceY][2] +
        openNodes[entranceX][entranceY][3];
openNodes[entranceX][entranceY][4] = entranceX;
openNodes[entranceX][entranceY][5] = entranceY;

为什么下标[1] 没有值?为什么要为下标[3] 分配两个不同的值?另外,老实说,entranceXentranceY 的名字对于他们正在做的工作来说太长了。它们使代码的可读性降低(尽管我确信您被告知要使用有意义的好名称)。对于这些数组索引,我可能只使用xy

在代码处:

    //Check the 8 squares around
    for(i = openX - 1; i <= openX + 1; i++)
        for(j = openY - 1; j <= openY + 1; j++)
        {

我可能会确保ij 都不会使用以下代码获取无效值:

    //Check the 8 squares around (openX, openY)
    int minX = max(openX - 1, 0);
    int maxX = min(openX + 1, gridsize);
    int minY = max(openY - 1, 0);
    int maxY = min(openY + 1, gridsize);
    for (i = minX; i <= maxX; i++)
        for (j = minY; j <= maxY; j++)
        {

我不确定您是否需要明确检查i == openX &amp;&amp; j == openY(当前单元格)的情况;它不是当前单元格周围的 8 个单元格之一(因为它当前单元格),但其他条件可能已经处理了这个问题。如果没有:

            if (i == openX && j == openY)
                continue;

我注意到我们没有定义 openXopenY 或许多其他非局部变量。这使得很难确定它们是类成员变量还是某种全局变量。我们也看不到它们是如何初始化的,也看不到它们代表什么的文档。

最可能的麻烦来源

aPath::SearchLessOpen(),你有:

        if(openNodes[i][j][0] == 1)
        {
            if(openNodes[i][j][6] <= F)
            {
                F = openNodes[i][j][7];

您在描述中指出,最后一位openNodes 的下标范围超过0..5;但是,您的代码正在访问下标 6 和 7。这很容易导致您描述的那种混乱——您正在访问越界的数据。我认为这可能很容易成为您麻烦的根源。当您访问openNodes[i][j][6] 时,这在技术上是未定义的行为,但最可能的结果是它读取的数据与您写入openNodes[i][j+1][0] 时相同(当j &lt; gridsize - 1 时)。同样,openNodes[i][j][7] 等同于访问openNodes[i][j+1][1],具有相同的注意事项。

【讨论】:

  • 谢谢,关于openNodes上的下标,当我复制代码时,看起来stackoverflow编辑了。我现在在第一条评论中修复了它。
  • 名字太长了,因为我一有空就写了几个月,所以我不得不使用我以后会记住的名字。我还应该添加标题以使代码更具可读性。我已经修改了零件以检查周围的 8 个方块,但我仍然遇到同样的问题。
猜你喜欢
  • 2011-08-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-22
  • 2023-03-29
  • 2012-02-06
  • 2023-03-08
相关资源
最近更新 更多