这应该是在C#中实现A *(A星)算法的简单实现的方法吗?
答案 0 :(得分:6)
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,允许调整一些设置。
答案 1 :(得分:1)
在函数AStar中,我们首先创建一个新的matrixNode,参数fromX和fromY。 matrixNode具有属性," fr"这是任何给定的matrixNode与起始节点的距离,"到"属性,它是给定的matrixNode与目标matrixNode的距离(将是' E'在unitTest的例子中的坐标(3,3)处),以及属性" sum&# 34;这是"到"的总和和" fr"。属性parent是对给定节点在从起始节点到结束节点到达的路径中移动到的matrixNode的引用。字典绿色和红色分别是openSet和closedSet,如维基百科上的A* search algorithm页面所述。这些集合的一般思想是,我们试图找到绿色/开放集合中的matrixNode,其具有最低的"总和"价值,"总和"是节点与起始节点(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);
}
}
}
}