【问题标题】:How to implement an A* algorithm? [closed]如何实现 A* 算法? [关闭]
【发布时间】:2011-01-09 11:11:22
【问题描述】:

在 C# 中获得 A*(A 星)算法的简单实现应该是哪种方式?

【问题讨论】:

  • 指针在 C# 中是不安全的。 /笑话
  • 谢谢你,我想我找到了,在这里:policyalmanac.org/games/aStarTutorial.htm
  • 一年半后,在谷歌中输入那个确切的句子,你应该会找到这个页面和一个尖刻的评论,告诉你去做你刚刚做的事情。
  • 4 年后,我们仍然在 Google 中输入这个确切的句子并找到这个页面,其中包含您的尖刻评论,告诉我们完全按照您所说的去做。
  • 6 年后,完全相同的 Google 查询将我们引向了这个无用的线程,其中包含刻薄的 cmets 和死链接。伙计们,万岁,我们已经有效地制造了一台到 1996 年的时间机器。

标签: c# algorithm a-star


【解决方案1】:

This article详细解释了基本实现:

这篇博文的目的是通过一个非常简单的 C# 实现来展示 A* 的基础知识。

它还指向更好的实现,更适合生产使用:

至于如何找到更好的路线,周围有很多 C# 示例比这个更好、更丰富。 CastorTiu 在 CodeProject 上有一个非常好的演示解决方案,A* algorithm implementation in C#,它可以动画搜索算法并允许用户调整一些设置。 [...]

EpPathFinding.cs- A Fast Path Finding Algorithm (Jump Point Search) in C# (grid-based)。它有一个漂亮、清晰的 GUI,并允许调整一些设置。

