219 lines
4.7 KiB
C++
219 lines
4.7 KiB
C++
|
|
#include "Astart.h"
|
|
#include "双向链表.h"
|
|
|
|
|
|
DWORD 测距(
|
|
POINT 坐标1,
|
|
POINT 坐标2)
|
|
{
|
|
DWORD x,y;
|
|
x = (坐标1.x>坐标2.x) ? 坐标1.x-坐标2.x:坐标2.x-坐标1.x;
|
|
y = (坐标1.y>坐标2.y) ? 坐标1.y-坐标2.y:坐标2.y-坐标1.y;
|
|
|
|
return (x+y)*10;
|
|
}
|
|
|
|
地图结构* WINAPI MapCreate(
|
|
DWORD 宽度,
|
|
DWORD 高度,
|
|
BYTE* 点阵数据)
|
|
{
|
|
地图结构* 地图 = (地图结构*)分配内存(sizeof(地图结构));
|
|
if (!地图)
|
|
return NULL;
|
|
|
|
地图->宽度 = 宽度;
|
|
地图->高度 = 高度;
|
|
地图->数据 = 点阵数据;
|
|
地图->大小 = 宽度*高度;
|
|
if (!(地图->节点 = (节点结构*)分配内存(地图->大小*sizeof(节点结构))))
|
|
{
|
|
释放内存(地图);
|
|
地图 = NULL;
|
|
}
|
|
|
|
return 地图;
|
|
}
|
|
|
|
VOID WINAPI MapDestroy(
|
|
地图结构* 地图)
|
|
{
|
|
释放内存(地图->节点);
|
|
释放内存(地图);
|
|
}
|
|
地图结构* WINAPI MapCreate2(
|
|
地图结构* 地图,
|
|
DWORD 宽度,
|
|
DWORD 高度,
|
|
BYTE* 点阵数据)
|
|
{
|
|
|
|
地图->宽度 = 宽度;
|
|
地图->高度 = 高度;
|
|
地图->数据 = 点阵数据;
|
|
地图->大小 = 宽度*高度;
|
|
if (!(地图->节点 = (节点结构*)分配内存(地图->大小*sizeof(节点结构))))
|
|
return NULL;
|
|
|
|
return 地图;
|
|
}
|
|
|
|
VOID WINAPI MapDestroy2(
|
|
地图结构* 地图)
|
|
{
|
|
释放内存(地图->节点);
|
|
}
|
|
BOOL WINAPI FindPath(
|
|
地图结构* 地图数据,
|
|
POINT* 起点坐标,
|
|
POINT* 终点坐标,
|
|
BOOL 搜索模式)
|
|
{
|
|
/* 终点开始查找 */
|
|
POINT 起点 = *终点坐标;
|
|
POINT 终点 = *起点坐标;
|
|
|
|
BYTE* 点阵数据 = 地图数据->数据;
|
|
DWORD 地图宽度 = 地图数据->宽度;
|
|
DWORD 地图高度 = 地图数据->高度;
|
|
DWORD 地图大小 = 地图数据->大小;
|
|
双向链表 待检链表(地图大小);
|
|
|
|
BOOLEAN 已找到 = FALSE;
|
|
static int x[] = {-1,-1,0,1,1,1,0,-1};
|
|
static int y[] = {0,-1,-1,-1,0,1,1,1};
|
|
|
|
节点结构* 地图节点 = 地图数据->节点;
|
|
内存清零(地图节点,地图大小*sizeof(节点结构));
|
|
|
|
DWORD 索引 = 地图宽度*起点.y+起点.x;
|
|
if (索引>=地图大小)
|
|
return FALSE;
|
|
地图节点[索引].状态 = 待检;
|
|
地图节点[索引].距终点 = 测距(起点,终点);
|
|
地图节点[索引].总距离 = 地图节点[索引].距终点;
|
|
|
|
待检链表.插入((LPVOID)索引,地图节点[索引].总距离);
|
|
|
|
while (待检链表.取节点数() != 0 && 已找到 == FALSE)
|
|
{
|
|
/* 在待检链表中取出 F(总距离) 最小的节点, 并将其选为当前点 */
|
|
待检链表.到尾节点();
|
|
DWORD 当前索引 = (DWORD)待检链表.取节点值();
|
|
待检链表.删除();
|
|
地图节点[当前索引].状态 = 关闭;
|
|
|
|
POINT 当前坐标 =
|
|
{
|
|
当前索引 % 地图宽度,
|
|
当前索引 / 地图宽度
|
|
};
|
|
|
|
/* 遍历当前坐标的八个相邻坐标 */
|
|
for (int i=0;i<8;i++)
|
|
{
|
|
if (搜索模式 && i%2)
|
|
continue;
|
|
POINT 相邻坐标 =
|
|
{
|
|
当前坐标.x + x[i],
|
|
当前坐标.y + y[i]
|
|
};
|
|
|
|
/* 检查坐标有效性 */
|
|
if (相邻坐标.x<0 || (DWORD)相邻坐标.x>=地图宽度
|
|
|| 相邻坐标.y<0 || (DWORD)相邻坐标.y>=地图高度)
|
|
continue;
|
|
|
|
DWORD 相邻索引 = 地图宽度*相邻坐标.y+相邻坐标.x;
|
|
if (点阵数据[相邻索引] != 可通过 ||相邻索引+1>=地图大小||
|
|
相邻索引+地图宽度>=地图大小||相邻索引-1<0||相邻索引-地图宽度<0)
|
|
continue;
|
|
switch (i)
|
|
{
|
|
case 1:
|
|
if (点阵数据[相邻索引+1] != 可通过 || 点阵数据[相邻索引+地图宽度] != 可通过)
|
|
continue;
|
|
case 3:
|
|
if (点阵数据[相邻索引-1] != 可通过 || 点阵数据[相邻索引+地图宽度] != 可通过)
|
|
continue;
|
|
case 5:
|
|
if (点阵数据[相邻索引-1] != 可通过 || 点阵数据[相邻索引-地图宽度] != 可通过)
|
|
continue;
|
|
case 7:
|
|
if (点阵数据[相邻索引+1] != 可通过 || 点阵数据[相邻索引-地图宽度] != 可通过)
|
|
continue;
|
|
}
|
|
|
|
/* 检查是否已到达终点 */
|
|
if (相邻坐标.x == 终点.x && 相邻坐标.y == 终点.y)
|
|
{
|
|
已找到 = TRUE;
|
|
地图节点[相邻索引].父坐标 = 当前坐标;
|
|
break;
|
|
}
|
|
|
|
DWORD g = ((i%2) ? 14:10) + abs(点阵数据[当前索引]-点阵数据[相邻索引]);
|
|
|
|
|
|
if (地图节点[相邻索引].状态 == 未知)
|
|
{
|
|
/* 放入待检链表中 */
|
|
地图节点[相邻索引].状态 = 待检;
|
|
地图节点[相邻索引].距起点 = 地图节点[当前索引].距起点 + g;
|
|
地图节点[相邻索引].距终点 = 测距(相邻坐标,终点);
|
|
地图节点[相邻索引].总距离 = 地图节点[相邻索引].距起点 + 地图节点[相邻索引].距终点;
|
|
地图节点[相邻索引].父坐标 = 当前坐标;
|
|
|
|
DWORD 总距离 = 地图节点[相邻索引].总距离;
|
|
if (待检链表.取节点数() == 0 )
|
|
待检链表.插入((LPVOID)相邻索引,地图节点[相邻索引].总距离);
|
|
else
|
|
{
|
|
待检链表.到尾节点();
|
|
while (TRUE)
|
|
{
|
|
if (待检链表.取键值()>=总距离)
|
|
{
|
|
待检链表.插入((LPVOID)相邻索引,地图节点[相邻索引].总距离);
|
|
break;
|
|
}
|
|
if (!待检链表.到父节点())
|
|
{
|
|
待检链表.插入((LPVOID)相邻索引,地图节点[相邻索引].总距离,双向链表::向前插入);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (地图节点[相邻索引].状态 == 待检)
|
|
{
|
|
/* 如果将当前点设为父 G(距起点) 值是否更小 */
|
|
if (地图节点[相邻索引].距起点 > 地图节点[当前索引].距起点 + g)
|
|
{
|
|
地图节点[相邻索引].父坐标 = 当前坐标;
|
|
地图节点[相邻索引].距起点 = 地图节点[当前索引].距起点 + g;
|
|
地图节点[相邻索引].总距离 = 地图节点[相邻索引].距起点 + 地图节点[相邻索引].距终点;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return 已找到;
|
|
}
|
|
|
|
BOOL WINAPI NextPath(
|
|
地图结构* 地图,
|
|
POINT* 坐标)
|
|
{
|
|
DWORD 索引 = 坐标->y*地图->宽度+坐标->x;
|
|
if (索引>=0 && 索引<地图->大小)
|
|
{
|
|
*坐标 = 地图->节点[索引].父坐标;
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|