-
Notifications
You must be signed in to change notification settings - Fork 7
/
AStar.cpp
316 lines (292 loc) · 9.4 KB
/
AStar.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
#include "AStar.h"
AStar::AStar()
: m_map(nullptr), m_mapWidth(0), m_mapHeight(0), m_beginNode(nullptr), m_endNode(nullptr)
{
}
AStar::~AStar()
{
// delete m_map
if (m_map) {
deleteMap();
}
}
void AStar::InitMap(int **map, unsigned int width, unsigned int height)
{
if (m_map) {
deleteMap();
}
m_mapWidth = width;
m_mapHeight = height;
// 建立辅助地图
m_map = new Node *[height];
for (int y = 0; y < height; y++)
{
m_map[y] = new Node[width];
for (int x = 0; x < width; x++)
{
Node &node = m_map[y][x];
node.X = x;
node.Y = y;
node.IsObstacle = map[y][x] == 1 ? true : false;
}
}
}
void AStar::FindPath(unsigned int beginX, unsigned int beginY, unsigned int endX, unsigned int endY)
{
resetMap();
m_beginNode = &m_map[beginY][beginX];
m_endNode = &m_map[endY][endX];
m_beginNode->IsInClosedList = true;
Node exploringNode = *m_beginNode;
while (true)
{
// 找出探路点周围8个可行点,保存到开放列表
updateOpenedNodeList(exploringNode);
if (m_openedNodeList.size() == 0)
{
break;
}
// 找出当前点周围最小f值可行点
vector<Node *>::const_iterator cIter = m_openedNodeList.cbegin();
vector<Node *>::const_iterator minFNodeConstIter = cIter;
// cout << endl
// << "在开放列表中的点: ";
for (; cIter != m_openedNodeList.cend(); cIter++)
{
// cout << (*cIter)->X << "," << (*cIter)->Y << " ";
if ((*minFNodeConstIter)->F > (*cIter)->F)
{
minFNodeConstIter = cIter;
}
}
// 换层
Node *minFNodePtr = *minFNodeConstIter;
if (minFNodePtr->X == m_endNode->X &&
minFNodePtr->Y == m_endNode->Y)
{
break;
}
exploringNode = *minFNodePtr;
minFNodePtr->IsInClosedList = true;
// 将探路点从开放列表中移除
minFNodePtr->IsInOpenedList = false;
m_openedNodeList.erase(minFNodeConstIter);
} // end--while(1)寻路
// 路径回溯
Node *pathNodePtr = m_endNode;
while (true)
{
pathNodePtr->IsInPath = true;
m_pathNodeList.insert(m_pathNodeList.begin(), pathNodePtr);
pathNodePtr = pathNodePtr->ParentNode;
if (nullptr == pathNodePtr)
{
break;
}
}
}
void AStar::PrintPath()
{
cout << endl
<< "最短路径:";
vector<Node *>::const_iterator cIter = m_pathNodeList.cbegin();
for (; cIter != m_pathNodeList.cend(); cIter++)
{
cout << (*cIter)->X << "," << (*cIter)->Y << " ";
}
cout << endl;
}
void AStar::PrintPathMap()
{
// 打印路线地图
for (int y = 0; y < m_mapHeight; y++)
{
for (int x = 0; x < m_mapWidth; x++)
{
if (m_map[y][x].IsInPath)
cout << "*";
else
cout << m_map[y][x].IsObstacle;
}
cout << endl;
}
}
void AStar::resetMap()
{
for (int y = 0; y < m_mapHeight; y++)
{
for (int x = 0; x < m_mapWidth; x++)
{
m_map[y][x].Reset();
}
}
m_openedNodeList.clear();
m_pathNodeList.clear();
}
bool AStar::isObstacle(const Node &node)
{
return whetherPosHasObstacle(node.X, node.Y);
}
bool AStar::whetherPosHasObstacle(unsigned int x, unsigned int y)
{
if (x < 0 || x >= m_mapWidth ||
y < 0 || y >= m_mapHeight) // 超出地图
return true;
if (m_map[y][x].IsObstacle) // 该点为障碍
return true;
return false;
}
int AStar::getH(const Node &node)
{
unsigned int x = abs(long(node.X) - long(m_endNode->X)); // 取水平距离差绝对值
unsigned int y = abs(long(node.Y) - long(m_endNode->Y)); // 取竖直距离差绝对值
return (x + y) * VerticalDist;
}
void AStar::updateOpenedNodeList(const Node &exploringNode)
{
Node nextExploringNode;
// 找出探路点周围8个可行点,保存到开放列表
for (DirectionEnum dir : DirectionEnums)
{
bool canWalkToNextNode = true; // 是否可行走至下一探路点
unsigned int gIncreaseValue = 0; // g值增加量
switch (dir)
{
case Up:
{
// nextExploringNode = &m_map[exploringNode->Y - 1][exploringNode->X]
nextExploringNode.X = exploringNode.X;
nextExploringNode.Y = exploringNode.Y - 1; // 只有行减1
gIncreaseValue = VerticalDist;
break;
}
case Down:
{
nextExploringNode.X = exploringNode.X;
nextExploringNode.Y = exploringNode.Y + 1; // 只有行加1
gIncreaseValue = VerticalDist;
break;
}
case Left:
{
nextExploringNode.X = exploringNode.X - 1; // 行不变,列减1
nextExploringNode.Y = exploringNode.Y;
gIncreaseValue = VerticalDist;
break;
}
case Right:
{
nextExploringNode.X = exploringNode.X + 1; // 行不变,列加1
nextExploringNode.Y = exploringNode.Y;
gIncreaseValue = VerticalDist;
break;
}
case LeftUp:
{
if (whetherPosHasObstacle(exploringNode.X, exploringNode.Y - 1) || // 判断当前点上边点是否为障碍
whetherPosHasObstacle(exploringNode.X - 1, exploringNode.Y) // 判断当前点左边点是否为障碍
)
{
canWalkToNextNode = false;
break;
}
nextExploringNode.X = exploringNode.X - 1;
nextExploringNode.Y = exploringNode.Y - 1;
gIncreaseValue = ObliqueDist;
break;
}
case LeftDown:
{
if (whetherPosHasObstacle(exploringNode.X, exploringNode.Y + 1) || // 判断当前点下边点是否为障碍
whetherPosHasObstacle(exploringNode.X - 1, exploringNode.Y) // 判断当前点左边点是否为障碍
)
{
canWalkToNextNode = false;
break;
}
nextExploringNode.X = exploringNode.X - 1;
nextExploringNode.Y = exploringNode.Y + 1;
gIncreaseValue = ObliqueDist;
break;
}
case RightUp:
{
if (whetherPosHasObstacle(exploringNode.X, exploringNode.Y - 1) || // 判断当前点上边点是否为障碍
whetherPosHasObstacle(exploringNode.X + 1, exploringNode.Y) // 判断当前点右边点是否为障碍
)
{
canWalkToNextNode = false;
break;
}
nextExploringNode.X = exploringNode.X + 1;
nextExploringNode.Y = exploringNode.Y - 1;
gIncreaseValue = ObliqueDist;
break;
}
case RightDown:
{
if (whetherPosHasObstacle(exploringNode.X, exploringNode.Y + 1) || // 判断当前点下边点是否为障碍
whetherPosHasObstacle(exploringNode.X + 1, exploringNode.Y) // 判断当前点右边点是否为障碍
)
{
canWalkToNextNode = false;
break;
}
nextExploringNode.X = exploringNode.X + 1;
nextExploringNode.Y = exploringNode.Y + 1;
gIncreaseValue = ObliqueDist;
break;
}
}
// 如果下一个探路点为障碍点,则视为不可行走到
if (canWalkToNextNode && isObstacle(nextExploringNode))
{
canWalkToNextNode = false;
}
if (!canWalkToNextNode)
{
continue;
}
// 如果下一个探路点在关闭列表中,则不加入开放列表
if (m_map[nextExploringNode.Y][nextExploringNode.X].IsInClosedList)
{
continue;
}
//// 将下一探路点加入到开放列表
// 更新下一探路点g值
nextExploringNode.G = exploringNode.G + gIncreaseValue;
// 检查是否已经在开放列表中
Node &exploringNodeInMap = m_map[exploringNode.Y][exploringNode.X];
Node &nextExploringNodeInMap = m_map[nextExploringNode.Y][nextExploringNode.X];
bool isInOpenLst = nextExploringNodeInMap.IsInOpenedList;
if (isInOpenLst)
{
// 如果下一探路点g值小于开放列表中对映点的g值
if (nextExploringNodeInMap.G > nextExploringNode.G)
{
nextExploringNodeInMap.G = nextExploringNode.G;
nextExploringNodeInMap.UpdateF();
nextExploringNodeInMap.ParentNode = &exploringNodeInMap;
}
}
else
{
nextExploringNodeInMap.G = nextExploringNode.G;
nextExploringNodeInMap.H = getH(nextExploringNodeInMap);
nextExploringNodeInMap.UpdateF();
nextExploringNodeInMap.ParentNode = &exploringNodeInMap;
// 加到开放列表
nextExploringNodeInMap.IsInOpenedList = true;
m_openedNodeList.push_back(&nextExploringNodeInMap);
}
} //--end--找出探路点周围8个可行点,保存到开放列表
}
void AStar::deleteMap()
{
for (int y = 0; y < m_mapHeight; y++)
{
delete [] m_map[y];
}
delete [] m_map;
m_map = nullptr;
}