【讨论】:

    【解决方案2】:

    在函数 AStar 中,我们首先创建一个新的 matrixNode,参数为 fromX 和 fromY。 matrixNode 具有属性,“fr”是任何给定 matrixNode 到起始节点的距离,“to”属性是给定 matrixNode 到目标 matrixNode 的距离(在坐标(3,3 ) 在 unitTest 的示例中),以及一个属性“sum”,它是“to”和“fr”的总和。属性 parent 是对给定节点在从开始节点到达结束节点的路径中移动到的 matrixNode 的引用。字典 greens 和 reds 分别是 openSet 和 closedSet,如 Wikipedia 上的 A* search algorithm 页面所述。这些集合的一般想法是,我们试图在绿色/开放集合中找到具有最低“sum”值的 matrixNode,因为“sum”是节点到起始节点的距离总和 ( fromX,fromY) 和结束节点 (toX, toY)

        public static void unitTest_AStar()
        {
            char[][] matrix = new char[][] { new char[] {'-', 'S', '-', '-', 'X'},
                                             new char[] {'-', 'X', 'X', '-', '-'},
                                             new char[] {'-', '-', '-', 'X', '-'},
                                             new char[] {'X', '-', 'X', 'E', '-'},
                                             new char[] {'-', '-', '-', '-', 'X'}};
    
            //looking for shortest path from 'S' at (0,1) to 'E' at (3,3)
            //obstacles marked by 'X'
            int fromX = 0, fromY = 1, toX = 3, toY = 3;
            matrixNode endNode = AStar(matrix, fromX, fromY, toX, toY);
    
            //looping through the Parent nodes until we get to the start node
            Stack<matrixNode> path = new Stack<matrixNode>();
    
            while (endNode.x != fromX || endNode.y != fromY)
            {
                path.Push(endNode);
                endNode = endNode.parent;
            }
            path.Push(endNode);
    
            Console.WriteLine("The shortest path from  " +
                              "(" + fromX + "," + fromY + ")  to " +
                              "(" + toX + "," + toY + ")  is:  \n");
    
            while (path.Count > 0)
            {
                matrixNode node = path.Pop();
                Console.WriteLine("(" + node.x + "," + node.y + ")");
            }
        }
    
        public class matrixNode
        {
            public int fr = 0, to = 0, sum = 0;
            public int x, y;
            public matrixNode parent;
        }
    
        public static matrixNode AStar(char[][] matrix, int fromX, int fromY, int toX, int toY)
        {
            ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
            // in this version an element in a matrix can move left/up/right/down in one step, two steps for a diagonal move.
            ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
            //the keys for greens and reds are x.ToString() + y.ToString() of the matrixNode 
            Dictionary<string, matrixNode> greens = new Dictionary<string, matrixNode>(); //open 
            Dictionary<string, matrixNode> reds = new Dictionary<string, matrixNode>(); //closed 
    
            matrixNode startNode = new matrixNode { x = fromX, y = fromY };
            string key = startNode.x.ToString() + startNode.x.ToString();
            greens.Add(key, startNode);
    
            Func<KeyValuePair<string, matrixNode>> smallestGreen = () =>
            {
                KeyValuePair<string, matrixNode> smallest = greens.ElementAt(0);
    
                foreach (KeyValuePair<string, matrixNode> item in greens)
                {
                    if (item.Value.sum < smallest.Value.sum)
                        smallest = item;
                    else if (item.Value.sum == smallest.Value.sum
                            && item.Value.to < smallest.Value.to)
                        smallest = item;
                }
    
                return smallest;
            };
    
    
            //add these values to current node's x and y values to get the left/up/right/bottom neighbors
            List<KeyValuePair<int, int>> fourNeighbors = new List<KeyValuePair<int, int>>()
                                                { new KeyValuePair<int, int>(-1,0),
                                                  new KeyValuePair<int, int>(0,1),
                                                  new KeyValuePair<int, int>(1, 0),
                                                  new KeyValuePair<int, int>(0,-1) };
    
            int maxX = matrix.GetLength(0);
            if (maxX == 0)
                return null;
            int maxY = matrix[0].Length;
    
            while (true)
            {
                if (greens.Count == 0)
                    return null;
    
                KeyValuePair<string, matrixNode> current = smallestGreen();
                if (current.Value.x == toX && current.Value.y == toY)
                    return current.Value;
    
                greens.Remove(current.Key);
                reds.Add(current.Key, current.Value);
    
                foreach (KeyValuePair<int, int> plusXY in fourNeighbors)
                {
                    int nbrX = current.Value.x + plusXY.Key;
                    int nbrY = current.Value.y + plusXY.Value;
                    string nbrKey = nbrX.ToString() + nbrY.ToString();
                    if (nbrX < 0 || nbrY < 0 || nbrX >= maxX || nbrY >= maxY
                        || matrix[nbrX][nbrY] == 'X' //obstacles marked by 'X'
                        || reds.ContainsKey(nbrKey))
                        continue;
    
                    if (greens.ContainsKey(nbrKey))
                    {
                        matrixNode curNbr = greens[nbrKey];
                        int from = Math.Abs(nbrX - fromX) + Math.Abs(nbrY - fromY);
                        if (from < curNbr.fr)
                        {
                            curNbr.fr = from;
                            curNbr.sum = curNbr.fr + curNbr.to;
                            curNbr.parent = current.Value;
                        }
                    }
                    else
                    {
                        matrixNode curNbr = new matrixNode { x = nbrX, y = nbrY };
                        curNbr.fr = Math.Abs(nbrX - fromX) + Math.Abs(nbrY - fromY);
                        curNbr.to = Math.Abs(nbrX - toX) + Math.Abs(nbrY - toY);
                        curNbr.sum = curNbr.fr + curNbr.to;
                        curNbr.parent = current.Value;
                        greens.Add(nbrKey, curNbr);
                    }
                }
            }
        }
    

    【讨论】:

    • 小类型'o string key = startNode.x.ToString() + startNode.x.ToString();必须改成string key = startNode.x.ToString() + startNode.y.ToString();
    猜你喜欢
    • 2016-12-20
    • 1970-01-01
    • 2016-07-05
    • 2011-04-19
    • 1970-01-01
    • 2012-03-15
    • 1970-01-01
    • 1970-01-01
    • 2011-06-05
    相关资源
    最近更新 更多