Ошибка * (алгоритм поиска по звездам) - PullRequest
3 голосов
/ 26 июля 2011

Я начал изучать алгоритмы и разработку программного обеспечения, и в качестве небольшого проекта по самооценке я решил написать алгоритм поиска A * на C ++.Он использует Qt и OpenGL для визуальной части (но это не важно).

Использование в основном этого источника: A * Pathfinding для начинающих

Я написал небольшойприложение, однако я нашел ошибку, которую не могу исправить.Похоже, что по какой-то причине родитель узла, близкого к стене, настроен на стену. (?) А родитель родительской стены установлен на начальную точку (?) Из-за способа хранения информации.

Я использовал 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;
                }
            }
        }
}

Кто-нибудь знает, что я делаю неправильно?

Спасибо.Редактировать: Вот несколько картинок:

1 Ответ

5 голосов
/ 26 июля 2011

В 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]? Кроме того, если честно, имена entranceX и entranceY слишком длинные для выполняемой ими работы; они делают код менее читабельным (хотя я уверен, что вам сказали использовать хорошие значащие имена). Для этих индексов массива я бы, вероятно, использовал бы x и y.

По коду:

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

Я бы, вероятно, убедился, что ни i, ни j не приняли недопустимые значения с кодом, таким как:

    //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 && j == openY (текущая ячейка); это не одна из 8 ячеек вокруг текущей ячейки (потому что является текущей ячейкой), но другие условия могут уже иметь дело с этим. Если нет:

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

Замечу, что у нас нет определений openX и openY или ряда других нелокальных переменных. Это затрудняет определение того, являются ли они переменными-членами класса или какими-то глобальными переменными. Мы также не видим ни их инициализации, ни документации о том, что они представляют.

Самый вероятный источник проблем

В 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 < gridsize - 1). Точно так же openNodes[i][j][7] эквивалентен доступу к openNodes[i][j+1][1] с теми же предостережениями.

...