00001
00002
00003
00004
00005
00006
00007
00008
00009
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00031
00032
00033
00034
00035
00036 #include "stratagus.h"
00037
00038 #include <stdlib.h>
00039
00040 #include "pathfinder.h"
00041
00042
00043
00044
00045
00046 struct Node {
00047 char Direction;
00048 char InGoal;
00049 int CostFromStart;
00050 int CostToGoal;
00051 };
00052
00053 struct Open {
00054 int X;
00055 int Y;
00056 int O;
00057 int Costs;
00058 };
00059
00061 #define AStarCosts(sx,sy,ex,ey) std::max(abs(sx - ex), abs(sy - ey))
00062
00063
00064
00065
00066
00067
00068
00069 const int Heading2X[9] = { 0,+1,+1,+1, 0,-1,-1,-1, 0 };
00070 const int Heading2Y[9] = { -1,-1, 0,+1,+1,+1, 0,-1, 0 };
00071 const int XY2Heading[3][3] = { {7,6,5},{0,0,4},{1,2,3}};
00072
00074 static Node *AStarMatrix;
00075
00077 static int *CloseSet;
00078 static int CloseSetSize;
00079 static int Threshold;
00080 static int OpenSetMaxSize;
00081 static int AStarMatrixSize;
00082 #define MAX_CLOSE_SET_RATIO 4
00083 #define MAX_OPEN_SET_RATIO 8 // 10,16 to small
00084
00086 int AStarFixedUnitCrossingCost;
00087 int AStarMovingUnitCrossingCost = 5;
00088 bool AStarKnowUnseenTerrain = false;
00089 int AStarUnknownTerrainCost = 2;
00090
00091 static int AStarMapWidth;
00092 static int AStarMapHeight;
00093
00094 static int AStarGoalX;
00095 static int AStarGoalY;
00096
00102
00103 static Open *OpenSet;
00105 static int OpenSetSize;
00106
00107 static unsigned char *VisionTable[3];
00108 static int *VisionLookup;
00109
00110 static int (STDCALL *CostMoveToCallback)(int x, int y, void *data);
00111 static int *CostMoveToCache;
00112 static const int CacheNotSet = -5;
00113
00114
00115
00116
00117
00118 #ifdef ASTAR_PROFILE
00119
00120 #include <map>
00121 #include <windows.h>
00122 #undef max
00123 #undef min
00124 static std::map<std::string, LARGE_INTEGER> functionTimerMap;
00125 struct ProfileData {
00126 unsigned long Calls;
00127 unsigned long TotalTime;
00128 };
00129 static std::map<std::string, ProfileData> functionProfiles;
00130
00131 inline void ProfileInit()
00132 {
00133 functionTimerMap.clear();
00134 functionProfiles.clear();
00135 }
00136
00137 inline void ProfileBegin(const std::string &function)
00138 {
00139 LARGE_INTEGER counter;
00140 if (!QueryPerformanceCounter(&counter)) {
00141 return;
00142 }
00143 functionTimerMap[function] = counter;
00144 }
00145
00146 inline void ProfileEnd(const std::string &function)
00147 {
00148 LARGE_INTEGER counter;
00149 if (!QueryPerformanceCounter(&counter)) {
00150 return;
00151 }
00152 unsigned long time = (unsigned long)(counter.QuadPart - functionTimerMap[function].QuadPart);
00153 ProfileData *data = &functionProfiles[function];
00154 data->Calls++;
00155 data->TotalTime += time;
00156 }
00157
00158 inline void ProfilePrint()
00159 {
00160 LARGE_INTEGER frequency;
00161 if (!QueryPerformanceFrequency(&frequency)) {
00162 return;
00163 }
00164
00165 std::map<std::string, ProfileData>::iterator i;
00166
00167 FILE *fd = fopen("profile.txt", "wb");
00168 fprintf(fd, " total\t calls\t per\tname\n");
00169
00170 for (i = functionProfiles.begin(); i != functionProfiles.end(); ++i) {
00171 ProfileData *data = &i->second;
00172 fprintf(fd, "%9.3f\t%9lu\t%9.3f\t%s\n",
00173 (double)data->TotalTime / frequency.QuadPart * 1000.0,
00174 data->Calls,
00175 (double)data->TotalTime / frequency.QuadPart * 1000.0 / data->Calls,
00176 i->first.c_str());
00177 }
00178
00179 fclose(fd);
00180 }
00181
00182 #else
00183 #define ProfileInit()
00184 #define ProfileBegin(f)
00185 #define ProfileEnd(f)
00186 #define ProfilePrint()
00187 #endif
00188
00189
00190
00191
00192
00193
00194 static void InitVisionTable(void)
00195 {
00196 ProfileBegin("InitVisionTable");
00197
00198 int *visionlist;
00199 int maxsize;
00200 int sizex;
00201 int sizey;
00202 int maxsearchsize;
00203 int i;
00204 int VisionTablePosition;
00205 int marker;
00206 int direction;
00207 int right;
00208 int up;
00209 int repeat;
00210
00211
00212 VisionTable[0] = new unsigned char[AStarMapWidth * AStarMapWidth];
00213 VisionTable[1] = new unsigned char[AStarMapWidth * AStarMapWidth];
00214 VisionTable[2] = new unsigned char[AStarMapWidth * AStarMapWidth];
00215
00216 VisionLookup = new int[AStarMapWidth + 2];
00217
00218 visionlist = new int[AStarMapWidth * AStarMapWidth];
00219
00220
00221 maxsize = AStarMapWidth;
00222 maxsearchsize = AStarMapWidth;
00223
00224 for (sizex = 0; sizex < maxsize; ++sizex) {
00225 for (sizey = 0; sizey < maxsize; ++sizey) {
00226 visionlist[sizey * maxsize + sizex] = isqrt(sizex * sizex + sizey * sizey);
00227 }
00228 }
00229
00230 VisionLookup[0] = 0;
00231 i = 1;
00232 VisionTablePosition = 0;
00233 while (i < maxsearchsize) {
00234
00235 VisionLookup[i] = VisionTablePosition;
00236
00237 VisionTable[0][VisionTablePosition] = i;
00238 VisionTable[1][VisionTablePosition] = 0;
00239 VisionTable[2][VisionTablePosition] = 0;
00240 ++VisionTablePosition;
00241
00242
00243
00244 marker = maxsize * i;
00245 direction = 0;
00246 right = 0;
00247 up = 0;
00248
00249
00250 do {
00251 repeat = 0;
00252 do {
00253
00254
00255 if ((repeat == 0 || direction == 1) && visionlist[marker + 1] == i) {
00256 right = 1;
00257 up = 0;
00258 ++repeat;
00259 direction = 1;
00260 ++marker;
00261 } else if ((repeat == 0 || direction == 2) && visionlist[marker - maxsize] == i) {
00262 up = 1;
00263 right = 0;
00264 ++repeat;
00265 direction = 2;
00266 marker = marker - maxsize;
00267 } else if ((repeat == 0 || direction == 3) && visionlist[marker + 1 - maxsize] == i &&
00268 visionlist[marker - maxsize] != i && visionlist[marker + 1] != i) {
00269 up = 1;
00270 right = 1;
00271 ++repeat;
00272 direction = 3;
00273 marker = marker + 1 - maxsize;
00274 } else {
00275 direction = 0;
00276 break;
00277 }
00278
00279
00280
00281
00282 } while (direction && marker > (maxsize * 2));
00283 if (right || up) {
00284 VisionTable[0][VisionTablePosition] = repeat;
00285 VisionTable[1][VisionTablePosition] = right;
00286 VisionTable[2][VisionTablePosition] = up;
00287 ++VisionTablePosition;
00288 }
00289 } while (marker > (maxsize * 2));
00290 ++i;
00291 }
00292
00293 delete[] visionlist;
00294
00295 ProfileEnd("InitVisionTable");
00296 }
00297
00301 void InitAStar(int mapWidth, int mapHeight, int (STDCALL *costMoveTo)(int x, int y, void *data))
00302 {
00303
00304 Assert(!AStarMatrix);
00305
00306 AStarMapWidth = mapWidth;
00307 AStarMapHeight = mapHeight;
00308 CostMoveToCallback = costMoveTo;
00309
00310 AStarMatrixSize = sizeof(Node) * AStarMapWidth * AStarMapHeight;
00311 AStarMatrix = new Node[AStarMapWidth * AStarMapHeight];
00312 memset(AStarMatrix, 0, AStarMatrixSize);
00313
00314 Threshold = AStarMapWidth * AStarMapHeight / MAX_CLOSE_SET_RATIO;
00315 CloseSet = new int[Threshold];
00316
00317 OpenSetMaxSize = AStarMapWidth * AStarMapHeight / MAX_OPEN_SET_RATIO;
00318 OpenSet = new Open[OpenSetMaxSize];
00319
00320 CostMoveToCache = new int[AStarMapWidth * AStarMapHeight];
00321
00322 InitVisionTable();
00323 ProfileInit();
00324 }
00325
00329 void FreeAStar(void)
00330 {
00331 delete[] AStarMatrix;
00332 AStarMatrix = NULL;
00333 delete[] CloseSet;
00334 CloseSet = NULL;
00335 CloseSetSize = 0;
00336 delete[] OpenSet;
00337 OpenSet = NULL;
00338 OpenSetSize = 0;
00339 delete[] CostMoveToCache;
00340 CostMoveToCache = NULL;
00341
00342 delete[] VisionLookup;
00343 VisionLookup = NULL;
00344 delete[] VisionTable[0];
00345 VisionTable[0] = NULL;
00346 delete[] VisionTable[1];
00347 VisionTable[1] = NULL;
00348 delete[] VisionTable[2];
00349 VisionTable[2] = NULL;
00350
00351 ProfilePrint();
00352 }
00353
00357 static void AStarPrepare(void)
00358 {
00359 memset(AStarMatrix, 0, AStarMatrixSize);
00360 }
00361
00365 static void AStarCleanUp()
00366 {
00367 ProfileBegin("AStarCleanUp");
00368
00369 if (CloseSetSize >= Threshold) {
00370 AStarPrepare();
00371 } else {
00372 for (int i = 0; i < CloseSetSize; ++i) {
00373 AStarMatrix[CloseSet[i]].CostFromStart = 0;
00374 AStarMatrix[CloseSet[i]].InGoal = 0;
00375 }
00376 }
00377
00378 ProfileEnd("AStarCleanUp");
00379 }
00380
00385 #define AStarFindMinimum() (OpenSetSize - 1)
00386
00387
00391 static void AStarRemoveMinimum(int pos)
00392 {
00393 Assert(pos == OpenSetSize - 1);
00394
00395 OpenSetSize--;
00396 }
00397
00403 static int AStarAddNode(int x, int y, int o, int costs)
00404 {
00405 ProfileBegin("AStarAddNode");
00406
00407 int bigi, smalli;
00408 int midcost;
00409 int midi;
00410 int costToGoal;
00411 int midCostToGoal;
00412 int dist;
00413 int midDist;
00414
00415 if (OpenSetSize + 1 >= OpenSetMaxSize) {
00416 fprintf(stderr, "A* internal error: raise Open Set Max Size "
00417 "(current value %d)\n", OpenSetMaxSize);
00418 ProfileEnd("AStarAddNode");
00419 return PF_FAILED;
00420 }
00421
00422 costToGoal = AStarMatrix[o].CostToGoal;
00423 dist = abs(x - AStarGoalX) + abs(y - AStarGoalY);
00424
00425
00426 bigi = 0;
00427 smalli = OpenSetSize;
00428
00429
00430 while (bigi < smalli) {
00431 midi = (smalli + bigi) >> 1;
00432 midcost = OpenSet[midi].Costs;
00433 midCostToGoal = AStarMatrix[OpenSet[midi].O].CostToGoal;
00434 midDist = abs(OpenSet[midi].X - AStarGoalX) + abs(OpenSet[midi].Y - AStarGoalY);
00435 if (costs > midcost || (costs == midcost &&
00436 (costToGoal > midCostToGoal || (costToGoal == midCostToGoal &&
00437 dist > midDist)))) {
00438 smalli = midi;
00439 } else if (costs < midcost || (costs == midcost &&
00440 (costToGoal < midCostToGoal || (costToGoal == midCostToGoal &&
00441 dist < midDist)))) {
00442 if (bigi == midi) {
00443 bigi++;
00444 } else {
00445 bigi = midi;
00446 }
00447 } else {
00448 bigi = midi;
00449 smalli = midi;
00450 }
00451 }
00452
00453 if (OpenSetSize > bigi) {
00454
00455 memmove(&OpenSet[bigi+1], &OpenSet[bigi], (OpenSetSize - bigi) * sizeof(Open));
00456 }
00457
00458
00459 OpenSet[bigi].X = x;
00460 OpenSet[bigi].Y = y;
00461 OpenSet[bigi].O = o;
00462 OpenSet[bigi].Costs = costs;
00463 ++OpenSetSize;
00464
00465 ProfileEnd("AStarAddNode");
00466
00467 return 0;
00468 }
00469
00475 static void AStarReplaceNode(int pos, int costs)
00476 {
00477 ProfileBegin("AStarReplaceNode");
00478
00479 Open node;
00480
00481
00482 node = OpenSet[pos];
00483 OpenSetSize--;
00484 memmove(&OpenSet[pos], &OpenSet[pos+1], sizeof(Open) * (OpenSetSize-pos));
00485
00486
00487 AStarAddNode(node.X, node.Y, node.O, node.Costs);
00488
00489 ProfileEnd("AStarReplaceNode");
00490 }
00491
00492
00498 static int AStarFindNode(int eo)
00499 {
00500 ProfileBegin("AStarFindNode");
00501
00502 for (int i = 0; i < OpenSetSize; ++i) {
00503 if (OpenSet[i].O == eo) {
00504 ProfileEnd("AStarFindNode");
00505 return i;
00506 }
00507 }
00508 ProfileEnd("AStarFindNode");
00509 return -1;
00510 }
00511
00515 static void AStarAddToClose(int node)
00516 {
00517 if (CloseSetSize < Threshold) {
00518 CloseSet[CloseSetSize++] = node;
00519 }
00520 }
00521
00533 static int CostMoveTo(int x, int y, void *data)
00534 {
00535 int *c = &CostMoveToCache[y * AStarMapWidth + x];
00536 if (*c != CacheNotSet) {
00537 return *c;
00538 }
00539 return (*c = CostMoveToCallback(x, y, data));
00540 }
00541
00545 static int AStarMarkGoal(int gx, int gy, int gw, int gh,
00546 int tilesizex, int tilesizey, int minrange, int maxrange, void *data)
00547 {
00548 ProfileBegin("AStarMarkGoal");
00549
00550 int cx[4];
00551 int cy[4];
00552 int steps;
00553 int cycle;
00554 int x;
00555 int y;
00556 bool goal_reachable;
00557 int quad;
00558 int eo;
00559 int filler;
00560 int range;
00561 int z1, z2;
00562 bool doz1, doz2;
00563
00564 goal_reachable = false;
00565
00566 if (minrange == 0 && maxrange == 0 && gw == 0 && gh == 0) {
00567 if (gx + tilesizex >= AStarMapWidth ||
00568 gy + tilesizey >= AStarMapHeight) {
00569 ProfileEnd("AStarMarkGoal");
00570 return 0;
00571 }
00572 if (CostMoveTo(gx, gy, data) >= 0) {
00573 AStarMatrix[gx + gy * AStarMapWidth].InGoal = 1;
00574 ProfileEnd("AStarMarkGoal");
00575 return 1;
00576 } else {
00577 ProfileEnd("AStarMarkGoal");
00578 return 0;
00579 }
00580 }
00581
00582 if (minrange == 0) {
00583 int sx = std::max(gx, 0);
00584 int ex = std::min(gx + gw, AStarMapWidth - tilesizex);
00585 for (x = sx; x < ex; ++x) {
00586 int sy = std::max(gy, 0);
00587 int ey = std::min(gy + gh, AStarMapHeight - tilesizey);
00588 for (y = sy; y < ey; ++y) {
00589 if (CostMoveTo(x, y, data) >= 0) {
00590 AStarMatrix[y * AStarMapWidth + x].InGoal = 1;
00591 goal_reachable = true;
00592 }
00593 AStarAddToClose(y * AStarMapWidth + x);
00594 }
00595 }
00596 }
00597
00598 if (gw) {
00599 gw--;
00600 }
00601 if (gh) {
00602 gh--;
00603 }
00604
00605 int sx = std::max(gx, 0);
00606 int ex = std::min(gx + gw, AStarMapWidth - tilesizex);
00607 int sy = std::max(gy, 0);
00608 int ey = std::min(gy + gh, AStarMapHeight - tilesizey);
00609
00610
00611 for (range = minrange; range <= maxrange; ++range) {
00612 z1 = gy - range;
00613 z2 = gy + range + gh;
00614 doz1 = z1 >= 0 && z1 + tilesizex - 1 < AStarMapHeight;
00615 doz2 = z2 >= 0 && z2 + tilesizey - 1 < AStarMapHeight;
00616 if (doz1 || doz2) {
00617
00618 for (x = sx; x <= ex; ++x) {
00619 if (doz1 && CostMoveTo(x, z1, data) >= 0) {
00620 AStarMatrix[z1 * AStarMapWidth + x].InGoal = 1;
00621 AStarAddToClose(z1 * AStarMapWidth + x);
00622 goal_reachable = true;
00623 }
00624 if (doz2 && CostMoveTo(x, z2, data) >= 0) {
00625 AStarMatrix[z2 * AStarMapWidth + x].InGoal = 1;
00626 AStarAddToClose(z2 * AStarMapWidth + x);
00627 goal_reachable = true;
00628 }
00629 }
00630 }
00631 z1 = gx - range;
00632 z2 = gx + gw + range;
00633 doz1 = z1 >= 0 && z1 + tilesizex - 1 < AStarMapWidth;
00634 doz2 = z2 >= 0 && z2 + tilesizex - 1 < AStarMapWidth;
00635 if (doz1 || doz2) {
00636
00637 for (y = sy; y <= ey; ++y) {
00638 if (doz1 && CostMoveTo(z1, y, data) >= 0) {
00639 AStarMatrix[y * AStarMapWidth + z1].InGoal = 1;
00640 AStarAddToClose(y * AStarMapWidth + z1);
00641 goal_reachable = true;
00642 }
00643 if (doz2 && CostMoveTo(z2, y, data) >= 0) {
00644 AStarMatrix[y * AStarMapWidth + z2].InGoal = 1;
00645 AStarAddToClose(y * AStarMapWidth + z2);
00646 goal_reachable = true;
00647 }
00648 }
00649 }
00650 }
00651
00652
00653
00654
00655
00656 steps = VisionLookup[minrange];
00657
00658 while (VisionTable[0][steps] <= maxrange) {
00659
00660 cx[0] = gx + gw;
00661 cy[0] = gy - VisionTable[0][steps];
00662
00663 cx[1] = gx;
00664 cy[1] = gy - VisionTable[0][steps];
00665
00666 cx[2] = gx;
00667 cy[2] = gy + VisionTable[0][steps]+gh;
00668
00669 cx[3] = gx + gw;
00670 cy[3] = gy + VisionTable[0][steps]+gh;
00671
00672 ++steps;
00673 while (VisionTable[1][steps] != 0 || VisionTable[2][steps] != 0) {
00674
00675 cycle = 0;
00676 while (cycle++ < VisionTable[0][steps]) {
00677
00678 if (VisionTable[1][steps] == VisionTable[2][steps]) {
00679
00680 for (quad = 0; quad < 4; ++quad) {
00681 if (quad < 2) {
00682 filler = 1;
00683 } else {
00684 filler = -1;
00685 }
00686 if (cx[quad] >= 0 && cx[quad] + tilesizex - 1 < AStarMapWidth &&
00687 cy[quad] + filler >= 0 && cy[quad] + filler + tilesizey - 1 < AStarMapHeight &&
00688 CostMoveTo(cx[quad], cy[quad] + filler, data) >= 0) {
00689 eo = (cy[quad] + filler) * AStarMapWidth + cx[quad];
00690 AStarMatrix[eo].InGoal = 1;
00691 AStarAddToClose(eo);
00692 goal_reachable = true;
00693 }
00694 }
00695 }
00696
00697 cx[0] += VisionTable[1][steps];
00698 cy[0] += VisionTable[2][steps];
00699 cx[1] -= VisionTable[1][steps];
00700 cy[1] += VisionTable[2][steps];
00701 cx[2] -= VisionTable[1][steps];
00702 cy[2] -= VisionTable[2][steps];
00703 cx[3] += VisionTable[1][steps];
00704 cy[3] -= VisionTable[2][steps];
00705
00706
00707 for (quad = 0; quad < 4; ++quad) {
00708 if (cx[quad] >= 0 && cx[quad] + tilesizex - 1 < AStarMapWidth &&
00709 cy[quad] >= 0 && cy[quad] + tilesizey - 1 < AStarMapHeight &&
00710 CostMoveTo(cx[quad], cy[quad], data) >= 0) {
00711 eo = cy[quad] * AStarMapWidth + cx[quad];
00712 AStarMatrix[eo].InGoal = 1;
00713 AStarAddToClose(eo);
00714 goal_reachable = true;
00715 }
00716 }
00717 }
00718 ++steps;
00719 }
00720 }
00721
00722 ProfileEnd("AStarMarkGoal");
00723 return goal_reachable;
00724 }
00725
00731 static int AStarSavePath(int startX, int startY, int endX, int endY, char *path, int pathLen)
00732 {
00733 ProfileBegin("AStarSavePath");
00734
00735 int currX, currY;
00736 int fullPathLength;
00737 int pathPos;
00738 int direction;
00739
00740
00741 fullPathLength = 0;
00742 currX = endX;
00743 currY = endY;
00744 while (currX != startX || currY != startY) {
00745 direction = AStarMatrix[currY * AStarMapWidth + currX].Direction;
00746 currX -= Heading2X[direction];
00747 currY -= Heading2Y[direction];
00748 fullPathLength++;
00749 }
00750
00751
00752 if (path) {
00753 pathLen = std::min(fullPathLength, pathLen);
00754 pathPos = fullPathLength;
00755 currX = endX;
00756 currY = endY;
00757 while ((currX != startX || currY != startY) && path != NULL) {
00758 direction = AStarMatrix[currY * AStarMapWidth + currX].Direction;
00759 currX -= Heading2X[direction];
00760 currY -= Heading2Y[direction];
00761 --pathPos;
00762 if (pathPos < pathLen) {
00763 path[pathLen - pathPos - 1] = direction;
00764 }
00765 }
00766 }
00767
00768 ProfileEnd("AStarSavePath");
00769 return fullPathLength;
00770 }
00771
00776 static int AStarFindSimplePath(int sx, int sy, int gx, int gy, int gw, int gh,
00777 int tilesizex, int tilesizey, int minrange, int maxrange, char *path, int pathlen, void *data)
00778 {
00779 ProfileBegin("AStarFindSimplePath");
00780
00781 if (gx == sx && gy == sy && minrange == 0) {
00782 ProfileEnd("AStarFindSimplePath");
00783 return PF_REACHED;
00784 }
00785
00786
00787 if (gx <= sx && sx <= gx + gw - 1 &&
00788 gy <= sy && sy <= gy + gh - 1) {
00789 return PF_FAILED;
00790 }
00791
00792 int dx = abs(gx - sx);
00793 int dy = abs(gy - sy);
00794 int distance = isqrt(dx * dx + dy * dy);
00795
00796
00797 if (minrange <= distance && distance <= maxrange) {
00798 ProfileEnd("AStarFindSimplePath");
00799 return PF_REACHED;
00800 }
00801
00802 if (dx <= 1 && dy <= 1) {
00803
00804 if (CostMoveTo(gx, gy, data) == -1) {
00805 ProfileEnd("AStarFindSimplePath");
00806 return PF_UNREACHABLE;
00807 }
00808
00809 if (path) {
00810 path[0] = XY2Heading[gx - sx + 1][gy - sy + 1];
00811 }
00812 ProfileEnd("AStarFindSimplePath");
00813 return 1;
00814 }
00815
00816 ProfileEnd("AStarFindSimplePath");
00817 return PF_FAILED;
00818 }
00819
00823 int AStarFindPath(int sx, int sy, int gx, int gy, int gw, int gh,
00824 int tilesizex, int tilesizey, int minrange, int maxrange, char *path, int pathlen, void *data)
00825 {
00826 ProfileBegin("AStarFindPath");
00827
00828 int i;
00829 int j;
00830 int o;
00831 int ex;
00832 int ey;
00833 int eo;
00834 int x;
00835 int y;
00836 int px;
00837 int py;
00838 int shortest;
00839
00840 int new_cost;
00841 int costToGoal;
00842 int path_length;
00843 int ret = PF_FAILED;
00844
00845 AStarGoalX = gx;
00846 AStarGoalY = gy;
00847
00848
00849
00850
00851 i = AStarFindSimplePath(sx, sy, gx, gy, gw, gh, tilesizex, tilesizey,
00852 minrange, maxrange, path, pathlen, data);
00853 if (i != PF_FAILED) {
00854 ret = i;
00855 goto Cleanup;
00856 }
00857
00858
00859
00860
00861 AStarCleanUp();
00862
00863 for (i = 0; i < AStarMapWidth * AStarMapHeight; ++i) {
00864 CostMoveToCache[i] = CacheNotSet;
00865 }
00866
00867 OpenSetSize = 0;
00868 CloseSetSize = 0;
00869 x = sx;
00870 y = sy;
00871
00872 if (!AStarMarkGoal(gx, gy, gw, gh, tilesizex, tilesizey,
00873 minrange, maxrange, data)) {
00874
00875 ret = PF_UNREACHABLE;
00876 goto Cleanup;
00877 }
00878
00879 eo = y * AStarMapWidth + x;
00880
00881
00882 AStarMatrix[eo].CostFromStart = 1;
00883
00884 AStarMatrix[eo].Direction = 8;
00885
00886
00887 costToGoal = AStarCosts(x, y, gx, gy);
00888 AStarMatrix[eo].CostToGoal = costToGoal;
00889 if (AStarAddNode(x, y, eo, 1 + costToGoal) == PF_FAILED) {
00890 ret = PF_FAILED;
00891 goto Cleanup;
00892 }
00893 AStarAddToClose(OpenSet[0].O);
00894 if (AStarMatrix[eo].InGoal) {
00895 ret = PF_REACHED;
00896 goto Cleanup;
00897 }
00898
00899
00900
00901
00902
00903
00904 while (1) {
00905
00906
00907
00908 shortest = AStarFindMinimum();
00909 x = OpenSet[shortest].X;
00910 y = OpenSet[shortest].Y;
00911 o = OpenSet[shortest].O;
00912
00913 AStarRemoveMinimum(shortest);
00914
00915
00916
00917 if (AStarMatrix[o].InGoal == 1) {
00918 ex = x;
00919 ey = y;
00920 break;
00921 }
00922
00923 #if 0
00924
00925
00926
00927 if (!counter--) {
00928
00929
00930
00931 AstarDebugPrint("way too long\n");
00932 ret = PF_FAILED;
00933 goto Cleanup;
00934 }
00935 #endif
00936
00937
00938
00939
00940
00941 px = x - Heading2X[(int)AStarMatrix[x + AStarMapWidth * y].Direction];
00942 py = y - Heading2Y[(int)AStarMatrix[x + AStarMapWidth * y].Direction];
00943
00944 for (i = 0; i < 8; ++i) {
00945 ex = x + Heading2X[i];
00946 ey = y + Heading2Y[i];
00947
00948
00949
00950
00951 if (ex == px && ey == py) {
00952 continue;
00953 }
00954
00955
00956
00957 if (ex < 0 || ex + tilesizex - 1 >= AStarMapWidth ||
00958 ey < 0 || ey + tilesizey - 1 >= AStarMapHeight) {
00959 continue;
00960 }
00961
00962
00963
00964
00965 new_cost = CostMoveTo(ex, ey, data);
00966 if (new_cost == -1) {
00967
00968 continue;
00969 }
00970
00971
00972 new_cost++;
00973 eo = ey * AStarMapWidth + ex;
00974 new_cost += AStarMatrix[o].CostFromStart;
00975 if (AStarMatrix[eo].CostFromStart == 0) {
00976
00977 AStarMatrix[eo].CostFromStart = new_cost;
00978 AStarMatrix[eo].Direction = i;
00979 costToGoal = AStarCosts(ex, ey, gx, gy);
00980 AStarMatrix[eo].CostToGoal = costToGoal;
00981 if (AStarAddNode(ex, ey, eo, AStarMatrix[eo].CostFromStart + costToGoal) == PF_FAILED) {
00982 ret = PF_FAILED;
00983 goto Cleanup;
00984 }
00985
00986 AStarAddToClose(eo);
00987 } else if (new_cost < AStarMatrix[eo].CostFromStart) {
00988
00989
00990 AStarMatrix[eo].CostFromStart = new_cost;
00991 AStarMatrix[eo].Direction = i;
00992
00993 j = AStarFindNode(eo);
00994 if (j == -1) {
00995 costToGoal = AStarCosts(ex, ey, gx, gy);
00996 AStarMatrix[eo].CostToGoal = costToGoal;
00997 if (AStarAddNode(ex, ey, eo,
00998 AStarMatrix[eo].CostFromStart + costToGoal) == PF_FAILED) {
00999 ret = PF_FAILED;
01000 goto Cleanup;
01001 }
01002 } else {
01003 costToGoal = AStarCosts(ex, ey, gx, gy);
01004 AStarMatrix[eo].CostToGoal = costToGoal;
01005 AStarReplaceNode(j, AStarMatrix[eo].CostFromStart + costToGoal);
01006 }
01007
01008 }
01009 }
01010 if (OpenSetSize <= 0) {
01011 ret = PF_UNREACHABLE;
01012 goto Cleanup;
01013 }
01014 }
01015
01016 path_length = AStarSavePath(sx, sy, ex, ey, path, pathlen);
01017
01018 ret = path_length;
01019
01020 Cleanup:
01021 ProfileEnd("AStarFindPath");
01022 return ret;
01023 }
01024
01025 struct StatsNode
01026 {
01027 StatsNode() : Direction(0), InGoal(0), CostFromStart(0), Costs(0) {}
01028
01029 int Direction;
01030 int InGoal;
01031 int CostFromStart;
01032 int Costs;
01033 int CostToGoal;
01034 };
01035
01036 StatsNode *AStarGetStats()
01037 {
01038 StatsNode *stats = new StatsNode[AStarMapWidth * AStarMapHeight];
01039 StatsNode *s = stats;
01040 Node *m = AStarMatrix;
01041
01042 for (int j = 0; j < AStarMapHeight; ++j) {
01043 for (int i = 0; i < AStarMapWidth; ++i) {
01044 s->Direction = m->Direction;
01045 s->InGoal = m->InGoal;
01046 s->CostFromStart = m->CostFromStart;
01047 s->CostToGoal = m->CostToGoal;
01048 ++s;
01049 ++m;
01050 }
01051 }
01052
01053 for (int i = 0; i < OpenSetSize; ++i) {
01054 stats[OpenSet[i].O].Costs = OpenSet[i].Costs;
01055 }
01056
01057 return stats;
01058 }
01059
01060 void AStarFreeStats(StatsNode *stats)
01061 {
01062 delete[] stats;
01063 }
01064
01065
01066
01067
01068
01069
01070 void SetAStarFixedUnitCrossingCost(int cost) {
01071 if (cost <= 3) {
01072 fprintf(stderr, "AStarFixedUnitCrossingCost must be greater than 3\n");
01073 }
01074 }
01075 int GetAStarFixedUnitCrossingCost() {
01076 return AStarFixedUnitCrossingCost;
01077 }
01078
01079
01080 void SetAStarMovingUnitCrossingCost(int cost) {
01081 if (cost <= 3) {
01082 fprintf(stderr, "AStarMovingUnitCrossingCost must be greater than 3\n");
01083 }
01084 }
01085 int GetAStarMovingUnitCrossingCost() {
01086 return AStarMovingUnitCrossingCost;
01087 }
01088
01089
01090 void SetAStarUnknownTerrainCost(int cost) {
01091 if (cost < 0) {
01092 fprintf(stderr, "AStarUnknownTerrainCost must be non-negative\n");
01093 return;
01094 }
01095 AStarUnknownTerrainCost = cost;
01096 }
01097 int GetAStarUnknownTerrainCost() {
01098 return AStarUnknownTerrainCost;
01099 }
01100