【问题标题】:A* (A star) algorithm not exactly workingA*(A 星)算法无法正常工作
【发布时间】:2014-08-12 12:51:52
【问题描述】:

我正在尝试为大学工作实施 A 星搜索方法,所以我需要从头开始,但我在让它以正确的方式工作时遇到了一些麻烦。 这是我的问题的图片:

如您所见,它确实找到了一条路径,但不是最简单的路径。

这是我的工具:

public List<node> updateAstar(){
    //clear all the lists
    openedNodes.Clear();
    closedNodes.Clear();
    nodesToLook.Clear();
    //check if starpos and endpos are okay
    if(startPos!=null && endPos!=null){
        float F;
        node currentNote=Grid.getNodeAtPos(startPos);

        openedNodes.Add(currentNote);
        int i = 0;
        int size = 100;
        while(currentNote.type!=tilesType.END){
            if(i<=size){ //debugging purpose. prevent infinite loop 
                nodesToLook.Clear();
                foreach(node nearNode in currentNote.getNearestTiles()){
                    if(closedNodes.Find(r => ((r.pos.x==nearNode.pos.x)&&(r.pos.y==nearNode.pos.y)))==null){
                        nodesToLook.Add(nearNode);
                    }
                }

                float bestValue=float.PositiveInfinity;
                node bestNode=new node();

                foreach(node lookingNode in nodesToLook){
                    //check if current node is not on the closed list
                    if((closedNodes.Find(r => ((r.pos.x==lookingNode.pos.x)&&(r.pos.y==lookingNode.pos.y)))==null)
                        &&(openedNodes.Find(r => ((r.pos.x==lookingNode.pos.x)&&(r.pos.y==lookingNode.pos.y)))==null) 
                        && lookingNode.type!=tilesType.BLOCK){
                        //calculate F=G+H

                        //assume path number is 0 for the question purpose
                        F=lookingNode.G[pathNumber]+lookingNode.H[pathNumber];
                        if(F<bestValue){
                            bestValue=F;
                            bestNode=lookingNode;
                        }else
                            closedNodes.Add(lookingNode);
                    }
                }
                openedNodes.Add(bestNode);
                currentNote=bestNode;
                i++;
            }else{
                Debug.Log("Error getting better path");
                break;
            }
        }
    }else Debug.Log("Current path does not have an startpos nor endpos");
    return openedNodes;
}

这是我实例化每个节点的方式(我将其保存在矩阵中):

coordinate posAux=new coordinate();
this.myNodes=new node[columnNumber,lineNumber];
this.lineNumber=lineNumber;
this.columnNumber=columnNumber;
for(int y=0;y<lineNumber;y++){                      // Y Desce = linhas
    for(int x=0; x<columnNumber; x++){               // X vai pro lado = colunas
        //create a node based on matrix position
        posAux.Set(x, y);
        tilesType type;
        node current=new node(posAux);
        //update up and left nodes
        //"nodeDireita" means rightNode and "nodeEsquerda" means left node
        if(x-1>=0){                 
            current.nodeEsquerda=myNodes[x-1, y];
            myNodes[x-1, y].nodeDireita=current;
        }             
        if(y-1>=0){
            current.nodeAcima=myNodes[x, y-1];
            current.nodeAcima.nodeAbaixo=current;
        }

        //UNity stuff to set type of node visually based on what object is in it
        Collider[] colliders;
        if((colliders = Physics.OverlapSphere(coordinate.gridToUnity(posAux), 3f)).Length >0){
            foreach(Collider collider in colliders){
                objScript obj = collider.gameObject.GetComponent<objScript>();
                current.type=obj.type;
                if(current.type==tilesType.START){
                    path Path = new path (obj.pos, obj.posEnd, this);
                    addPath (Path); 
                    Path.numeroPath=paths.IndexOf(Path);
                }
            }
        }
        myNodes[x,y]=current;
    }
}   
//adicionar vetor[] para H e G com numero de paths nos nodes
//create a vector for multiple paths in each node
int numeroPaths = paths.Count;
for (int y = 0; y < lineNumber; y++) {
    for (int x = 0; x < columnNumber; x++) { 
        myNodes [x, y].H=new float[numeroPaths];
        myNodes [x, y].G=new float[numeroPaths];
    }
}
//adicionar Heuristica e G para cada node em cada path
//calculate heuristic and G for each node in each path
foreach (path Path in paths) {
    coordinate start=Path.startPos, end=Path.endPos;
    int numeroPath=paths.IndexOf(Path);

    for (int y = 0; y < lineNumber; y++) {
        for (int x = 0; x < columnNumber; x++) { 
            coordinate pos = myNodes [x, y].pos;
            //G e H as manhattan distance

            /*Mathf.Sqrt(Mathf.Pow((start.x - pos.x), 2) + Mathf.Pow((start.y - pos.y), 2)); euclidian-does not apply x.x */
            myNodes [x, y].H[numeroPath]=Mathf.Abs(pos.x-end.x) + Mathf.Abs(pos.y-end.y);
            myNodes [x, y].G[numeroPath]=Mathf.Abs(start.x-pos.x) + Mathf.Abs(start.y-pos.y);
        }
    }
}

