aystar.cpp
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "../../stdafx.h"
00027 #include "../../core/alloc_func.hpp"
00028 #include "aystar.h"
00029
00035 PathNode *AyStar::ClosedListIsInList(const AyStarNode *node)
00036 {
00037 return (PathNode*)this->closedlist_hash.Get(node->tile, node->direction);
00038 }
00039
00045 void AyStar::ClosedListAdd(const PathNode *node)
00046 {
00047
00048 PathNode *new_node = MallocT<PathNode>(1);
00049 *new_node = *node;
00050 this->closedlist_hash.Set(node->node.tile, node->node.direction, new_node);
00051 }
00052
00058 OpenListNode *AyStar::OpenListIsInList(const AyStarNode *node)
00059 {
00060 return (OpenListNode*)this->openlist_hash.Get(node->tile, node->direction);
00061 }
00062
00068 OpenListNode *AyStar::OpenListPop()
00069 {
00070
00071 OpenListNode *res = (OpenListNode*)this->openlist_queue.Pop();
00072 if (res != NULL) {
00073 this->openlist_hash.DeleteValue(res->path.node.tile, res->path.node.direction);
00074 }
00075
00076 return res;
00077 }
00078
00083 void AyStar::OpenListAdd(PathNode *parent, const AyStarNode *node, int f, int g)
00084 {
00085
00086 OpenListNode *new_node = MallocT<OpenListNode>(1);
00087 new_node->g = g;
00088 new_node->path.parent = parent;
00089 new_node->path.node = *node;
00090 this->openlist_hash.Set(node->tile, node->direction, new_node);
00091
00092
00093 this->openlist_queue.Push(new_node, f);
00094 }
00095
00099 void AyStar::CheckTile(AyStarNode *current, OpenListNode *parent)
00100 {
00101 int new_f, new_g, new_h;
00102 PathNode *closedlist_parent;
00103 OpenListNode *check;
00104
00105
00106 if (this->ClosedListIsInList(current) != NULL) return;
00107
00108
00109 new_g = this->CalculateG(this, current, parent);
00110
00111 if (new_g == AYSTAR_INVALID_NODE) return;
00112
00113
00114 assert(new_g >= 0);
00115
00116 new_g += parent->g;
00117 if (this->max_path_cost != 0 && (uint)new_g > this->max_path_cost) return;
00118
00119
00120 new_h = this->CalculateH(this, current, parent);
00121
00122 assert(new_h >= 0);
00123
00124
00125 new_f = new_g + new_h;
00126
00127
00128 closedlist_parent = this->ClosedListIsInList(&parent->path.node);
00129
00130
00131 check = this->OpenListIsInList(current);
00132 if (check != NULL) {
00133 uint i;
00134
00135 if (new_g > check->g) return;
00136 this->openlist_queue.Delete(check, 0);
00137
00138 check->g = new_g;
00139 check->path.parent = closedlist_parent;
00140
00141 for (i = 0; i < lengthof(current->user_data); i++) {
00142 check->path.node.user_data[i] = current->user_data[i];
00143 }
00144
00145 this->openlist_queue.Push(check, new_f);
00146 } else {
00147
00148 this->OpenListAdd(closedlist_parent, current, new_f, new_g);
00149 }
00150 }
00151
00161 int AyStar::Loop()
00162 {
00163 int i;
00164
00165
00166 OpenListNode *current = this->OpenListPop();
00167
00168 if (current == NULL) return AYSTAR_EMPTY_OPENLIST;
00169
00170
00171 if (this->EndNodeCheck(this, current) == AYSTAR_FOUND_END_NODE) {
00172 if (this->FoundEndNode != NULL) {
00173 this->FoundEndNode(this, current);
00174 }
00175 free(current);
00176 return AYSTAR_FOUND_END_NODE;
00177 }
00178
00179
00180 this->ClosedListAdd(¤t->path);
00181
00182
00183 this->GetNeighbours(this, current);
00184
00185
00186 for (i = 0; i < this->num_neighbours; i++) {
00187
00188 this->CheckTile(&this->neighbours[i], current);
00189 }
00190
00191
00192 free(current);
00193
00194 if (this->max_search_nodes != 0 && this->closedlist_hash.GetSize() >= this->max_search_nodes) {
00195
00196 return AYSTAR_LIMIT_REACHED;
00197 } else {
00198
00199 return AYSTAR_STILL_BUSY;
00200 }
00201 }
00202
00206 void AyStar::Free()
00207 {
00208 this->openlist_queue.Free(false);
00209
00210
00211 this->openlist_hash.Delete(true);
00212 this->closedlist_hash.Delete(true);
00213 #ifdef AYSTAR_DEBUG
00214 printf("[AyStar] Memory free'd\n");
00215 #endif
00216 }
00217
00222 void AyStar::Clear()
00223 {
00224
00225
00226 this->openlist_queue.Clear(false);
00227
00228 this->openlist_hash.Clear(true);
00229 this->closedlist_hash.Clear(true);
00230
00231 #ifdef AYSTAR_DEBUG
00232 printf("[AyStar] Cleared AyStar\n");
00233 #endif
00234 }
00235
00245 int AyStar::Main()
00246 {
00247 int r, i = 0;
00248
00249
00250 while ((r = this->Loop()) == AYSTAR_STILL_BUSY && (this->loops_per_tick == 0 || ++i < this->loops_per_tick)) { }
00251 #ifdef AYSTAR_DEBUG
00252 switch (r) {
00253 case AYSTAR_FOUND_END_NODE: printf("[AyStar] Found path!\n"); break;
00254 case AYSTAR_EMPTY_OPENLIST: printf("[AyStar] OpenList run dry, no path found\n"); break;
00255 case AYSTAR_LIMIT_REACHED: printf("[AyStar] Exceeded search_nodes, no path found\n"); break;
00256 default: break;
00257 }
00258 #endif
00259 if (r != AYSTAR_STILL_BUSY) {
00260
00261 this->Clear();
00262 }
00263
00264 switch (r) {
00265 case AYSTAR_FOUND_END_NODE: return AYSTAR_FOUND_END_NODE;
00266 case AYSTAR_EMPTY_OPENLIST:
00267 case AYSTAR_LIMIT_REACHED: return AYSTAR_NO_PATH;
00268 default: return AYSTAR_STILL_BUSY;
00269 }
00270 }
00271
00280 void AyStar::AddStartNode(AyStarNode *start_node, uint g)
00281 {
00282 #ifdef AYSTAR_DEBUG
00283 printf("[AyStar] Starting A* Algorithm from node (%d, %d, %d)\n",
00284 TileX(start_node->tile), TileY(start_node->tile), start_node->direction);
00285 #endif
00286 this->OpenListAdd(NULL, start_node, 0, g);
00287 }
00288
00293 void AyStar::Init(Hash_HashProc hash, uint num_buckets)
00294 {
00295
00296 this->openlist_hash.Init(hash, num_buckets);
00297 this->closedlist_hash.Init(hash, num_buckets);
00298
00299
00300
00301
00302
00303 this->openlist_queue.Init(102400);
00304 }