【问题标题】:A Star Search Algorithm一种星搜索算法
【发布时间】:2013-04-19 20:57:45
【问题描述】:

在这里,我有一个关于 A 星搜索算法的查询。我正在构建所谓的 8 块拼图。 这是一个有 9 个位置的游戏(1 个是空的),您必须按照正确的顺序排列瓷砖以达到目标位置。

我只需要验证我是否正确编写了算法,这样我就可以在我的代码中的其他地方寻找该问题。

我个人认为该算法是正确的,因为它能够解决我创建的第一个预设难题,只需一步即可到达目标位置。但是,它无法解决需要更多动作的谜题。

我已尝试以 3 种不同的方式使其发挥作用,但都带来了相同的问题。

尝试 1:

while (openList.Count() > 0)
        {
            PuzzleNode currentNode;
            var orderedOpenList = openList.OrderBy(PuzzleNode => PuzzleNode.getPathCost());

            currentNode = orderedOpenList.First();
            if (compare(currentNode.getPuzzle(), goalArray) == true)
            {
                //openList.RemoveAt(0); //POLL
                break;
                // otherwise push currentNode onto closedList & remove from openList
            }
            else
            {
                openList.Remove(currentNode);
                closedList.Add(currentNode);
            }

            //generate all the neighbor nodes
            generateSuccessors(currentNode, tempList);

            for (int i = 0; i < tempList.Count(); i++)
            {
                PuzzleNode tempNode = tempList[i];

                //skip the node if it's in the closed list
                if (closedList.Contains(tempNode))
                {
                    continue;
                }//end if

                //We need to ensure that the G we have seen here is the shortest one
                int gScore = currentNode.getG() + 1;

                if (!openList.Contains(tempNode) || gScore < tempNode.getG())
                {
                    tempNode.setParentNode(currentNode);
                    tempNode.setH(tempNode.calcH(currentHueristic, tempNode.getPuzzle(), goalArray));
                    tempNode.setG(gScore);
                    tempNode.updatePathCost();

                    if (!openList.Contains(tempNode))
                    {
                        openList.Add(tempNode);
                    }//end if


                }//end if
            }//end for

        }//end while

尝试 2:

while (openList.Count() > 0)
        {
            PuzzleNode currentNode = GetBestNodeFromOpenList(openList);

            openList.Remove(currentNode);
            closedList.Add(currentNode);

            generateSuccessors(currentNode, tempList);

            foreach (PuzzleNode successorNode in tempList)
            {
                if (compare(successorNode.getPuzzle(), goalArray) == true)
                {
                    //goto thebreak;
                    return successorNode;
                }
                successorNode.setG(currentNode.getG() + 1);
                successorNode.setH(successorNode.calcH(currentHueristic, successorNode.getPuzzle(), goalArray));
                successorNode.updatePathCost();


                if (OpenListHasBetterNode(successorNode, openList))
                    continue;

                openList.Add(successorNode);
            }
        }//end while

private static PuzzleNode GetBestNodeFromOpenList(IEnumerable<PuzzleNode> openList)
    {
        return openList.OrderBy(n => n.getPathCost()).First();
    }

private static bool OpenListHasBetterNode(PuzzleNode successor, IEnumerable<PuzzleNode> list)
    {
        return list.FirstOrDefault(n => n.getG().Equals(successor.getG())
                && n.getPathCost() < successor.getPathCost()) != null;
    }

尝试 2 是对我在互联网上找到的算法的更改:Solving the 8-Puzzle Problem

但是我尽我所能遵循维基百科上的伪代码:

function A*(start,goal)
     closedset := the empty set    // The set of nodes already evaluated.
     openset := {start}    // The set of tentative nodes to be evaluated, initially containing the start node
     came_from := the empty map    // The map of navigated nodes.

     g_score[start] := 0    // Cost from start along best known path.
     // Estimated total cost from start to goal through y.
     f_score[start] := g_score[start] + heuristic_cost_estimate(start, goal)

     while openset is not empty
         current := the node in openset having the lowest f_score[] value
         if current = goal
             return reconstruct_path(came_from, goal)

         remove current from openset
         add current to closedset
         for each neighbor in neighbor_nodes(current)
             tentative_g_score := g_score[current] + dist_between(current,neighbor)
             if neighbor in closedset
                 if tentative_g_score >= g_score[neighbor]
                     continue

             if neighbor not in openset or tentative_g_score < g_score[neighbor] 
                 came_from[neighbor] := current
                 g_score[neighbor] := tentative_g_score
                 f_score[neighbor] := g_score[neighbor] + heuristic_cost_estimate(neighbor, goal)
                 if neighbor not in openset
                     add neighbor to openset

我问你是否能找到一个问题,因为我很困惑为什么它只适用于其中一个谜题。 唯一将这些谜题分开是解决到目标状态所需的移动量。

我已经调试了好几个小时,但我还是看不到它,我也看不到我的代码中的其他地方可能有问题。所以我想我只是在问,这对你来说是否正确?

任何问题请务必提出,我会尽可能提供更多信息! 提前谢谢!

【问题讨论】:

  • 对于这样的问题,你基本上是在问你的代码是否有错误,我们需要整个项目。例如,我不知道 PuzzleNode 是什么,我可能做出的假设很容易出错并且浪费时间。请在某处为我们发布您的项目的 zip。
  • 另外,鉴于这是一段相当复杂的代码,最好利用您的时间来使用调试器并逐步执行它,跟踪每个变量,看看它是否是做你认为应该做的事。
  • "我个人认为该算法是正确的,因为它能够解决我创建的第一个预设难题,只需一步即可到达目标位置。但是,它是无法解决需要更多动作的难题。“这没有任何意义。您认为该算法是正确的因为除了最微不足道的情况之外,它对所有事情都给出了错误的答案?
  • 有没有办法私下分享这个项目,因为这是一项大学作业,我不希望任何人只下载我迄今为止的进度并可能在我面前上传它。我已经逐步完成了代码,但根据我的期望,我认为我可能会遗漏一些东西。至于没有意义的段落。我知道你来自哪里,但我这么说是因为算法在解决第一个难题时起作用。我认为也许其他地方可能存在导致问题的问题。

标签: c# algorithm search puzzle a-star


【解决方案1】:

注意:我正在使用 CustomPriorityQueue 类(由 itowlson 编写),您可以找到 here

所以这里我基本上使用 PriorityQueue,它会根据启发式值排列问题状态

这是一个简单的 C# 中的 A* 模板,说明了 A* 搜索的工作原理:

void enqueueAll(CustomPriorityQueue<PuzzleNode> a, ArrayList<PuzzleNode> b)
{
    foreach(PuzzleNode c in b) a.enqueue(c, h(c));
}

// A* heuritic: h = f + g ; h <= h*
int h(PuzzleNode n);

// returns TRUE if n is a solution
bool isSolution(PuzzleNode n);

// expand n into list of neighbors
ArrayList<PuzzleNode> expand(PuzzleNode n);

PuzzleNode Astar(PuzzleNode startPoint)
{
    CustomPriorityQueue list = new CustomPriorityQueue<PuzzleNode>();
    PuzzleNode current = null;

    list.enqueue(startPoint, h(startPoint));

    while (list.size() > 0)
    {
        current = list.dequeue();

        if (isSolution(current))
        {
            return current;
        }

        enqueueAll(list, expand(current));
    }
}

希望对你有帮助

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-10
    • 2019-12-20
    • 1970-01-01
    相关资源
    最近更新 更多