1 #ifndef __SPFA__H
2 #define __SPFA__H
3
4 #include <deque>
5 #include "AIDefine.h"
6
7 class SPFA
8 {
9 public:
10 SPFA()
11 {
12 m_nodeArr = NULL;
13 m_able = false;
14 }
15 ~SPFA()
16 {
17 if(NULL != m_nodeArr)
18 {
19 delete[] m_nodeArr;
20 m_nodeArr = NULL;
21 }
22 }
23 static bool find(const PointI &size, const PointI &start, const PointI &end, AI_VisitFun visitFun, Path **path = NULL,
24 EFindType findType = EFIND_TYPE8, AI_DitanceFun fun = AI_Ditance1)
25 {
26 SPFA spfa;
27 if(spfa.init(size, end, visitFun, findType, fun))
28 {
29 return spfa.findPath(start, path);
30 }
31 if(NULL != path){*path = new Path(false, 0.0f);}
32 return false;
33 }
34 bool init(const PointI &size, const PointI &end, AI_VisitFun visitFun, EFindType findType = EFIND_TYPE8, AI_DitanceFun fun = AI_Ditance1)
35 {
36 if(size.x <= 0 || size.y <= 0 || end.x < 0 || end.y < 0 || end.x >= size.x || end.y >= size.y)
37 {
38 return false;
39 }
40 m_able = true;
41 m_size.x = size.x; m_size.y = size.y;
42 m_end.x = end.x; m_end.y = end.y;
43 if(NULL != m_nodeArr){delete m_nodeArr; m_nodeArr = NULL;}
44 m_nodeArr = new Info[size.x * size.y];
45 std::deque<Info*> Q;
46 Info *cur, *temp;
47 PointI pos;
48 cur = &m_nodeArr[end.y * size.x + end.x];
49 cur->x = end.x; cur->y = end.y; cur->dis = 0; cur->visit = 1; cur->visited = true;
50 cur->path.x = end.x; cur->path.y = end.y; cur->hasPath = true;
51 Q.push_back(cur);
52
53 float cost;
54 while(!Q.empty())
55 {
56 cur = Q.front();
57 Q.pop_front();
58 for(int i = 0; i < findType; ++i)
59 {
60 pos.x = cur->x + AI_FindHelpPoint[i].x;pos.y = cur->y + AI_FindHelpPoint[i].y;
61 if(pos.x >= 0 && pos.x < size.x && pos.y >= 0 && pos.y < size.y)
62 {
63 temp = &m_nodeArr[pos.y * size.x + pos.x];
64 temp->x = pos.x; temp->y = pos.y;
65 cost = fun(cur->x, cur->y, temp->x, temp->y);
66 if(!temp->visited && AI_CheckPass(cur->x, cur->y, pos.x, pos.y, visitFun) && cur->dis + cost < temp->dis)
67 {
68 temp->dis = cur->dis + cost;
69 temp->visit += 1; temp->visited = true;
70 temp->path.x = cur->x; temp->path.y = cur->y; temp->hasPath = true;
71 if(temp->visit > 8)
72 {
73 return false;
74 }
75 if(!Q.empty())
76 {
77 if(temp->dis < Q.front()->dis){Q.push_front(temp);}
78 else{Q.push_back(temp);}
79 }else{Q.push_back(temp);}
80 }
81 }
82 }
83 cur->visited = false;
84 }
85
86 return true;
87 }
88 bool getDis(const PointI &start, float &dis)
89 {
90 dis = 0;
91 if(m_able)
92 {
93 if(start.x == m_end.x && start.y == m_end.y)
94 {
95 return true;
96 }
97 if(start.x < 0 || start.x >= m_size.x || start.y < 0 || start.y >= m_size.y)
98 {
99 return false;
100 }
101 dis = m_nodeArr[start.y * m_size.x + start.x].dis;
102 return true;
103 }
104 return false;
105 }
106 bool findPath(const PointI &start, Path **path = NULL, bool isStart = true)
107 {
108 bool result = false;
109 if(m_able)
110 {
111 Path *_path = new Path(true, 0.0f);
112 if(start.x == m_end.x && start.y == m_end.y)
113 {
114 if(NULL != path){*path = _path;}else{delete _path;}
115 return true;
116 }
117 Info *cur;
118 _path->push_back(PointI(start.x, start.y));
119 cur = &m_nodeArr[start.y * m_size.x + start.x];
120 _path->setDis(cur->dis);
121 while(true)
122 {
123 if(cur->path.x == m_end.x && cur->path.y == m_end.y)
124 {
125 result = true;
126 break;
127 }
128 if(isStart){_path->push_back(PointI(cur->path.x, cur->path.y));}
129 else{_path->push_front(PointI(cur->path.x, cur->path.y));}
130 cur = &m_nodeArr[cur->path.y * m_size.x + cur->path.x];
131 }
132 if(!result){delete _path; _path = new Path(false, 0.0f);}
133 else
134 {
135 if(isStart){_path->push_back(PointI(m_end.x, m_end.y));}
136 else{_path->push_front(PointI(m_end.x, m_end.y));}
137 }
138 if(NULL != path){*path = _path;}else{delete _path;}
139 }
140 return result;
141 }
142 private:
143 struct Info
144 {
145 Info():visit(0),dis(0x7FFFFFFF),visited(false),hasPath(false){}
146 int x, y, visit;
147 float dis;
148 bool visited, hasPath;
149 PointI path;
150 };
151 private:
152 Info *m_nodeArr;
153 PointI m_size;
154 PointI m_end;
155 bool m_able;
156 };
157
158 #endif