28#include "MapSearchAStar.h"
31#include "Pac-Man_Evolution.h"
34class MazeNode :
public CMemPME
38 MazeNode(Sint32, Sint32);
39 bool isGoal(MazeNode*);
40 bool isSameState(MazeNode*);
57 bool operator() (
const MazeNode* n1,
const MazeNode* n2)
const {
return n1->f > n2->f; }
61#define COST_ORTHOGONAL 1.0f
67 pParent = pChild =
nullptr;
72MazeNode::MazeNode(Sint32 iNX, Sint32 iNY)
74 pParent = pChild =
nullptr;
79bool MazeNode::isSameState(MazeNode* pNode)
81 if((iX == pNode->iX) && (iY == pNode->iY))
return true;
85bool MazeNode::isGoal(MazeNode* pNode)
87 if((iX == pNode->iX) && (iY == pNode->iY))
return true;
93 Main::Instance().ILogMgr().get()->msg(LML_NORMAL,
" [MazeNode] Info: (%d,%d) f(%.3f)=g(%.3f)+h(%.3f)\n", iX, iY, f, g, h);
97MapSearchAStar::MapSearchAStar(GameField* GF)
103 eSS = SS_NOT_INITIALISED;
104 pNodeStart =
nullptr;
106 pNodeCurrentSolution =
nullptr;
107 iMinimumAcceptableValue = 0;
108 bCancelRequest =
false;
111 iAllocateNodeCount = 0;
118MapSearchAStar::~MapSearchAStar()
120 pGameField =
nullptr;
124MapSearchAStar::eSearchState MapSearchAStar::findPath(Sint32 iXStart, Sint32 iYStart, Sint32 iXGoal, Sint32 iYGoal, vector<MazePoint>& pPath, Sint32 iValid)
127 if(iXStart == iXGoal && iYStart == iYGoal)
return SS_INVALID;
130 iMinimumAcceptableValue = iValid;
135 iAllocateNodeCount = 0;
137 bCancelRequest =
false;
138 pNodeStart = allocateNode();
139 pNodeGoal = allocateNode();
142 pNodeStart->iX = iXStart; pNodeStart->iY = iYStart;
143 pNodeGoal->iX = iXGoal; pNodeGoal->iY = iYGoal;
145 pNodeStart->h = heuristic(pNodeStart);
146 pNodeStart->f = pNodeStart->g + pNodeStart->h;
147 pNodeStart->pParent = 0;
150 vOpenList.push_back(pNodeStart);
157 }
while(eSS == SS_SEARCHING);
160 if(eSS == SS_SUCCEEDED)
162 MazeNode* node = getSolutionStart();
166 node = getSolutionNext();
170 pPath.push_back(point);
174 std::reverse(pPath.begin(), pPath.end());
179 #ifdef DEBUG_MAPSEARCH
180 Main::Instance().ILogMgr().get()->msg(LML_NORMAL,
" [MapSearchA*] Info: iterations %d - Allocated/free nodes %d/%d - ", iAStarSteps, iAllocateNodeCount, iFreeNodeCount);
181 if(eSS == SS_FAILED) Main::Instance().ILogMgr().get()->msg(LML_NORMAL,
"Goal node not found\n");
182 else Main::Instance().ILogMgr().get()->msg(LML_NORMAL,
"Goal node found with %d steps\n", pPath.size());
188float MapSearchAStar::heuristic(MazeNode* pNode)
197 float dx = abs((
float)pNode->iX - (
float)pNodeGoal->iX);
198 float dy = abs((
float)pNode->iY - (
float)pNodeGoal->iY);
199 fHeuristic = D * (dx + dy);
202 float dx1 = (float)pNode->iX - (
float)pNodeGoal->iX;
203 float dy1 = (float)pNode->iY - (
float)pNodeGoal->iY;
204 float dx2 = (float)pNodeStart->iX - (
float)pNodeGoal->iX;
205 float dy2 = (float)pNodeStart->iY - (
float)pNodeGoal->iY;
206 cross = abs(dx1 * dy2 - dx2 * dy1);
208 fHeuristic = fHeuristic + cross * 0.001f;
213float MapSearchAStar::cost(MazeNode *successor, Sint32 x, Sint32 y)
215 float fCost = COST_ORTHOGONAL;
222void MapSearchAStar::AStarDoStep()
225 if((eSS == SS_SUCCEEDED) || (eSS == SS_FAILED))
return;
228 if(vOpenList.empty() || bCancelRequest)
236 MazeNode* n = vOpenList.front();
237 pop_heap(vOpenList.begin(), vOpenList.end(), HeapCompare_f());
238 vOpenList.pop_back();
241 if(n->isGoal(pNodeGoal))
244 pNodeGoal->pParent = n->pParent;
252 MazeNode* nodeChild = pNodeGoal;
253 MazeNode* nodeParent = pNodeGoal->pParent;
257 nodeParent->pChild = nodeChild;
258 nodeChild = nodeParent;
259 nodeParent = nodeParent->pParent;
260 }
while(nodeChild != pNodeStart);
274 bool ret = getSuccessors(n, n->pParent);
278 for(vector< MazeNode * >::iterator successor = vSuccessors.begin(); successor != vSuccessors.end(); ++successor)
280 freeNode((*successor));
288 eSS = SS_OUT_OF_MEMORY;
293 for(vector< MazeNode * >::iterator successor = vSuccessors.begin(); successor != vSuccessors.end(); ++successor)
295 float newg = n->g + cost((*successor), n->iX, n->iY);
302 vector< MazeNode * >::iterator openlist_result;
303 for(openlist_result = vOpenList.begin(); openlist_result != vOpenList.end(); ++openlist_result)
305 if((*openlist_result)->isSameState((*successor)))
break;
307 if(openlist_result != vOpenList.end())
310 if((*openlist_result)->g <= newg)
312 freeNode((*successor));
318 vector< MazeNode * >::iterator closedlist_result;
319 for(closedlist_result = vClosedList.begin(); closedlist_result != vClosedList.end(); ++closedlist_result)
321 if((*closedlist_result)->isSameState((*successor)))
break;
324 if(closedlist_result != vClosedList.end())
327 if((*closedlist_result)->g <= newg)
330 freeNode((*successor));
336 (*successor)->pParent = n;
337 (*successor)->g = newg;
338 (*successor)->h = heuristic((*successor));
339 (*successor)->f = (*successor)->g + (*successor)->h;
342 if(closedlist_result != vClosedList.end())
345 freeNode((*closedlist_result));
346 vClosedList.erase(closedlist_result);
350 if(openlist_result != vOpenList.end())
352 freeNode((*openlist_result));
353 vOpenList.erase(openlist_result);
356 make_heap(vOpenList.begin(), vOpenList.end(), HeapCompare_f());
360 vOpenList.push_back((*successor));
363 push_heap(vOpenList.begin(), vOpenList.end(), HeapCompare_f());
367 vClosedList.push_back(n);
373bool MapSearchAStar::addSuccessor(MazeNode* State)
375 MazeNode* node = allocateNode();
379 vSuccessors.push_back(node);
387bool MapSearchAStar::getSuccessors(MazeNode *current, MazeNode *parent_node)
390 Sint32 parent_x = -1;
391 Sint32 parent_y = -1;
395 parent_x = parent_node->iX;
396 parent_y = parent_node->iY;
400 if((pGameField->getState(current->iX - 1, current->iY) >= iMinimumAcceptableValue) && !((parent_x == current->iX - 1) && (parent_y == current->iY)))
402 NewNode = MazeNode(current->iX - 1, current->iY);
403 addSuccessor(&NewNode);
406 if((pGameField->getState(current->iX + 1, current->iY) >= iMinimumAcceptableValue) && !((parent_x == current->iX + 1) && (parent_y == current->iY)))
408 NewNode = MazeNode(current->iX + 1, current->iY);
409 addSuccessor(&NewNode);
412 if((pGameField->getState(current->iX, current->iY - 1) >= iMinimumAcceptableValue) && !((parent_x == current->iX) && (parent_y == current->iY - 1)))
414 NewNode = MazeNode(current->iX, current->iY - 1);
415 addSuccessor(&NewNode);
418 if((pGameField->getState(current->iX, current->iY + 1) >= iMinimumAcceptableValue) && !((parent_x == current->iX) && (parent_y == current->iY + 1)))
420 NewNode = MazeNode(current->iX, current->iY + 1);
421 addSuccessor(&NewNode);
427void MapSearchAStar::cancelSearch()
429 bCancelRequest =
true;
433MazeNode* MapSearchAStar::allocateNode()
435 iAllocateNodeCount++;
436 MazeNode* p =
new(std::nothrow) MazeNode;
441void MapSearchAStar::freeNode(MazeNode* node)
448void MapSearchAStar::freeAllNodes()
451 vector<MazeNode*>::iterator iterOpen = vOpenList.begin();
452 while(iterOpen != vOpenList.end())
454 MazeNode* n = (*iterOpen);
461 vector<MazeNode*>::iterator iterClosed;
462 for(iterClosed = vClosedList.begin(); iterClosed != vClosedList.end(); ++iterClosed)
464 MazeNode* n = (*iterClosed);
471void MapSearchAStar::freeUnusedNodes()
474 vector<MazeNode*>::iterator iterOpen = vOpenList.begin();
475 while(iterOpen != vOpenList.end())
477 MazeNode* n = (*iterOpen);
478 if(!n->pChild) { freeNode(n); n =
nullptr; }
484 vector<MazeNode*>::iterator iterClosed;
485 for(iterClosed = vClosedList.begin(); iterClosed != vClosedList.end(); ++iterClosed)
487 MazeNode* n = (*iterClosed);
488 if(!n->pChild) { freeNode(n); n =
nullptr; }
494void MapSearchAStar::freeSolutionNodes()
496 MazeNode* n = pNodeStart;
497 if(pNodeStart->pChild)
505 }
while(n != pNodeGoal);
512 freeNode(pNodeStart);
519MazeNode* MapSearchAStar::getSolutionStart()
521 pNodeCurrentSolution = pNodeStart;
522 if(pNodeStart)
return pNodeStart;
527MazeNode* MapSearchAStar::getSolutionNext()
529 if(pNodeCurrentSolution)
531 if(pNodeCurrentSolution->pChild)
533 MazeNode* child = pNodeCurrentSolution->pChild;
534 pNodeCurrentSolution = pNodeCurrentSolution->pChild;
542MazeNode* MapSearchAStar::getSolutionEnd()
544 pNodeCurrentSolution = pNodeGoal;
545 if(pNodeGoal)
return pNodeGoal;
550MazeNode* MapSearchAStar::getSolutionPrev()
552 if(pNodeCurrentSolution)
554 if(pNodeCurrentSolution->pParent)
556 MazeNode* parent = pNodeCurrentSolution->pParent;
557 pNodeCurrentSolution = pNodeCurrentSolution->pParent;
567MazeNode* MapSearchAStar::getOpenListStart()
570 return getOpenListStart(f, g, h);
572MazeNode* MapSearchAStar::getOpenListStart(
float &f,
float &g,
float &h)
574 iterDbgOpen = vOpenList.begin();
575 if(iterDbgOpen != vOpenList.end())
577 f = (*iterDbgOpen)->f;
578 g = (*iterDbgOpen)->g;
579 h = (*iterDbgOpen)->h;
580 return (*iterDbgOpen);
586MazeNode* MapSearchAStar::getOpenListNext()
589 return getOpenListNext(f, g, h);
591MazeNode* MapSearchAStar::getOpenListNext(
float &f,
float &g,
float &h)
594 if(iterDbgOpen != vOpenList.end())
596 f = (*iterDbgOpen)->f;
597 g = (*iterDbgOpen)->g;
598 h = (*iterDbgOpen)->h;
599 return (*iterDbgOpen);
605MazeNode* MapSearchAStar::getClosedListStart()
608 return getClosedListStart(f, g, h);
610MazeNode* MapSearchAStar::getClosedListStart(
float &f,
float &g,
float &h)
612 iterDbgClosed = vClosedList.begin();
613 if(iterDbgClosed != vClosedList.end())
615 f = (*iterDbgClosed)->f;
616 g = (*iterDbgClosed)->g;
617 h = (*iterDbgClosed)->h;
618 return (*iterDbgClosed);
624MazeNode* MapSearchAStar::getClosedListNext()
627 return getClosedListNext(f, g, h);
629MazeNode* MapSearchAStar::getClosedListNext(
float &f,
float &g,
float &h)
632 if(iterDbgClosed != vClosedList.end())
634 f = (*iterDbgClosed)->f;
635 g = (*iterDbgClosed)->g;
636 h = (*iterDbgClosed)->h;
637 return (*iterDbgClosed);