решение n-головоломки с помощью алгоритма A * с использованием C ++

Я реализую A* algorithm на C++, чтобы решить проблему с n-головоломками.
Я пытался реализовать псевдокод в эта ссылка.
Расчет общей стоимости (F=H+G): "стоимость зависит от количества неуместных плиток (эвристика) + шагов от начального состояния (G)" . Алгоритм функции AStar приведен ниже.

Проблема в том, что у меня ситуация с бесконечным циклом. Как я могу это решить?

PS: Я могу дать реализации других функций, используемых в AStar, если потребуется.

Любая помощь будет оценена по достоинству.

void AStar(const int size, int** puzzle)
{
int moveCount = 0;                                                                  // initialize G(n)
int**goalState = GoalState(size);                                                   // initialize  and assign goal state
int openListIndex = 0;                                                              // initialize open list index
vector<node> openList;                                                              // initialize open list
vector<node> closedList;                                                            // initialize closed list

node startNode;                                                                     // initialize start node
startNode.puzzleArray = puzzle;                                                     // assign start node's state
startNode.cost = moveCount + Heuristics(goalState,puzzle,size);                     // assign start node's cost

node goalNode;                                                                      // initialize goal node
goalNode.puzzleArray = goalState;                                                   // assign goal node's state

openList.push_back(startNode);                                                      // push start node to the open list

while (!openList.empty())                                                           // loop while open list is not empty
{
    node currentNode = CalculateLowestCost(&openList, &closedList);                 // initialize current node which has the lowest cost, pop it from open list, push it to the closed list
    int** currentState = currentNode.puzzleArray;                                   // initialize and assign current state array
    /*********************************************************************************************/
    if (GoalCheck(goalState, currentState, size)) break;                            // GOAL CHECK//
    /*********************************************************************************************/
    vector<char> successorDirectionList = CalculateSuccessor(size, currentState);   // initialize a char vector for the directions of the successors

    int**successor;                                                                 // initialize successor state
    node successorNode;                                                             // initialize successor node
    moveCount++;                                                                    // advance G(n)

    for (;!successorDirectionList.empty();)                                         // loop over the successor list
    {
        char direction = successorDirectionList.back();                             // take a direction from the list
        successorDirectionList.pop_back();                                          // remove that direction from the list
        successor = MoveBlank(currentState, size, direction);                       // assign successor state

        successorNode.puzzleArray = successor;                                      // assign successor node's state
        successorNode.cost = moveCount + Heuristics(goalState,currentState,size);   // assign successor node's cost

        //vector<node> stateCheckList = openList;                                   // copy the open list for the checking the nodes in that list

        bool flagOpen = false;
        bool flagClosed = false;
        int locationOpen = -1;
        int locationClosed = -1;

        for (int i=0; i<openList.size(); i++)
        {
            int** existing = openList[i].puzzleArray;
            int existingCost = openList[i].cost;

            if (StateCheck(successor, existing, size))
            {
                locationOpen = i;
                if (successorNode.cost > existingCost)
                {
                    flagOpen = true;
                    break;
                }
            }
        }
        if (flagOpen) continue;

        int** existingInOpen;
        if(locationOpen != -1) 
        {
            existingInOpen = openList[locationOpen].puzzleArray;
            openList.erase(openList.begin()+locationOpen);
        }

        for (int i=0; i<closedList.size(); i++)
        {
            int** existing = closedList[i].puzzleArray;
            int existingCost = closedList[i].cost;

            if (StateCheck(successor, existing, size))
            {
                locationClosed = i;
                if (successorNode.cost > existingCost)
                {
                    flagClosed = true;
                    break;
                }
            }
        }
        if (flagClosed) continue;

        int**existingInClosed;
        if(locationClosed != -1)
        {
            existingInClosed = closedList[locationClosed].puzzleArray;
            closedList.erase(closedList.begin()+locationClosed);
        }

        openList.push_back(successorNode);
    }    
}

}


person minyatur    schedule 18.10.2011    source источник
comment
Скорее вопрос, чем комментарий, но почему вы не использовали «пока (!successorDirectionList.empty())» вместо «for (;!successorDirectionList.empty();)»? Хотя то, что вы сделали, безусловно, является допустимым синтаксисом, это не совсем типично.   -  person andand    schedule 18.10.2011
comment
Я думал это одно и то же, в чем разница? Я пробовал с «пока» после того, как вы сказали, но все равно получаю бесконечный цикл.   -  person minyatur    schedule 18.10.2011
comment
Это то же самое; это просто не то, что люди обычно используют.   -  person icktoofay    schedule 18.10.2011
comment
Также может оказаться полезной дополнительная информация: Откуда вы знаете, что существует бесконечный цикл (в отличие от цикла, который выполняется, но занимает много времени)? Какие тесты вы выполнили, чтобы убедиться, что существует бесконечный цикл, и что это за цикл? Как настроить проблему, чтобы начать? IIRC, есть конфигурации, которые невозможно решить, если вы начинаете с чисто случайного состояния.   -  person andand    schedule 18.10.2011
comment
Я тестирую доску 3x3 (8-головоломка), которая должна состоять не более чем из 22 шагов (я думаю) с этой «допустимой» эвристикой. Кстати, это не дает бесконечного цикла, когда дело доходит до 2x2, как я сейчас тестировал.   -  person minyatur    schedule 18.10.2011
comment
У вас сложный алгоритм (+сложный код), без полного примера, и вы ждете помощи?   -  person BЈовић    schedule 18.10.2011
comment
Я думаю, вам нужно удалить узел из открытого списка, я предлагаю вам выполнить шаги по ссылке, которую вы разместили, и убедиться, что вы делаете их правильно.   -  person Carl Winder    schedule 18.10.2011


Ответы (3)


Из-за возможности циклов, то есть последовательности ходов, возвращающих вас в состояние, которое вы уже посетили, важно проверять наличие повторяющихся состояний (очевидно, это не проблема поиска по дереву). Я не совсем понимаю, что вы делаете с проверкой этого, но, вероятно, проблема именно в этом. У меня была похожая на вас проблема при написании реализации на Haskell (подробности здесь и здесь), и дело сводилось к проблеме обращения с исследуемым набором. Примите это правильно, и все заработает. (Получение решения головоломки 4x4 остается делом случайного, особенно если вы начинаете с состояния, находящегося далеко от цели в пространстве состояний, но в основном это связано с недостатками A* и наивным способом мы имеем дело с возможными ходами.)

person Ian Ross    schedule 20.10.2011

вы удаляете состояние, которое вы выбираете из открытого списка? это код C #, который очень прост и хорошо написан, возможно, он может вам помочь: http://geekbrothers.org/index.php/categories/computer/12-solve-8-puzzle-with-a, а также A* автоматически избегает циклов, поскольку занимает ходы, которые вы принимаете во внимание

person odyse    schedule 07.09.2013

Я также реализовал n-головоломку (сначала в глубину и a*), и она вошла в бесконечный цикл. Это произошло из-за следующего цикла: вверх, влево, вниз, вправо, вверх, влево... Я действительно не знаю, есть ли способ предотвратить такое (максимум, что я мог сделать, это предотвратить циклы, такие как левый-правый -влево... запоминая последний сделанный ход).

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

person rapuze    schedule 20.10.2011