用A *解决C ++中的8-Puzzle导致无限循环

时间:2016-06-11 21:39:54

标签: c++ algorithm a-star

我目前正在尝试使用A *搜索算法解决8-Puzzle问题,但我的程序陷入无限循环。

我的主要搜索循环是:

std::vector<Field> Search::AStar(Field &start, Field &goal){
std::cout << "Calculating..." << std::endl;

std::unordered_map<Field, Field> explored;
std::vector<Field> searched;

if (Puzzle::finished(start))
    return MakePath(start, start);

std::priority_queue<Field, std::vector<Field>, std::greater<Field>> frontier;
frontier.push(start);

Field current;
Field child;

size_t i = 0;
while (!frontier.empty())
{
    current = frontier.top();
    frontier.pop();

    if (++i > 500)
    {
        std::cout << "Iteration Error" << std::endl;
        return searched;
    }

    searched.push_back(current);

    for (Direction d : Puzzle::Actions(current))
    {
        child = Puzzle::Action(d, current);

        if (Puzzle::finished(child))
        {
            std::cout << "Found goal!" << std::endl;
            return MakePath(explored[child], start);
        }

        child.CostG = current.CostG + 1; // Make a step

        if (!isIn(child, explored) || child.CostG < explored[child].CostG)
        {
            child.CostH = Puzzle::Heuristic(child, goal); // Calculate Heuristic
            child.CostF = child.CostG + child.CostH; // Calculate final costs

            frontier.push(child);
            explored[child] = child;
            explored[child].setParent(&explored[current]);
        }
    }
}

std::cout << "Error: frontier Empty" << std::endl;

return searched;
}

“搜索”向量只是为了让我可以看到A *做了什么,一旦算法运行,我就会删除它。

CostG代表在此之前完成的步骤数,CostH是“目标”的估计最小(启发式)成本,而CostF是两者的总和。

Field :: Boxes向量的索引是字段的编号,每个元素都包含该位置。

My Heuristic功能如下所示:

    inline int Heuristic(Field &goal)
{
    size_t d = 0;

    for (size_t i = 0; i < Boxes.size(); i++)
    {
        d += (std::abs(static_cast<int>(Boxes[i].x) - static_cast<int>(goal.Boxes[i].x))
            + std::abs(static_cast<int>(Boxes[i].y) - static_cast<int>(goal.Boxes[i].y)));
    }

    return d;
}

为了更好的可读性和内容,代码也在Github上。但是,要执行它,您需要在Visual Studio中包含SFML方向。

感谢每一位帮助!

编辑1: 您现在不再需要SFML来执行&amp;调试程序!我将更改提交给github,链接是一样的。

1 个答案:

答案 0 :(得分:0)

问题在于,虽然您从边界删除了current节点,但您从未将其添加到explored集,即您永远不会将其关闭。以下代码工作。我的修订严格遵循Wikipedia's A* Pseudocode

我还建议您在一个简单的谜题上使用简单的启发式算法(对所有值返回零值)测试您的算法,以验证您的算法是否正确实现。 (有关此技术的简要说明,请参阅this answer。)

while (!frontier.empty())
{
    current = frontier.top();
    frontier.pop();

    if (++i > 500)
    {
        std::cout << "Iteration Error" << std::endl;
        return searched;
    }

    // Check for goal here
    if (Puzzle::finished(current)
    {
        std::cout << "Found goal!" << std::endl;
        return MakePath(explored[current], start);
    }

    explored[current] = current; //close the current node
    searched.push_back(current);

    for (Direction d : Puzzle::Actions(current))
    {
        child = Puzzle::Action(d, current);

        if (isIn(child,explored)) 
        {
            continue; //ignore the neighbor which is already evaluated
        }

        child.CostG = current.CostG + 1; // Make a step

        if (!isIn(child, frontier)) //discovered a new node
        {
            frontier.push(child);
        } 
        else if (child.CostG >= explored[child].CostG)
        {
            continue; //this is not a better path
        {

        //the path is best until now. Record it!
        child.CostH = Puzzle::Heuristic(child, goal); // Calculate Heuristic
        child.CostF = child.CostG + child.CostH; // Calculate final costs

        //frontier.push(child); moved up to earlier point in code
        explored[child] = child;
        explored[child].setParent(&explored[current]);

    }
}