class Node//结点
{
public bool isOb = false;
public Node Parent;
public int F;
public int G;
public int H;
public int X;
public int Y;
public bool isLine = false;
}
class Map//地图
{
public Node[][] nodes;
public int XLength;
public int YLength;
public void Clear()
{
for (int i = 0; i < XLength; i++)
{
for (int j = 0; j < YLength; j++)
{
Node node = nodes[i][j];
node.F = 0;
node.G = 0;
node.H = 0;
node.isLine = false;
node.Parent = null;
}
}
}
//输出地图和寻路结果信息
public void PrintMap()
{
for (int i = 0; i < YLength; i++)
{
if (i == 0)
{
Console.Write(" " + " ");
for (int k = 0; k < XLength; k++)
{
Console.Write(k + " ");
}
Console.WriteLine();
}
for (int j = 0; j < XLength; j++)
{
if (j == 0)
{
Console.Write(i + " ");
}
Node node = nodes[j][i];
if (node.isLine)
{
Console.ForegroundColor = ConsoleColor.Red;
}
else
{
Console.ForegroundColor = ConsoleColor.Green;
}
if (node.isOb)
{
Console.ForegroundColor = ConsoleColor.Yellow;
Console.Write("#" + " ");
}
else
{
Console.Write("*" + " ");
}
Console.ForegroundColor = ConsoleColor.White;
}
Console.WriteLine();
}
}
}
class AXin//寻找
{
private List<Node> openList;
private List<Node> closeList;
private Map map;
private Node startNode;
private Node endNode;
private Node preNode;
public AXin()
{
openList = new List<Node>();
closeList = new List<Node>();
}
public void Search(int startX, int startY,int endX,int endY)
{
if (map == null)
{
Console.WriteLine("请设置地图");
return;
}
openList.Clear();
closeList.Clear();
map.Clear();
startNode = map.nodes[startX][startY];
if (startNode.isOb)
{
Console.WriteLine("开始位置为障碍物!");
return;
}
endNode = map.nodes[endX][endY];
openList.Add(startNode);
Search();
}
private void Search()
{
bool isSearch = false;
Node tempNode = null;
while (openList.Count > 0 && !isSearch)
{
tempNode = GetLowerFNode();
openList.Remove(tempNode);
closeList.Add(tempNode);
preNode = tempNode; //用来计算其他的结点的F
int x = tempNode.X, y = tempNode.Y;
//遍历周边结点8个 障碍和在close的 忽略
for (int i = -1; i < 2; i++)//x
{
for (int j = -1; j < 2; j++)//y
{
x = tempNode.X + i;
y = tempNode.Y + j;
if (x < 0 || x >= map.XLength || y < 0 || y >= map.YLength)
{
//越界了
continue;
}
if (i == 0 && j == 0) continue;//中心点
Node node = map.nodes[x][y];
//障碍跳过
if (node.isOb) continue;
//在close里面的跳过
if (isInClose(node)) continue;
//检查对角线 两边有障碍物的不能过
if (i != 0 && j != 0)
{
Node oneNode = map.nodes[tempNode.X][y];
if (oneNode.isOb) continue;
oneNode = map.nodes[x][tempNode.Y];
if (oneNode.isOb) continue;
}
//已经在openList
if (isInOpen(node))
{
//判断是否需要重新算 F
int offsetX = Math.Abs(node.X - preNode.X);
int offsetY = Math.Abs(node.Y - preNode.Y);
int len = 10;
if (offsetX + offsetY == 2)
{
len = 14;
}
if (preNode.G + len < node.G)
{
//重新算
node.G = preNode.G + len;
node.F = node.G + node.H;
node.Parent = preNode;
}
}
else {
//计算F 加进去 设置父物体
CalF(node);
openList.Add(node);
node.Parent = preNode;
if (node == endNode)
{
isSearch = true;
}
}
}
}
}
if (isSearch)
{
Node go = endNode;
//输出结果
while (go != startNode)
{
//Console.WriteLine("X:" + go.X +"||" + "Y:" + go.Y);
//Console.WriteLine("权重F="+go.F +" G="+go.G + " H="+go.H);
go.isLine = true;//标志路径
go = go.Parent;
}
go.isLine = true;
PrintMap();
}
else {
Console.WriteLine("没有找到!");
}
}
public void SetMap(Map m)
{
map = m;
}
//计算F的值
private void CalF(Node node)
{
int offsetX = Math.Abs(node.X - preNode.X);
int offsetY = Math.Abs(node.Y - preNode.Y);
if (offsetX + offsetY == 2)
{
node.G += 14;
}
else {
node.G += 10;
}
//计算方向
int DirectX = Math.Sign(endNode.X - node.X);
int DirectY = Math.Sign(endNode.Y - node.Y);
//计算H的X
int indexX = node.X;
while (indexX != endNode.X)
{
if (map.nodes[indexX][node.Y].isOb == false)
{
node.H += 10;
}
indexX += DirectX;
}
//计算H的Y
int indexY = node.Y;
while (indexY != endNode.Y)
{
if (map.nodes[node.X][indexY].isOb == false)
{
node.H += 10;
}
indexY += DirectY;
}
node.F = node.G + node.H;
}
private bool isInClose(Node node)
{
//可优化 在节点中保存信息
bool isIn = false;
foreach (var i in closeList)
{
if (node == i)
isIn = true;
}
return isIn;
}
private bool isInOpen(Node node)
{
//可优化 在节点中保存信息
bool isIn = false;
foreach (var i in openList)
{
if (node == i)
isIn = true;
}
return isIn;
}
private Node GetLowerFNode()
{
//可优化,用最小堆
if (openList.Count < 1) {
Console.WriteLine("怎么会没有了呢!");
return null;
}
Node node = openList[0];
for (int i = 1; i < openList.Count; i++)
{
if (openList[i].F < node.F)
{
node = openList[i];
}
}
return node;
}
public void PrintMap()
{
map.PrintMap();
}
}首先是将寻路区域分作一个个小方格(我这里是),这是基础
还需要一个评估节点承前启后的消耗,也就是F的计算,G是来到这个节点需要的消耗,H是预计到达目标点的消耗,F是这两个值的和
一个openList记录需要检查周边的节点,closeList记录已经去过的节点(就不用再访问了)
逻辑是这样子的,从openList取出F值最小的加入到closeList中,一开始起点结点会放到openList中
然后遍历这个节点周边的8个节点,障碍物的、在closeList的(访问过的)、斜角边附近有障碍物的都不能通过,直接不做处理;其他的做处理,如果在openList的,要检查当前路径到达这个节点的消耗是否优于以前的,是的话就更换一下F和G值,如果不是,新节点没访问过的,计算一下FGH,加入进去openList。
一直进行下去,直到找到了目标,它要加入到openList,或则openList里面一个元素都没有了。
G - 一个横 一个竖 都是10消耗,一个斜线14消耗(勾股定理)
H - 距离目标横竖偏移和*10(除开障碍物)
F = G + H