代码参考:

--node 是一个自定义类,包含我使用曼哈顿公式定义的“G”和“H”,“x”、“y”、“BLOCK”或“NORMAL” (职位空缺)

--openedNodes 是一个列表,我为路径放置了正确的节点

--closedNodes 是我检查的节点,但有更大的“F”值;

--nodesToLook 是要检查的邻居节点。

感谢您的帮助。 谢谢。

【问题讨论】:

  • 您是否特别需要自己实现这个?对于我最后一年的项目,我只是能够将this实现引用为一个dll,然后只需要一行代码就可以实现
  • 正如我所评论的,整个目的是学习如何从头开始编写 IA 路径。
  • 我没有看到一条评论说,无论哪种方式,该链接都有可能对您有所帮助的完整源代码。
  • 请注意:您应该使用 HashSets 而不是 Lists(更快)甚至是 Bitarrays
  • 一方面,您混淆了打开和关闭列表。打开列表包含最终必须检查的节点,而关闭列表包含不再检查的节点(因为它们无法通过更短的路径到达)。那么,如何计算节点的GH?我在任何地方都看不到任何成本的更新(这是算法的重要部分)。您对列表的处理总体上有点笨拙。例如。你真的不需要nodesToLook。而是直接将节点添加到打开列表中,或者如果它们已经在此列表中,则更新它们的成本。

标签: c# unity3d artificial-intelligence a-star


【解决方案1】:

由于你没有发布你的整个代码,我一点也不知道你在用你的节点做什么,但是我可以看到:

  • 您没有更新 G。G 不是启发式,它是到达该节点的实际成本。又名:nextTile.G = currentTile.G + distanceBetween(currentTile,nextTile)
  • 您只是将最佳选项添加到打开列表中。因此,您只需检查 1 个,而不是检查所有 4 个

我可以继续,但你的整个算法根本不像 A* 那样工作。修复你的代码意味着完全重写它。

算法很简单。维基百科上的pseudocode可以直接复制实现。似乎您在那里错过了几个步骤并且错误地实施了很多事情。

【讨论】:

  • 我的 G 和 H 都是在使用曼哈顿方法创建节点时计算的。我不会在代码运行时更新它们。我应该吗?
  • 不,H 可以保留,因为它是启发式的。但是,G 必须更新。这就像数步数。 “我花了 6 步才到这里。我的下一个职位将是 6 + 1 = 7 步”。更新G意味着更新F(F=G+H,G变,F也会变)
  • H 可以保持预先计算的原因:它不会改变。除非您知道到达终点需要多少步,否则您无法预测 H。如果您确实知道它将采取多少步...您已经知道路径;-)
  • 好吧,我希望你现在能更好地理解 A* 背后的概念。我上次实现它已经 4 年了,所以我不知道如何实际实现它,但这个概念非常像你在现实生活中的做法。
猜你喜欢
  • 1970-01-01
  • 2017-05-16
  • 2014-05-14
  • 2011-10-22
  • 1970-01-01
  • 2015-10-14
  • 1970-01-01
  • 2014-11-06
相关资源
最近更新 更多