public void StartSearchPath()
{
if (start == null)
throw new InvalidNodeException(InvalidNodeTypes.NoStart);//起点为空 引发异常
if (end == null)
throw new InvalidNodeException(InvalidNodeTypes.NoEnd);//终点为空 引发异常
path = null;
openList.Clear();
closeList.Clear();//清理开启节点和关闭节点
currentNode = start;// 现节点为开始节点
SearchPath(currentNode);
}
//寻路递归,受保护的虚方法,允许在子类重写寻路算法
protected virtual void SearchPath(StarNode starNode)
{
openList.Remove(starNode);//从开启列表中移除
closeList.Add(starNode);//从关闭列表中加入
AddNodeToOpenList();//把当前点周围可通过的点加入到开放列表中
if (closeList.Contains(end))//如果终点在关闭列表中,找到路径
{
StarNode node = starNode.Parent;//将starNode的父节点赋值给node1
path = new StarNodeCollection();//声明一个路径节点集合
do
{
path.Add(node);//将node结点放入路径
node = node.Parent;
} while (node != null && !node.Equals(start));//路径中循环添加父节点(逆向返回添加)
path.Reverse();//将路径反转
return;
}
else if (openList.Count == 0)//终点不在关闭列表,开放列表已空,没有可通行的路径
{
return;
}
currentNode = GetNextNode();
SearchPath(currentNode);//迭代过程
}
public StarNode GetNextNode()//获得当前节点的下一个最佳节点
{
openList.SortByF();
return openList[0];//返回开启列表中F值最小的节点
} private void AddNodeToOpenList()//把当前点周围可通过的点加入到开放列表中
{ //上
if (currentNode.Y - 1 >= 0 && map[currentNode.X, currentNode.Y - 1] == 0 && !closeList.Contains(currentNode.X, currentNode.Y - 1))
{ //不是第一行 上节点map值为0 上节点不在关闭列表中
CheckNodeStatus(currentNode.X, currentNode.Y - 1);
}
//下
if (currentNode.Y + 1 < map.Height && map[currentNode.X, currentNode.Y + 1] == 0 && !closeList.Contains(currentNode.X, currentNode.Y + 1))
{//不是最底部一行 下节点map值为0 下节点不再关闭列表中
CheckNodeStatus(currentNode.X, currentNode.Y + 1);
}
//左
if (currentNode.X - 1 >= 0 && map[currentNode.X - 1, currentNode.Y] == 0 && !closeList.Contains(currentNode.X - 1, currentNode.Y))
{
CheckNodeStatus(currentNode.X - 1, currentNode.Y);
}
//右
if (currentNode.X + 1 < map.Width && map[currentNode.X + 1, currentNode.Y] == 0 && !closeList.Contains(currentNode.X + 1, currentNode.Y))
{
CheckNodeStatus(currentNode.X + 1, currentNode.Y);
}
if (allDirection)
{
//允许8方向寻路,查找对角线上的节点
//上左
if (currentNode.X - 1 >= 0 && currentNode.Y - 1 >= 0 && map[currentNode.X - 1, currentNode.Y - 1] == 0 && !closeList.Contains(currentNode.X - 1, currentNode.Y - 1))
{ //不在最左上 左上节点map值为0 左上节点不在关闭列表中
CheckNodeStatus(currentNode.X - 1, currentNode.Y - 1);
}
//上右
if (currentNode.X + 1 < map.Width && currentNode.Y - 1 >= 0 && map[currentNode.X + 1, currentNode.Y - 1] == 0 && !closeList.Contains(currentNode.X + 1, currentNode.Y + 1))
{
CheckNodeStatus(currentNode.X + 1, currentNode.Y - 1);
}
//下左
if (currentNode.X - 1 >= 0 && currentNode.Y + 1 < map.Height && map[currentNode.X - 1, currentNode.Y + 1] == 0 && !closeList.Contains(currentNode.X - 1, currentNode.Y + 1))
{
CheckNodeStatus(currentNode.X - 1, currentNode.Y + 1);
}
//下右
if (currentNode.X + 1 < map.Width && currentNode.Y + 1 < map.Height && map[currentNode.X + 1, currentNode.Y + 1] == 0 && !closeList.Contains(currentNode.X + 1, currentNode.Y + 1))
{
CheckNodeStatus(currentNode.X + 1, currentNode.Y + 1);
}
}
} private void CheckNodeStatus(int x, int y)//x,y为courrent附近的节点
{
StarNode childNode = new StarNode(x, y);//将坐标封装到节点
childNode.G = CalcG(childNode);
childNode.H = CalcH(childNode,end); //计算该点的H值和G值
if (openList.Contains(childNode))
{
//如果节点已经在开放列表中
StarNode node = openList[openList.FindIndex(childNode)];//openList[openList.FindIndex(childNode)]与childNode只有X Y相同 其余的不一定相同 故不可以用childNode代替openList[openList.FindIndex(childNode)]
if (currentNode.G + childNode.G <= node.G)
{
//如果从当前节点的父节点到该节点的G值小于等于该节点原有的G值
node.Parent = currentNode;//将该节点的父节点设为当前节点,并重新计算G值
node.G = currentNode.G + childNode.G;
}
}
else
{ //如果节点不在开放列表中
childNode.Parent = currentNode; //当前结点为下一结点的父结点
childNode.G += currentNode.G; //计算下一结点的G值
openList.Add(childNode); //将下一结点加入到开放列表中
}
} //计算两个节点间的H值
private int CalcH(StarNode node1, StarNode node2) // H = 从网格上那个方格移动到终点B的预估移动耗费
{
int h = Math.Abs(node2.X - node1.X) + Math.Abs(node2.Y - node1.Y);//从网格上那个方格移动到终点B的网格数
return h * 10;
} //计算指定节点相对当前节点的G值
private int CalcG(StarNode node) //G = 从起点A,沿着产生的路径,移动到网格上指定方格的移动耗费
{
if (node.X == currentNode.X || node.Y == currentNode.Y)//上下左右返回10
return 10;
else //斜对角返回14
return 14;
}这是曼哈顿A*算法 看代码好像要是进入死胡同的话是出不来的 可是程序运行却能绕过死胡同 这是怎么回事 请高手指点一二
{
if (start == null)
throw new InvalidNodeException(InvalidNodeTypes.NoStart);//起点为空 引发异常
if (end == null)
throw new InvalidNodeException(InvalidNodeTypes.NoEnd);//终点为空 引发异常
path = null;
openList.Clear();
closeList.Clear();//清理开启节点和关闭节点
currentNode = start;// 现节点为开始节点
SearchPath(currentNode);
}
//寻路递归,受保护的虚方法,允许在子类重写寻路算法
protected virtual void SearchPath(StarNode starNode)
{
openList.Remove(starNode);//从开启列表中移除
closeList.Add(starNode);//从关闭列表中加入
AddNodeToOpenList();//把当前点周围可通过的点加入到开放列表中
if (closeList.Contains(end))//如果终点在关闭列表中,找到路径
{
StarNode node = starNode.Parent;//将starNode的父节点赋值给node1
path = new StarNodeCollection();//声明一个路径节点集合
do
{
path.Add(node);//将node结点放入路径
node = node.Parent;
} while (node != null && !node.Equals(start));//路径中循环添加父节点(逆向返回添加)
path.Reverse();//将路径反转
return;
}
else if (openList.Count == 0)//终点不在关闭列表,开放列表已空,没有可通行的路径
{
return;
}
currentNode = GetNextNode();
SearchPath(currentNode);//迭代过程
}
public StarNode GetNextNode()//获得当前节点的下一个最佳节点
{
openList.SortByF();
return openList[0];//返回开启列表中F值最小的节点
} private void AddNodeToOpenList()//把当前点周围可通过的点加入到开放列表中
{ //上
if (currentNode.Y - 1 >= 0 && map[currentNode.X, currentNode.Y - 1] == 0 && !closeList.Contains(currentNode.X, currentNode.Y - 1))
{ //不是第一行 上节点map值为0 上节点不在关闭列表中
CheckNodeStatus(currentNode.X, currentNode.Y - 1);
}
//下
if (currentNode.Y + 1 < map.Height && map[currentNode.X, currentNode.Y + 1] == 0 && !closeList.Contains(currentNode.X, currentNode.Y + 1))
{//不是最底部一行 下节点map值为0 下节点不再关闭列表中
CheckNodeStatus(currentNode.X, currentNode.Y + 1);
}
//左
if (currentNode.X - 1 >= 0 && map[currentNode.X - 1, currentNode.Y] == 0 && !closeList.Contains(currentNode.X - 1, currentNode.Y))
{
CheckNodeStatus(currentNode.X - 1, currentNode.Y);
}
//右
if (currentNode.X + 1 < map.Width && map[currentNode.X + 1, currentNode.Y] == 0 && !closeList.Contains(currentNode.X + 1, currentNode.Y))
{
CheckNodeStatus(currentNode.X + 1, currentNode.Y);
}
if (allDirection)
{
//允许8方向寻路,查找对角线上的节点
//上左
if (currentNode.X - 1 >= 0 && currentNode.Y - 1 >= 0 && map[currentNode.X - 1, currentNode.Y - 1] == 0 && !closeList.Contains(currentNode.X - 1, currentNode.Y - 1))
{ //不在最左上 左上节点map值为0 左上节点不在关闭列表中
CheckNodeStatus(currentNode.X - 1, currentNode.Y - 1);
}
//上右
if (currentNode.X + 1 < map.Width && currentNode.Y - 1 >= 0 && map[currentNode.X + 1, currentNode.Y - 1] == 0 && !closeList.Contains(currentNode.X + 1, currentNode.Y + 1))
{
CheckNodeStatus(currentNode.X + 1, currentNode.Y - 1);
}
//下左
if (currentNode.X - 1 >= 0 && currentNode.Y + 1 < map.Height && map[currentNode.X - 1, currentNode.Y + 1] == 0 && !closeList.Contains(currentNode.X - 1, currentNode.Y + 1))
{
CheckNodeStatus(currentNode.X - 1, currentNode.Y + 1);
}
//下右
if (currentNode.X + 1 < map.Width && currentNode.Y + 1 < map.Height && map[currentNode.X + 1, currentNode.Y + 1] == 0 && !closeList.Contains(currentNode.X + 1, currentNode.Y + 1))
{
CheckNodeStatus(currentNode.X + 1, currentNode.Y + 1);
}
}
} private void CheckNodeStatus(int x, int y)//x,y为courrent附近的节点
{
StarNode childNode = new StarNode(x, y);//将坐标封装到节点
childNode.G = CalcG(childNode);
childNode.H = CalcH(childNode,end); //计算该点的H值和G值
if (openList.Contains(childNode))
{
//如果节点已经在开放列表中
StarNode node = openList[openList.FindIndex(childNode)];//openList[openList.FindIndex(childNode)]与childNode只有X Y相同 其余的不一定相同 故不可以用childNode代替openList[openList.FindIndex(childNode)]
if (currentNode.G + childNode.G <= node.G)
{
//如果从当前节点的父节点到该节点的G值小于等于该节点原有的G值
node.Parent = currentNode;//将该节点的父节点设为当前节点,并重新计算G值
node.G = currentNode.G + childNode.G;
}
}
else
{ //如果节点不在开放列表中
childNode.Parent = currentNode; //当前结点为下一结点的父结点
childNode.G += currentNode.G; //计算下一结点的G值
openList.Add(childNode); //将下一结点加入到开放列表中
}
} //计算两个节点间的H值
private int CalcH(StarNode node1, StarNode node2) // H = 从网格上那个方格移动到终点B的预估移动耗费
{
int h = Math.Abs(node2.X - node1.X) + Math.Abs(node2.Y - node1.Y);//从网格上那个方格移动到终点B的网格数
return h * 10;
} //计算指定节点相对当前节点的G值
private int CalcG(StarNode node) //G = 从起点A,沿着产生的路径,移动到网格上指定方格的移动耗费
{
if (node.X == currentNode.X || node.Y == currentNode.Y)//上下左右返回10
return 10;
else //斜对角返回14
return 14;
}这是曼哈顿A*算法 看代码好像要是进入死胡同的话是出不来的 可是程序运行却能绕过死胡同 这是怎么回事 请高手指点一二
解决方案 »
免费领取超大流量手机卡,每月29元包185G流量+100分钟通话, 中国电信官方发货