diff --git a/source/glest_game/ai/IntrHashSet.hpp b/source/glest_game/ai/IntrHashSet.hpp deleted file mode 100644 index 6996ad59..00000000 --- a/source/glest_game/ai/IntrHashSet.hpp +++ /dev/null @@ -1,403 +0,0 @@ -// ============================================================== -// This file is part of Glest (www.glest.org) -// -// Copyright (C) 2012 Mark Vejvoda -// -// You can redistribute this code and/or modify it under -// the terms of the GNU General Public License as published -// by the Free Software Foundation; either version 2 of the -// License, or (at your option) any later version -// ============================================================== - -#ifndef __INTRUSIVE_HASH_SET_HPP__ -#define __INTRUSIVE_HASH_SET_HPP__ - -#ifndef WIN32 -#include -#endif - -#include - -/* - This is base class for values that can be - stored in intrusive hashset. - -*/ -struct IntrHashSetNodeBase{ - IntrHashSetNodeBase* ihsNextNode; -}; - -/* - Values must be allocated in (some kind of) a heap. - Not stack. - Values are also nodes in a hash table, - so deleting values that is in hash is bad thing to do. -*/ - - -/* - class TRAITS MUST implement following static members: - - bool TRAITS::isEqual(const T* a,const T* b); - uint32_t TRAITS::getHashCode(const T* a); -*/ - -template -class IntrHashSet{ -protected: - typedef T Node; - // copy constructor is protected - // values CANNOT be copied since - // they are allocated outside of this container! - IntrHashSet(const IntrHashSet&); -public: - // default constructor - // preAlloc values CANNOT be zero! - IntrHashSet(int preAlloc=128) - { - hash=new Node*[preAlloc]; - memset(hash,0,sizeof(Node*)*preAlloc); - hashSize=preAlloc; - collisionsCount=0; - } - //destructor - ~IntrHashSet() - { - if(hash) - { - delete [] hash; - } - } - //just empties container without deleting values! - void Clear() - { - collisionsCount=0; - memset(hash,0,sizeof(Node*)*hashSize); - } - - //insert allocated value - void Insert(T* value) - { - if(collisionsCount>hashSize/2) - { - Rehash(); - } - uint32_t hidx=getIndex(value); - Node*& nodePtr=hash[hidx]; - collisionsCount+=nodePtr!=0?1:0; - value->ihsNextNode=nodePtr; - nodePtr=value; - } - - //iterator - //can be used to iterate over all values of hash - //and also returned by find method and can be - //use to delete value from hash faster - class ConstIterator{ - public: - ConstIterator(const IntrHashSet* argHash):node(0),parent(0),index(0),hash(argHash){} - ConstIterator(const IntrHashSet& argHash):node(0),parent(0),index(0),hash(&argHash){} - - const T* Get()const - { - return node; - } - - bool Found()const - { - return node!=0; - } - - void Rewind() - { - index=0; - node=0; - parent=0; - } - - bool Next() - { - if(index>=hash->hashSize) - { - return false; - } - if(index==0 && node==0 && parent==0) - { - parent=&hash->hash; - node=*parent; - if(node) - { - return true; - } - } - while(node==0) - { - index++; - if(index>=hash->hashSize) - { - return false; - } - parent=hash->hash+index; - node=*parent; - if(node) - { - return true; - } - } - if(*parent!=node) - { - parent=(Node**)&(*parent)->ihsNextNode; - } - node=(Node*)node->ihsNextNode; - if(node) - { - return true; - } - return Next(); - } - - protected: - ConstIterator(const IntrHashSet* argHash,uint32_t argIndex,const Node* argNode,const Node*const* argParent): - node(argNode),parent(argParent),index(argIndex),hash(argHash){} - const Node* node; - const Node*const* parent; - uint32_t index; - const IntrHashSet* hash; - friend class IntrHashSet; - }; - - //mutable version of iterator - //however it's not good idea to modify key part of stored value - class Iterator{ - public: - Iterator(IntrHashSet* argHash):node(0),parent(0),index(0),hash(argHash){} - Iterator(IntrHashSet& argHash):node(0),parent(0),index(0),hash(&argHash){} - - T* Get() - { - return node; - } - - bool Found()const - { - return node!=0; - } - - void Rewind() - { - index=0; - node=0; - parent=0; - } - - bool Next() - { - if(index>=hash->hashSize) - { - return false; - } - if(index==0 && node==0 && parent==0) - { - parent=hash->hash; - node=*parent; - if(node) - { - return true; - } - } - while(node==0) - { - index++; - if(index>=hash->hashSize) - { - return false; - } - parent=hash->hash+index; - node=*parent; - if(node) - { - return true; - } - } - if(*parent!=node) - { - parent=(Node**)&(*parent)->ihsNextNode; - } - node=(Node*)node->ihsNextNode; - if(node) - { - return true; - } - return Next(); - } - - protected: - Iterator(IntrHashSet* argHash,uint32_t argIndex,Node* argNode,Node** argParent): - node(argNode),parent(argParent),index(argIndex),hash(argHash){} - Node* node; - Node** parent; - uint32_t index; - IntrHashSet* hash; - friend class IntrHashSet; - }; - - //constant version of find - //returned iterator can be used to obtain found value - //or delete it from hashet - - ConstIterator Find(const T& value)const - { - uint32_t hidx=getIndex(&value); - Node*const* nodePtr=&hash[hidx]; - if(!*nodePtr)return ConstIterator(0); - if(TRAITS::isEqual((*nodePtr),&value)) - { - return ConstIterator(this,hidx,*nodePtr,nodePtr); - } - Node*const* parentPtr=nodePtr; - Node* node=(Node*)(*nodePtr)->ihsNextNode; - while(node) - { - if(TRAITS::isEqual(node,&value)) - { - return ConstIterator(this,hidx,node,parentPtr); - } - parentPtr=nodePtr; - nodePtr=(Node**)&node->ihsNextNode; - node=(Node*)node->ihsNextNode; - } - return ConstIterator(0); - } - - //non constant version of find - Iterator Find(const T& value) - { - uint32_t hidx=getIndex(&value); - Node** nodePtr=&hash[hidx]; - if(!*nodePtr)return Iterator(0); - if(TRAITS::isEqual((*nodePtr),&value)) - { - return Iterator(this,hidx,*nodePtr,nodePtr); - } - Node** parentPtr=nodePtr; - Node* node=(Node*)(*nodePtr)->ihsNextNode; - while(node) - { - if(TRAITS::isEqual(node,&value)) - { - return Iterator(this,hidx,node,parentPtr); - } - parentPtr=nodePtr; - nodePtr=(Node**)&node->ihsNextNode; - node=(Node*)node->ihsNextNode; - } - return Iterator(0); - } - - //delete element from hashset 'by value' - //actual value IS NOT DEALLOCATED - //and should be deallocated separately - void Delete(const T& value) - { - uint32_t hidx=getIndex(&value); - Node** nodePtr=hash+hidx; - if(TRAITS::isEqual((*nodePtr),&value)) - { - Node* node=*nodePtr; - *nodePtr=(Node*)node->ihsNextNode; - if(*nodePtr) - { - collisionsCount--; - } - return; - } - Node* parentPtr=*nodePtr; - Node* node=(Node*)(*nodePtr)->ihsNextNode; - while(node) - { - if(TRAITS::isEqual(node,&value)) - { - parentPtr->ihsNextNode=node->ihsNextNode; - return; - } - parentPtr=node; - node=(Node*)node->ihsNextNode; - } - } - - //delete element by iterator returned from Find - //or used for iteration. - //iterator used for Delete is no longer valid - //for iteration, however element it refer to - //is still here and Get is still valid after Delete. - //actuall value also IS NOT DEALLOCATED! - - void Delete(const Iterator& hi) - { - Node** parentPtr=(Node**)hi.parent; - Node* node=(Node*)hi.node; - if(!node) - { - return; - } - if(*parentPtr==node) - { - *parentPtr=(Node*)node->ihsNextNode; - }else - { - (*parentPtr)->ihsNextNode=node->ihsNextNode; - } - if(*parentPtr) - { - collisionsCount--; - } - } - -protected: - - // get index of a bucket in a hash table - uint32_t getIndex(const T* value)const - { - uint32_t hashCode=TRAITS::getHashCode(value); - return hashCode%hashSize; - } - - // increase hash table size if there are - // too much collisions - void Rehash() - { - Node** oldHash=hash; - Node** oldHashEnd=hash+hashSize; - hashSize*=2; - hash=new Node*[hashSize]; - memset(hash,0,sizeof(Node*)*hashSize); - collisionsCount=0; - for(Node** it=oldHash;it!=oldHashEnd;it++) - { - Node* node=*it; - Node* nextNode; - while(node) - { - uint32_t hidx=getIndex(node); - Node** nodePtr=hash+hidx; - if(*nodePtr) - { - collisionsCount++; - } - nextNode=(Node*)node->ihsNextNode; - node->ihsNextNode=*nodePtr; - *nodePtr=node; - node=nextNode; - } - } - } - // hash table itself - Node** hash; - // size of hash table - size_t hashSize; - // number of collisions - int collisionsCount; - -}; - -#endif diff --git a/source/glest_game/ai/IntrHeapHash.hpp b/source/glest_game/ai/IntrHeapHash.hpp deleted file mode 100644 index 549268c4..00000000 --- a/source/glest_game/ai/IntrHeapHash.hpp +++ /dev/null @@ -1,546 +0,0 @@ -// ============================================================== -// This file is part of Glest (www.glest.org) -// -// Copyright (C) 2012 Mark Vejvoda -// -// You can redistribute this code and/or modify it under -// the terms of the GNU General Public License as published -// by the Free Software Foundation; either version 2 of the -// License, or (at your option) any later version -// ============================================================== - -#ifndef __INTRUSIVE_HEAP_HASH_SET_HPP__ -#define __INTRUSIVE_HEAP_HASH_SET_HPP__ - -#ifndef WIN32 -#include -#endif - -#include -#include "IntrHashSet.hpp" - -/* -Here is temlate class Intrusive Heap/HashSet. -Actuall values are stored in this container, -no copying is performed, so all values should -be allocated in a heap or in a storage with -lifetime as long as lifetime of container. -Values are also used as nodes of container, -so no value can be stored in two containers -of this kind simultaneously. -*/ - -/* - This is what should be done with duplicate - from hash point of view values. -*/ -enum HHDuplicatePolicy{ - hhdpReplaceOld, //replace old value. old values is not deallocated! - hhdpKeepOld, //container is not modified in this case. - hhdpInsertDuplicate //duplicates are stored in container -}; - -/* -TRAITS class MUST implement following static members: -for heap - this is something like operator< or operator> - bool TRAITS::Compare(const T* a,const T* b); -for hash - bool TRAITS::isEqual(const T* a,const T* b); - uint32_t TRAITS::getHashCode(const T& a); -*/ - -/* - This is base class for values stored in a intrusive heap hash -*/ -struct IntrHeapHashNodeBase:public IntrHashSetNodeBase{ - int ihhNodeIndex; -}; - -template -class IntrHeapHash{ -public: - //default constructor - //preAlloc value cannot be 0! - IntrHeapHash(int preAlloc=128) - { - hash=new Node*[preAlloc]; - memset(hash,0,preAlloc*sizeof(Node*)); - hashSize=preAlloc; - heap=new Node*[preAlloc]; - memset(heap,0,preAlloc*sizeof(Node*)); - heapSize=0; - heapAlloc=preAlloc; - collisionsCount=0; - } - - //guess what? destructor! - ~IntrHeapHash() - { - delete [] hash; - delete [] heap; - } - - // clear content container - // values are not deallocated! - void Clear() - { - memset(hash,0,hashSize*sizeof(Node*)); - heapSize=0; - collisionsCount=0; - } - - //insert new value into container - //return value is equal to inserted value for all policies if no duplicate detected - //in case of duplicate for keep old policy 0 is returned - //in case of duplicate for replace old policy old value is returned - T* Insert(T* value) - { - if(collisionsCount>hashSize/2) - { - Rehash(); - } - uint32_t hidx=getIndex(value); - Node*& node=hash[hidx]; - T* rv=value; - if(policy==hhdpReplaceOld || policy==hhdpKeepOld) - { - Node* ptr=FindHashNode(node,*value); - if(ptr) - { - if(policy==hhdpKeepOld) - { - return 0; - } - DeleteHashNode(hash+hidx,ptr); - rv=ptr; - } - } - value->ihhNodeIndex=heapSize; - if(node) - { - collisionsCount++; - } - value->ihsNextNode=node; - node=value; - if(heapSize==heapAlloc) - { - heapAlloc*=2; - Node** newHeap=new Node*[heapAlloc]; - memcpy(newHeap,heap,heapSize*sizeof(Node*)); - delete [] heap; - heap=newHeap; - } - heap[heapSize++]=value; - HeapPush(); - return rv; - } - - // value at the head of heap - const T* getHead()const - { - return *heap; - } - - // same as previous but non const - T* getHead() - { - return **heap; - } - - // get and remove head value of heap - T* Pop() - { - T* rv=*heap; - uint32_t hidx=getIndex(rv); - DeleteHashNode(&hash[hidx],rv); - HeapSwap(heap,heap+heapSize-1); - heapSize--; - HeapPop(); - return rv; - } - - //find value in hash - //const version - const T* Find(const T& value)const - { - uint32_t hidx=getIndex(&value); - Node* ptr=hash[hidx]; - while(ptr) - { - if(TRAITS::isEqual(ptr,&value)) - { - return ptr; - } - ptr=(Node*)ptr->ihsNextNode; - } - return 0; - } - - //find value in hash - //non const version - //it's not good idea to modify key value of hash or key value of heap however - T* Find(const T& value) - { - uint32_t hidx=getIndex(&value); - Node* ptr=hash[hidx]; - while(ptr) - { - if(TRAITS::isEqual(ptr,&value)) - { - return ptr; - } - ptr=(Node*)ptr->ihsNextNode; - } - return 0; - } - - //get from hash all values equal to given - void GetAll(const T& value,std::vector& values)const - { - uint32_t hidx=getIndex(&value); - Node* ptr=hash[hidx]; - while(ptr) - { - if(TRAITS::isEqual(ptr,&value)) - { - values.push_back(ptr); - } - ptr=(Node*)ptr->ihsNextNode; - } - } - - //delete value from hash - //deleted object returned - T* Delete(const T& value) - { - uint32_t hidx=getIndex(&value); - int idx=DeleteHashNode(hash+hidx,value); - if(idx==-1) - { - return 0; - } - if(idx==heapSize-1) - { - heapSize--; - return heap[heapSize]; - } - HeapSwap(heap+idx,heap+heapSize-1); - heapSize--; - HeapFix(idx); - return heap[heapSize]; - } - - //delete all values equal to given - void DeleteAll(const T& value) - { - uint32_t hidx=getIndex(&value); - Node** nodePtr=hash+hidx; - while(*nodePtr) - { - int idx=DeleteHashNode(nodePtr,value); - if(idx==-1) - { - return; - } - if(idx==heapSize-1) - { - heapSize--; - continue; - } - HeapSwap(heap+idx,heap+heapSize-1); - heapSize--; - HeapFix(idx); - } - } - - //get number of elements in container - size_t getSize()const - { - return heapSize; - } - - //check if container is empty - bool isEmpty()const - { - return heapSize==0; - } - - //iterator - //can/should be used like this: - //for(IHHTypeDef::Iterator it(ihh);it.Next();) - //{ - // dosomething(it.Get()) - //} - class Iterator{ - public: - Iterator(const IntrHeapHash& argHH) - { - begin=argHH.heap; - current=0; - end=argHH.heap+argHH.heapSize; - } - bool Next() - { - if(current==0) - { - current=begin; - }else - { - current++; - } - return current!=end; - } - T* Get() - { - if(current) - { - return *current; - } - return 0; - } - void Rewind() - { - current=begin; - } - protected: - typename IntrHeapHash::Node **begin,**current,**end; - }; - -protected: - - //protected copy constructor - //values cannot be copied as well as container - IntrHeapHash(const IntrHeapHash&); - - //typedef for convenience - typedef T Node; - //heap array - Node** heap; - //hash table - Node** hash; - //size of hash table - size_t hashSize; - //used size of heap - size_t heapSize; - //allocated size of heap - size_t heapAlloc; - - //count of collisions in hash - int collisionsCount; - - //get index of value in hash table - uint32_t getIndex(const T* value)const - { - uint32_t hashCode=TRAITS::getHashCode(value); - return hashCode%hashSize; - } - - //resize hash table when - //collisions count is too big - void Rehash() - { - Node** oldHash=hash; - Node** oldHashEnd=oldHash+hashSize; - hashSize*=2; - hash=new Node*[hashSize]; - memset(hash,0,hashSize*sizeof(Node*)); - collisionsCount=0; - for(Node** it=oldHash;it!=oldHashEnd;it++) - { - Node* nodePtr=*it; - while(nodePtr) - { - uint32_t hidx=getIndex(nodePtr); - Node*& hnode=hash[hidx]; - if(hnode) - { - collisionsCount++; - } - Node* next=(Node*)nodePtr->ihsNextNode; - nodePtr->ihsNextNode=hnode; - hnode=nodePtr; - nodePtr=next; - - } - } - } - - //find and delete hash node from bucket by ptr - void DeleteHashNode(Node** nodeBasePtr,Node* nodePtr) - { - if(*nodeBasePtr==nodePtr) - { - *nodeBasePtr=(Node*)nodePtr->ihsNextNode; - if(*nodeBasePtr) - { - collisionsCount--; - } - return; - } - Node* parentPtr=*nodeBasePtr; - Node* iterPtr=(Node*)parentPtr->ihsNextNode; - while(iterPtr) - { - if(iterPtr==nodePtr) - { - parentPtr->ihsNextNode=nodePtr->ihsNextNode; - collisionsCount--; - return; - } - parentPtr=iterPtr; - iterPtr=(Node*)iterPtr->ihsNextNode; - } - } - - //find and delete hash node from bucked by value - //heap index returned - int DeleteHashNode(Node** nodePtr,const T& data) - { - if(!*nodePtr)return -1; - if(TRAITS::isEqual(*nodePtr,&data)) - { - int rv=(*nodePtr)->ihhNodeIndex; - *nodePtr=(Node*)(*nodePtr)->ihsNextNode; - if(*nodePtr) - { - collisionsCount--; - } - return rv; - } - Node* parentPtr=*nodePtr; - Node* node=(Node*)(*nodePtr)->ihsNextNode; - while(node) - { - if(TRAITS::isEqual(node,&data)) - { - parentPtr->ihsNextNode=node->ihsNextNode; - collisionsCount--; - return node->ihhNodeIndex; - } - parentPtr=node; - node=(Node*)node->ihsNextNode; - } - return -1; - } - - //find hash node in a bucked by value - Node* FindHashNode(Node* nodePtr,const T& data) - { - while(nodePtr) - { - if(TRAITS::isEqual(nodePtr,&data)) - { - return nodePtr; - } - nodePtr=(Node*)nodePtr->ihsNextNode; - } - return 0; - } - - //float up tail element - void HeapPush(int didx=-1) - { - int idx=didx==-1?heapSize-1:didx; - int pidx; - Node** b=heap; - Node** i=b+idx; - Node** pi; - Node* ptr=*i; - while(idx) - { - pidx=(idx-1)/2; - pi=b+pidx; - if(TRAITS::Compare(ptr,(*pi))) - { - *i=*pi; - (*i)->ihhNodeIndex=idx; - i=pi; - idx=pidx; - }else - { - break; - } - } - *i=ptr; - ptr->ihhNodeIndex=idx; - } - //drow down element from head - void HeapPop(int idx=0) - { - if(heapSize<=1) - { - return; - } - Node **i,**b,**i1,**i2; - int cidx1,cidx2; - b=heap; - i=b+idx; - Node* ptr=*i; - while(idx=heapSize) - { - break; - } - i1=b+cidx1; - i2=b+cidx2; - if(cidx2>=heapSize || TRAITS::Compare((*i1),(*i2))) - { - if(!TRAITS::Compare(ptr,(*i1))) - { - *i=*i1; - (*i)->ihhNodeIndex=idx; - idx=cidx1; - i=i1; - }else - { - break; - } - }else - { - if(!TRAITS::Compare(ptr,(*i2))) - { - *i=*i2; - (*i)->ihhNodeIndex=idx; - idx=cidx2; - i=i2; - }else - { - break; - } - } - } - *i=ptr; - ptr->ihhNodeIndex=idx; - } - - //either drow down or float up element at middle - void HeapFix(int idx) - { - int pidx=(idx-1)/2; - if(TRAITS::Compare(heap[idx],heap[pidx])) - { - HeapPush(idx); - }else - { - HeapPop(idx); - } - } - - //swap two element fixing indeces - void HeapSwap(Node** i1,Node** i2) - { - int idx1=(*i1)->ihhNodeIndex; - int idx2=(*i2)->ihhNodeIndex; - Node* ptr=*i1; - *i1=*i2; - (*i1)->ihhNodeIndex=idx1; - (*i2)=ptr; - (*i2)->ihhNodeIndex=idx2; - } - -}; - -#endif diff --git a/source/glest_game/ai/fast_path_finder.cpp b/source/glest_game/ai/fast_path_finder.cpp deleted file mode 100644 index 1b3eeeac..00000000 --- a/source/glest_game/ai/fast_path_finder.cpp +++ /dev/null @@ -1,1156 +0,0 @@ -/*! -// ============================================================== -// This file is part of Glest (www.glest.org) -// -// Copyright (C) 2012 Mark Vejvoda -// -// You can redistribute this code and/or modify it under -// the terms of the GNU General Public License as published -// by the Free Software Foundation; either version 2 of the -// License, or (at your option) any later version -// ============================================================== - -** Copyright (c) 2007 by John W. Ratcliff mailto:jratcliff@infiniplex.net -** -** Portions of this source has been released with the PhysXViewer application, as well as -** Rocket, CreateDynamics, ODF, and as a number of sample code snippets. -** -** If you find this code useful or you are feeling particularily generous I would -** ask that you please go to http://www.amillionpixels.us and make a donation -** to Troy DeMolay. -** -** DeMolay is a youth group for young men between the ages of 12 and 21. -** It teaches strong moral principles, as well as leadership skills and -** public speaking. The donations page uses the 'pay for pixels' paradigm -** where, in this case, a pixel is only a single penny. Donations can be -** made for as small as $4 or as high as a $100 block. Each person who donates -** will get a link to their own site as well as acknowledgement on the -** donations blog located here http://www.amillionpixels.blogspot.com/ -** -** If you wish to contact me you can use the following methods: -** -** Skype Phone: 636-486-4040 (let it ring a long time while it goes through switches) -** Skype ID: jratcliff63367 -** Yahoo: jratcliff63367 -** AOL: jratcliff1961 -** email: jratcliff@infiniplex.net - -A* Algorithm Implementation using STL is -Copyright (C)2001-2005 Justin Heyes-Jones - - FixedSizeAllocator class - Copyright 2001 Justin Heyes-Jones - - This class is a constant time O(1) memory manager for objects of - a specified type. The type is specified using a template class. - - Memory is allocated from a fixed size buffer which you can specify in the - class constructor or use the default. - - Using GetFirst and GetNext it is possible to iterate through the elements - one by one, and this would be the most common use for the class. - - I would suggest using this class when you want O(1) add and delete - and you don't do much searching, which would be O(n). Structures such as binary - trees can be used instead to get O(logn) access time. - -** -** The MIT license: -** -** Permission is hereby granted, free of charge, to any person obtaining a copy -** of this software and associated documentation files (the "Software"), to deal -** in the Software without restriction, including without limitation the rights -** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -** copies of the Software, and to permit persons to whom the Software is furnished -** to do so, subject to the following conditions: -** -** The above copyright notice and this permission notice shall be included in all -** copies or substantial portions of the Software. - -** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -** WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -** CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -*/ - -#include -#include -#include -#include - -//*** IMPORTANT : READ ME FIRST !! -//*** -//*** This source code simply provides a C++ wrapper for the AStar Algorithm Implementation in STL written by Justin Heyes-Jones -//*** There is nothing wrong with Justin's code in any way, except that he uses templates. My personal programming style is -//*** to use virtual interfaces and the PIMPLE paradigm to hide the details of the implementation. -//*** -//*** To use my wrapper you simply have your own path node inherit the pure virtual interface 'AI_Node' and implement the -//*** following four methods. -//*** -//*** -//** virtual float getDistance(const AI_Node *node) = 0; // Return the distance between two nodes -//** virtual float getCost(void) = 0; // return the relative 'cost' of a node. Default should be 1. -//** virtual unsigned int getEdgeCount(void) const = 0; // Return the number of edges in a node. -//** virtual AI_Node * getEdge(int index) const = 0; // Return a pointer to the node a particular edge is connected to. -//** -//** That's all there is to it. -//** -//** Here is an example usage: -//** -//** FastAstar *fa = createFastAstar(); -//** astarStartSearch(fq,fromNode,toNode); -//** for (int i=0; i<10000; i++) -//** { -//** bool finished = astarSearchStep(fa); -//** if ( finished ) break; -//** } -//** -//** unsigned int count; -//** AI_Node **solution = getSolution(fa,count); -//** -//** ... do something you want with the answer -//** -//** releaseFastAstar(fa); -//** -//******************************* - -#include "fast_path_finder.h" -#include "IntrHeapHash.hpp" - -template class FixedSizeAllocator { - -public: - // Constants - enum { - FSA_DEFAULT_SIZE = 3000 - }; - - // This class enables us to transparently manage the extra data - // needed to enable the user class to form part of the double-linked - // list class - struct FSA_ELEMENT { - USER_TYPE UserType; - - FSA_ELEMENT *pPrev; - FSA_ELEMENT *pNext; - }; - -public: // methods - FixedSizeAllocator( unsigned int MaxElements = FSA_DEFAULT_SIZE ) : - m_MaxElements( MaxElements ), - m_pFirstUsed( NULL ) { - // Allocate enough memory for the maximum number of elements - char *pMem = new char[ m_MaxElements * sizeof(FSA_ELEMENT) ]; - m_pMemory = (FSA_ELEMENT *) pMem; - // Set the free list first pointer - m_pFirstFree = m_pMemory; - // Clear the memory - memset( m_pMemory, 0, sizeof( FSA_ELEMENT ) * m_MaxElements ); - // Point at first element - FSA_ELEMENT *pElement = m_pFirstFree; - // Set the double linked free list - for( unsigned int i=0; ipPrev = pElement-1; - pElement->pNext = pElement+1; - - pElement++; - } - - // first element should have a null prev - m_pFirstFree->pPrev = NULL; - // last element should have a null next - (pElement-1)->pNext = NULL; - } - - ~FixedSizeAllocator() { - // Free up the memory - delete [] m_pMemory; - } - - void reset() { - m_pFirstUsed = NULL; - m_pFirstFree = m_pMemory; - // Point at first element - FSA_ELEMENT *pElement = m_pFirstFree; - // Set the double linked free list - for( unsigned int i=0; ipPrev = pElement-1; - pElement->pNext = pElement+1; - - pElement++; - } - - // first element should have a null prev - m_pFirstFree->pPrev = NULL; - // last element should have a null next - (pElement-1)->pNext = NULL; - } - - // Allocate a new USER_TYPE and return a pointer to it - USER_TYPE *alloc() { - FSA_ELEMENT *pNewNode = NULL; - if( !m_pFirstFree ) { - return NULL; - } - else { - pNewNode = m_pFirstFree; - m_pFirstFree = pNewNode->pNext; - - // if the new node points to another free node then - // change that nodes prev free pointer... - if( pNewNode->pNext ) { - pNewNode->pNext->pPrev = NULL; - } - - // node is now on the used list - pNewNode->pPrev = NULL; // the allocated node is always first in the list - if( m_pFirstUsed == NULL ) { - pNewNode->pNext = NULL; // no other nodes - } - else { - m_pFirstUsed->pPrev = pNewNode; // insert this at the head of the used list - pNewNode->pNext = m_pFirstUsed; - } - - m_pFirstUsed = pNewNode; - } - - return reinterpret_cast(pNewNode); - } - - // Free the given user type - // For efficiency I don't check whether the user_data is a valid - // pointer that was allocated. I may add some debug only checking - // (To add the debug check you'd need to make sure the pointer is in - // the m_pMemory area and is pointing at the start of a node) - void free( USER_TYPE *user_data ) { - FSA_ELEMENT *pNode = reinterpret_cast(user_data); - - // manage used list, remove this node from it - if( pNode->pPrev ) { - pNode->pPrev->pNext = pNode->pNext; - } - else { - // this handles the case that we delete the first node in the used list - m_pFirstUsed = pNode->pNext; - } - - if( pNode->pNext ) { - pNode->pNext->pPrev = pNode->pPrev; - } - - // add to free list - if( m_pFirstFree == NULL ) { - // free list was empty - m_pFirstFree = pNode; - pNode->pPrev = NULL; - pNode->pNext = NULL; - } - else { - // Add this node at the start of the free list - m_pFirstFree->pPrev = pNode; - pNode->pNext = m_pFirstFree; - m_pFirstFree = pNode; - } - } - - // For debugging this displays both lists (using the prev/next list pointers) - void Debug() { - printf( "free list " ); - - FSA_ELEMENT *p = m_pFirstFree; - while( p ) { - printf( "%x!%x ", p->pPrev, p->pNext ); - p = p->pNext; - } - printf( "\n" ); - - printf( "used list " ); - - p = m_pFirstUsed; - while( p ) { - printf( "%x!%x ", p->pPrev, p->pNext ); - p = p->pNext; - } - printf( "\n" ); - } - - // Iterators - - USER_TYPE *GetFirst() { - return reinterpret_cast(m_pFirstUsed); - } - - USER_TYPE *GetNext( USER_TYPE *node ) { - return reinterpret_cast - ( - (reinterpret_cast(node))->pNext - ); - } - -public: // data - -private: // methods - -private: // data - - FSA_ELEMENT *m_pFirstFree; - FSA_ELEMENT *m_pFirstUsed; - unsigned int m_MaxElements; - FSA_ELEMENT *m_pMemory; - -}; - -/* -A* Algorithm Implementation using STL is -Copyright (C)2001-2005 Justin Heyes-Jones - -Permission is given by the author to freely redistribute and -include this code in any program as long as this credit is -given where due. - - COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, - WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, - INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE - IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE - OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND - PERFORMANCE OF THE COVERED CODE IS WITH YOU. SHOULD ANY COVERED - CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT THE INITIAL - DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY - NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF - WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE - OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER - THIS DISCLAIMER. - - Use at your own risk! - -*/ - -// used for text debugging -#include -#include -//#include -#include - -// stl includes -#include -#include -#include - -using namespace std; - -// Fixed size memory allocator can be disabled to compare performance -// Uses std new and delete instead if you turn it off -#define USE_FSA_MEMORY 1 - -// disable warning that debugging information has lines that are truncated -// occurs in stl headers -#pragma warning( disable : 4786 ) - -// The AStar search class. UserState is the users state space type -template class AStarSearch { - -public: // data - // A node represents a possible state in the search - // The user provided state type is included inside this type - -public: - - class Node : public IntrHeapHashNodeBase { - public: - Node *parent; // used during the search to record the parent of successor nodes - Node *child; // used after the search for the application to view the search in reverse - - float g; // cost of this node + it's predecessors - float h; // heuristic estimate of distance to goal - float f; // sum of cumulative cost of predecessors and self and heuristic - - Node() : - parent( 0 ), - child( 0 ), - g( 0.0f ), - h( 0.0f ), - f( 0.0f ) - { - } - - //used in AllocateNode - void clear() { - parent=0; - child=0; - g=0; - h=0; - f=0; - } - - UserState m_UserState; - }; - - // Both hashset and heaphash use this traits of node - - struct NodeTraits{ - static bool Compare(const Node* x,const Node* y) - { - return x->f < y->f; - } - static bool isEqual(const Node* x,const Node* y) - { - return x->m_UserState.IsSameState(y->m_UserState); - } - static int32 getHashCode(const Node* x) - { - return x->m_UserState.getHashCode(); - } - }; - - // For sorting the heap the STL needs compare function that lets us compare - // the f value of two nodes -// class HeapCompare_f { -// public: -// bool operator() ( const Node *x, const Node *y ) const { -// return x->f > y->f; -// } -// }; - -public: // methods - - // constructor just initialises private data - AStarSearch( ) : - m_State( SEARCH_STATE_NOT_INITIALISED ), - m_CurrentSolutionNode( NULL ), - m_Start( NULL), - m_Goal( NULL), - m_CancelRequest( false ) - { - InitPool(); - } - - ~AStarSearch() - { - // if additional pool page was allocated, let's free it - NodePoolPage* page=defaultPool.nextPage; - while(page) - { - NodePoolPage* next=page->nextPage; - delete page; - page=next; - } - } - - // call at any time to cancel the search and free up all the memory - void CancelSearch() { - m_CancelRequest = true; - } - - // Set Start and goal states - inline void SetStartAndGoalStates( UserState &Start, UserState &Goal, void *userData ) { - this->userData = userData; - - // Reinit nodes pool after previous searches - InitPool(); - - // Clear containers after previous searches - m_OpenList.Clear(); - m_ClosedList.Clear(); - - m_CancelRequest = false; - - // allocate start end goal nodes - m_Start = AllocateNode(); - m_Goal = AllocateNode(); - - m_Start->m_UserState = Start; - m_Goal->m_UserState = Goal; - - m_State = SEARCH_STATE_SEARCHING; - - // Initialise the AStar specific parts of the Start Node - // The user only needs fill out the state information - m_Start->g = 0; - m_Start->h = m_Start->m_UserState.GoalDistanceEstimate( m_Goal->m_UserState, userData ); - m_Start->f = m_Start->g + m_Start->h; - m_Start->parent = 0; - - // Push the start node on the Open list - //m_OpenList.push_back( m_Start ); // heap now unsorted - - // Sort back element into heap - //push_heap( m_OpenList.begin(), m_OpenList.end(), HeapCompare_f() ); - m_OpenList.Insert( m_Start ); - - // Initialise counter for search steps - m_Steps = 0; - } - - // Advances search one step - inline SearchState SearchStep(unsigned int &searchCount) { - searchCount = 0; - // Firstly break if the user has not initialised the search - assert( (m_State > SEARCH_STATE_NOT_INITIALISED) && (m_State < SEARCH_STATE_INVALID) ); - - // Next I want it to be safe to do a searchstep once the search has succeeded... - if( (m_State == SEARCH_STATE_SUCCEEDED) || (m_State == SEARCH_STATE_FAILED) ) { - return m_State; - } - - // Failure is defined as emptying the open list as there is nothing left to - // search... - // New: Allow user abort - if( m_OpenList.isEmpty() || m_CancelRequest ) { - //FreeAllNodes(); - m_State = SEARCH_STATE_FAILED; - return m_State; - } - - // Incremement step count - m_Steps ++; - - // Pop the best node (the one with the lowest f) - Node *n= m_OpenList.Pop(); - - //printf("n:(%d,%d):%d\n",n->m_UserState.x,n->m_UserState.y,n->f); - - // Check for the goal, once we pop that we're done - if( n->m_UserState.IsGoal( m_Goal->m_UserState ) ) - { - // The user is going to use the Goal Node he passed in - // so copy the parent pointer of n - m_Goal->parent = n->parent; - - // A special case is that the goal was passed in as the start state - // so handle that here - if( false == n->m_UserState.IsSameState( m_Start->m_UserState ) ) - { - FreeNode( n ); - - // set the child pointers in each node (except Goal which has no child) - Node *nodeChild = m_Goal; - Node *nodeParent = m_Goal->parent; - do - { - nodeParent->child = nodeChild; - - nodeChild = nodeParent; - nodeParent = nodeParent->parent; - - } - while( nodeChild != m_Start ); // Start is always the first node by definition - - } - - m_State = SEARCH_STATE_SUCCEEDED; - - return m_State; - } - else // not goal - { - - // We now need to generate the successors of this node - // The user helps us to do this, and we keep the new nodes in - // m_Successors ... - - m_Successors.clear(); // empty vector of successor nodes to n - - // User provides this functions and uses AddSuccessor to add each successor of - // node 'n' to m_Successors - n->m_UserState.GetSuccessors( this, n->parent ? &n->parent->m_UserState : NULL ); - - // Now handle each successor to the current node ... - for( typename std::vector< Node * >::iterator successor = m_Successors.begin(); successor != m_Successors.end(); successor ++ ) - { - - // The g value for this successor ... - int newg = n->g + n->m_UserState.GetCost( (*successor)->m_UserState, userData ); - - - // Now we need to find whether the node is on the open or closed lists - // If it is but the node that is already on them is better (lower g) - // then we can forget about this successor - - const Node* openlist_result=m_OpenList.Find(**successor); - - if( openlist_result ) - { - - // we found this state on open - - if( openlist_result->g <= newg ) - { - FreeNode( (*successor) ); - - // the one on Open is cheaper than this one - continue; - } - } - - typename NodeHash::Iterator closedlist_result=m_ClosedList.Find(**successor); - - if( closedlist_result.Found() ) - { - - // we found this state on closed - - if( closedlist_result.Get()->g <= newg ) - { - // the one on Closed is cheaper than this one - FreeNode( (*successor) ); - - continue; - } - } - - // This node is the best node so far with this particular state - // so lets keep it and set up its AStar specific data ... - - (*successor)->parent = n; - (*successor)->g = newg; - (*successor)->h = (*successor)->m_UserState.GoalDistanceEstimate( m_Goal->m_UserState, userData ); - (*successor)->f = (*successor)->g + (*successor)->h; - - // Remove successor from closed if it was on it - - if( closedlist_result.Found() ) - { - // remove it from Closed - Node* node=(Node*)closedlist_result.Get(); - m_ClosedList.Delete( closedlist_result ); - FreeNode( node ); - - } - - // Update old version of this node - if( openlist_result ) - { - m_OpenList.Delete( *openlist_result ); - FreeNode( (Node*)openlist_result ); - } - - m_OpenList.Insert( (*successor) ); - - } - - // push n onto Closed, as we have expanded it now - - m_ClosedList.Insert( n ); - - } // end else (not goal so expand) - - return m_State; // Succeeded bool is false at this point. - } - - // User calls this to add a successor to a list of successors - // when expanding the search frontier - inline bool AddSuccessor( UserState &State ) { - Node *node = AllocateNode(); - if( node ) { - node->m_UserState = State; - - m_Successors.push_back( node ); - - return true; - } - - return false; - } - - // Free the solution nodes - // This is done to clean up all used Node memory when you are done with the - // search - inline void FreeSolutionNodes() { - Node *n = m_Start; - if( m_Start && m_Start->child ) { - do { - Node *del = n; - n = n->child; - FreeNode( del ); - - del = NULL; - - } while( n != m_Goal ); - - FreeNode( n ); // Delete the goal - m_Start = NULL; - m_Goal = NULL; - } - else { - // if the start node is the solution we need to just delete the start and goal - // nodes - FreeNode( m_Start ); - m_Start = NULL; - FreeNode( m_Goal ); - m_Goal = NULL; - } - } - - // Functions for traversing the solution - - // Get start node - inline UserState *GetSolutionStart() { - m_CurrentSolutionNode = m_Start; - if( m_Start ) { - return &m_Start->m_UserState; - } - else { - return NULL; - } - } - - // Get next node - inline UserState *GetSolutionNext() { - if( m_CurrentSolutionNode ) { - if( m_CurrentSolutionNode->child ) { - m_CurrentSolutionNode = m_CurrentSolutionNode->child; - return &m_CurrentSolutionNode->m_UserState; - } - } - - return NULL; - } - - // Get end node - inline UserState *GetSolutionEnd() { - m_CurrentSolutionNode = m_Goal; - if( m_Goal ) { - return &m_Goal->m_UserState; - } - else { - return NULL; - } - } - - // Step solution iterator backwards - inline UserState *GetSolutionPrev() { - if( m_CurrentSolutionNode ) { - if( m_CurrentSolutionNode->parent ) { - m_CurrentSolutionNode = m_CurrentSolutionNode->parent; - return &m_CurrentSolutionNode->m_UserState; - } - } - - return NULL; - } - - // For educational use and debugging it is useful to be able to view - // the open and closed list at each step, here are two functions to allow that. -// UserState *GetOpenListStart() { -// float f,g,h; -// return GetOpenListStart( f,g,h ); -// } - -// UserState *GetOpenListStart( float &f, float &g, float &h ) { -// iterDbgOpen = m_OpenList.begin(); -// if( iterDbgOpen != m_OpenList.end() ) { -// f = (*iterDbgOpen)->f; -// g = (*iterDbgOpen)->g; -// h = (*iterDbgOpen)->h; -// return &(*iterDbgOpen)->m_UserState; -// } -// -// return NULL; -// } - -// UserState *GetOpenListNext() { -// float f,g,h; -// return GetOpenListNext( f,g,h ); -// } - -// UserState *GetOpenListNext( float &f, float &g, float &h ) { -// iterDbgOpen++; -// if( iterDbgOpen != m_OpenList.end() ) { -// f = (*iterDbgOpen)->f; -// g = (*iterDbgOpen)->g; -// h = (*iterDbgOpen)->h; -// return &(*iterDbgOpen)->m_UserState; -// } -// -// return NULL; -// } - -// UserState *GetClosedListStart() { -// float f,g,h; -// return GetClosedListStart( f,g,h ); -// } -// -// UserState *GetClosedListStart( float &f, float &g, float &h ) { -// iterDbgClosed = m_ClosedList.begin(); -// if( iterDbgClosed != m_ClosedList.end() ) { -// f = (*iterDbgClosed)->f; -// g = (*iterDbgClosed)->g; -// h = (*iterDbgClosed)->h; -// -// return &(*iterDbgClosed)->m_UserState; -// } -// -// return NULL; -// } -// -// UserState *GetClosedListNext() { -// float f,g,h; -// return GetClosedListNext( f,g,h ); -// } -// -// UserState *GetClosedListNext( float &f, float &g, float &h ) { -// iterDbgClosed++; -// if( iterDbgClosed != m_ClosedList.end() ) { -// f = (*iterDbgClosed)->f; -// g = (*iterDbgClosed)->g; -// h = (*iterDbgClosed)->h; -// -// return &(*iterDbgClosed)->m_UserState; -// } -// -// return NULL; -// } - - // Get the number of steps - - inline int GetStepCount() { return m_Steps; } - -// void EnsureMemoryFreed() { -//#if USE_FSA_MEMORY -// assert(m_AllocateNodeCount == 0); -//#endif -// } - - inline void * getUserData() { return userData; } - - // This is called when a search fails or is cancelled to free all used - // memory -// void FreeAllNodes() { -// // iterate open list and delete all nodes -// typename vector< Node * >::iterator iterOpen = m_OpenList.begin(); -// -// while( iterOpen != m_OpenList.end() ) { -// Node *n = (*iterOpen); -// FreeNode( n ); -// -// iterOpen ++; -// } -// -// m_OpenList.clear(); -// -// // iterate closed list and delete unused nodes -// typename vector< Node * >::iterator iterClosed; -// -// for( iterClosed = m_ClosedList.begin(); -// iterClosed != m_ClosedList.end(); iterClosed ++ ) { -// Node *n = (*iterClosed); -// FreeNode( n ); -// } -// -// m_ClosedList.clear(); -// -// // delete the goal -// FreeNode(m_Goal); -// m_Goal = NULL; -// } - -private: // methods - - // This call is made by the search class when the search ends. A lot of nodes may be - // created that are still present when the search ends. They will be deleted by this - // routine once the search ends -// void FreeUnusedNodes() { -// // iterate open list and delete unused nodes -// typename vector< Node * >::iterator iterOpen = m_OpenList.begin(); -// -// while( iterOpen != m_OpenList.end() ) { -// Node *n = (*iterOpen); -// if( !n->child ) { -// FreeNode( n ); -// n = NULL; -// } -// -// iterOpen ++; -// } -// -// m_OpenList.clear(); -// -// // iterate closed list and delete unused nodes -// typename vector< Node * >::iterator iterClosed; -// -// for( iterClosed = m_ClosedList.begin(); -// iterClosed != m_ClosedList.end(); iterClosed ++ ) { -// Node *n = (*iterClosed); -// if( !n->child ) { -// FreeNode( n ); -// n = NULL; -// } -// } -// -// m_ClosedList.clear(); -// } - - // Node memory management - // Node memory management - inline Node *AllocateNode() { - if(freeNodesList) { - Node* rv=freeNodesList; - freeNodesList=freeNodesList->child; - rv->clear(); - return rv; - } - if(currentPoolPage->nextFreeNode==currentPoolPage->endFreeNode) { - currentPoolPage=currentPoolPage->nextPage=new NodePoolPage; - } - Node* rv=currentPoolPage->nextFreeNode++; - rv->clear(); - return rv; - } - - inline void FreeNode( Node *node ) { - node->child=freeNodesList; - freeNodesList=node; - } - -private: // data - - // binary heap and hashset '2 in 1' container with 'open' nodes - typedef IntrHeapHash NodeHeap; - NodeHeap m_OpenList; - - // hashset for 'closed' nodes - typedef IntrHashSet NodeHash; - NodeHash m_ClosedList; - - // Successors is a vector filled out by the user each type successors to a node - // are generated - typedef std::vector< Node * > NodeVector; - NodeVector m_Successors; - - //default page size - enum { nodesPerPage=4096 }; - - // page of pool of nodes for fast allocation - struct NodePoolPage { - Node nodes[nodesPerPage]; - Node* nextFreeNode; - Node* endFreeNode; - NodePoolPage* nextPage; - - NodePoolPage() { - Init(); - nextPage=0; - } - void Init() { - nextFreeNode=nodes; - endFreeNode=nodes+nodesPerPage; - } - }; - - //first page of pool allocated along with AStarSearch object on stack - //or in data segement if static. - //should be enough for most tasks - NodePoolPage defaultPool; - //pointer to current pool page. equal to address of default pool at start - NodePoolPage* currentPoolPage; - //pointer to first node of linked list of nodes - Node* freeNodesList; - - void InitPool() { - currentPoolPage=&defaultPool; - freeNodesList=0; - NodePoolPage* ptr=currentPoolPage; - while(ptr) { - ptr->Init(); - ptr=ptr->nextPage; - } - } - - // State - SearchState m_State; - - // Counts steps - int m_Steps; - - // Start and goal state pointers - Node *m_Start; - Node *m_Goal; - Node *m_CurrentSolutionNode; - - bool m_CancelRequest; - - void *userData; -}; - -//******************************************************** -//********** C++ wrapper written by John W. Ratcliff *** -//******************************************************** - -class MapSearchNode { -public: - MapSearchNode(void) { - mNode = 0; - } - - MapSearchNode(AI_Node *point) { - mNode = point; - } - - float GoalDistanceEstimate( MapSearchNode &nodeGoal, void *userData ); - bool IsGoal( MapSearchNode &nodeGoal ); - bool GetSuccessors( AStarSearch *astarsearch, MapSearchNode *parent_node ); - float GetCost( MapSearchNode &successor, void *userData ); - bool IsSameState( const MapSearchNode &rhs ) const; - int32 getHashCode() const; - - void PrintNodeInfo(); - - AI_Node * getNode(void) const { return mNode; }; - -private: - - AI_Node *mNode; -}; - -inline bool MapSearchNode::IsSameState( const MapSearchNode &rhs ) const { - bool ret = false; - if ( mNode == rhs.mNode ) ret = true; - - return ret; -} - -inline int32 MapSearchNode::getHashCode() const { - return mNode->getHashCode(); -} - -void MapSearchNode::PrintNodeInfo() { -} - -inline float MapSearchNode::GoalDistanceEstimate( MapSearchNode &nodeGoal, void *userData ) { - return mNode->getDistance( nodeGoal.mNode, userData ); -} - -inline bool MapSearchNode::IsGoal( MapSearchNode &nodeGoal ) { - bool ret = false; - if ( mNode == nodeGoal.mNode ) ret = true; - return ret; -} - -inline bool MapSearchNode::GetSuccessors( AStarSearch *astarsearch, MapSearchNode *parent_node ) { - unsigned int count = mNode->getEdgeCount(astarsearch->getUserData()); - for (unsigned int i = 0; i < count; ++i) { - AI_Node *node = mNode->getEdge(i,astarsearch->getUserData()); - MapSearchNode newNode(node); - astarsearch->AddSuccessor( newNode ); - } - - return true; -} - -inline float MapSearchNode::GetCost( MapSearchNode &successor, void *userData ) { - return mNode->getCost(userData); -} - -class FastAstar { -public: - - FastAstar(void) { - } - - ~FastAstar(void) { - } - - inline void startSearch(AI_Node *from,AI_Node *to,void *userData) { - mSolution.clear(); - MapSearchNode start(from); - MapSearchNode end(to); - - mAstarSearch.SetStartAndGoalStates(start,end,userData); - } - - inline SearchState getLastSearchState() { - return lastSearchState; - } - - inline bool searchStep(unsigned int &searchCount) { - bool ret = false; - - SearchState state = mAstarSearch.SearchStep(searchCount); - lastSearchState = state; - - switch ( state ) { - case SEARCH_STATE_NOT_INITIALISED: - ret = true; - break; - case SEARCH_STATE_SEARCHING: - ret = false; - break; - case SEARCH_STATE_SUCCEEDED: - if ( 1 ) { - MapSearchNode *node = mAstarSearch.GetSolutionStart(); - while ( node ) { - AI_Node *ai = node->getNode(); - mSolution.push_back(ai); - node = mAstarSearch.GetSolutionNext(); - } - //mAstarSearch.FreeSolutionNodes(); - } - ret = true; - break; - case SEARCH_STATE_FAILED: - ret = true; - break; - case SEARCH_STATE_OUT_OF_MEMORY: - assert(0); - break; - case SEARCH_STATE_INVALID: - ret = true; - break; - } - - return ret; - } - - inline AI_Node ** getSolution(unsigned int &count) { - AI_Node **ret = 0; - count = 0; - if ( !mSolution.empty() ) { - count = mSolution.size(); - ret = &mSolution[0]; - } - return ret; - } - -private: - AStarSearch< MapSearchNode > mAstarSearch; - std::vector< AI_Node * > mSolution; - SearchState lastSearchState; -}; - -FastAstar * createFastAstar(void) { - FastAstar *ret = new FastAstar; - return ret; -} - -void astarStartSearch(FastAstar *astar,AI_Node *from,AI_Node *to,void *userData) { - if ( astar ) astar->startSearch(from,to,userData); -} - -bool astarSearchStep(FastAstar *astar,unsigned int &searchCount) { - bool ret = true; - if ( astar ) - ret =astar->searchStep(searchCount); - - return ret; -} - -SearchState getLastSearchState(FastAstar *astar) { - return astar->getLastSearchState(); -} - -void releaseFastAstar(FastAstar *astar) { - delete astar; -} - -AI_Node ** getSolution(FastAstar *astar,unsigned int &count) { - AI_Node **ret = 0; - if ( astar ) { - ret = astar->getSolution(count); - } - - return ret; -} diff --git a/source/glest_game/ai/fast_path_finder.h b/source/glest_game/ai/fast_path_finder.h deleted file mode 100644 index becdf864..00000000 --- a/source/glest_game/ai/fast_path_finder.h +++ /dev/null @@ -1,155 +0,0 @@ -/*! -// ============================================================== -// This file is part of Glest (www.glest.org) -// -// Copyright (C) 2012 Mark Vejvoda -// -// You can redistribute this code and/or modify it under -// the terms of the GNU General Public License as published -// by the Free Software Foundation; either version 2 of the -// License, or (at your option) any later version -// ============================================================== - -** Copyright (c) 2007 by John W. Ratcliff mailto:jratcliff@infiniplex.net -** -** Portions of this source has been released with the PhysXViewer application, as well as -** Rocket, CreateDynamics, ODF, and as a number of sample code snippets. -** -** If you find this code useful or you are feeling particularily generous I would -** ask that you please go to http://www.amillionpixels.us and make a donation -** to Troy DeMolay. -** -** DeMolay is a youth group for young men between the ages of 12 and 21. -** It teaches strong moral principles, as well as leadership skills and -** public speaking. The donations page uses the 'pay for pixels' paradigm -** where, in this case, a pixel is only a single penny. Donations can be -** made for as small as $4 or as high as a $100 block. Each person who donates -** will get a link to their own site as well as acknowledgement on the -** donations blog located here http://www.amillionpixels.blogspot.com/ -** -** If you wish to contact me you can use the following methods: -** -** Skype Phone: 636-486-4040 (let it ring a long time while it goes through switches) -** Skype ID: jratcliff63367 -** Yahoo: jratcliff63367 -** AOL: jratcliff1961 -** email: jratcliff@infiniplex.net - -A* Algorithm Implementation using STL is -Copyright (C)2001-2005 Justin Heyes-Jones - - FixedSizeAllocator class - Copyright 2001 Justin Heyes-Jones - - This class is a constant time O(1) memory manager for objects of - a specified type. The type is specified using a template class. - - Memory is allocated from a fixed size buffer which you can specify in the - class constructor or use the default. - - Using GetFirst and GetNext it is possible to iterate through the elements - one by one, and this would be the most common use for the class. - - I would suggest using this class when you want O(1) add and delete - and you don't do much searching, which would be O(n). Structures such as binary - trees can be used instead to get O(logn) access time. - -** -** The MIT license: -** -** Permission is hereby granted, free of charge, to any person obtaining a copy -** of this software and associated documentation files (the "Software"), to deal -** in the Software without restriction, including without limitation the rights -** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -** copies of the Software, and to permit persons to whom the Software is furnished -** to do so, subject to the following conditions: -** -** The above copyright notice and this permission notice shall be included in all -** copies or substantial portions of the Software. - -** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -** WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -** CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -*/ - -#ifndef FAST_ASTAR_H - -#define FAST_ASTAR_H - -//*** IMPORTANT : READ ME FIRST !! -//*** -//*** This source code simply provides a C++ wrapper for the AStar Algorithm Implementation in STL written by Justin Heyes-Jones -//*** There is nothing wrong with Justin's code in any way, except that he uses templates. My personal programming style is -//*** to use virtual interfaces and the PIMPLE paradigm to hide the details of the implementation. -//*** -//*** To use my wrapper you simply have your own path node inherit the pure virtual interface 'AI_Node' and implement the -//*** following four methods. -//*** -//*** -//** virtual float getDistance(const AI_Node *node) = 0; // Return the distance between two nodes -//** virtual float getCost(void) = 0; // return the relative 'cost' of a node. Default should be 1. -//** virtual unsigned int getEdgeCount(void) const = 0; // Return the number of edges in a node. -//** virtual AI_Node * getEdge(int index) const = 0; // Return a pointer to the node a particular edge is connected to. -//** -//** That's all there is to it. -//** -//** Here is an example usage: -//** -//** FastAstar *fa = createFastAstar(); -//** astarStartSearch(fq,fromNode,toNode); -//** for (int i=0; i<10000; i++) -//** { -//** bool finished = astarSearchStep(fa); -//** if ( finished ) break; -//** } -//** -//** unsigned int count; -//** AI_Node **solution = getSolution(fa,count); -//** -//** ... do something you want with the answer -//** -//** releaseFastAstar(fa); -//** -//******************************* -#include "data_types.h" - -using namespace Shared::Platform; - -class AI_Node -{ -public: - virtual float getDistance(const AI_Node *node,void *userData) = 0; - virtual float getCost(void *userData) = 0; - virtual unsigned int getEdgeCount(void *userData) const = 0; - virtual AI_Node * getEdge(int index,void *userData) const = 0; - virtual int32 getHashCode() const = 0; - - virtual ~AI_Node() {} -}; - -enum SearchState { - SEARCH_STATE_NOT_INITIALISED, - SEARCH_STATE_SEARCHING, - SEARCH_STATE_SUCCEEDED, - SEARCH_STATE_FAILED, - SEARCH_STATE_OUT_OF_MEMORY, - SEARCH_STATE_INVALID -}; - -class FastAstar; - -FastAstar * createFastAstar(void); // Create an instance of the FastAstar utility. -void astarStartSearch(FastAstar *astar,AI_Node *from,AI_Node *to, void *userData); // start a search. - -bool astarSearchStep(FastAstar *astar,unsigned int &searchCount); // step the A star algorithm one time. Return true if the search is completed. -SearchState getLastSearchState(FastAstar *astar); - -AI_Node ** getSolution(FastAstar *astar,unsigned int &count); // retrieve the solution. If this returns a null pointer and count of zero, it means no solution could be found. -void releaseFastAstar(FastAstar *astar); // Release the intance of the FastAstar utility. - - -#endif diff --git a/source/glest_game/ai/path_finder.cpp b/source/glest_game/ai/path_finder.cpp index af7e61d3..274b74e5 100644 --- a/source/glest_game/ai/path_finder.cpp +++ b/source/glest_game/ai/path_finder.cpp @@ -21,7 +21,6 @@ #include "command.h" #include "faction.h" #include "randomgen.h" -#include "fast_path_finder.h" #include "leak_dumper.h" using namespace std; @@ -87,9 +86,6 @@ void PathFinder::init(const Map *map) { PathFinder::~PathFinder() { for(int i = 0; i < GameConstants::maxPlayers; ++i) { factions[i].nodePool.clear(); - - releaseFastAstar(factions[i].fa); - factions[i].fa = NULL; } factions.clear(); map=NULL; @@ -229,18 +225,9 @@ TravelState PathFinder::findPath(Unit *unit, const Vec2i &finalPos, bool *wasStu uint32 searched_node_count = 0; minorDebugPathfinder = false; - //bool enableFastPathfinder = Config::getInstance().getBool("EnableFastPathFinder","false"); - bool enableFastPathfinder = false; - if(enableFastPathfinder == true) { - if(minorDebugPathfinder) printf("Fast Pathfind Unit [%d - %s] from = %s to = %s frameIndex = %d\n",unit->getId(),unit->getType()->getName().c_str(),unit->getPos().getString().c_str(),finalPos.getString().c_str(),frameIndex); + if(minorDebugPathfinder) printf("Legacy Pathfind Unit [%d - %s] from = %s to = %s frameIndex = %d\n",unit->getId(),unit->getType()->getName().c_str(),unit->getPos().getString().c_str(),finalPos.getString().c_str(),frameIndex); - ts = aStarFast(unit, finalPos, false, frameIndex, maxNodeCount,&searched_node_count); - } - else { - if(minorDebugPathfinder) printf("Legacy Pathfind Unit [%d - %s] from = %s to = %s frameIndex = %d\n",unit->getId(),unit->getType()->getName().c_str(),unit->getPos().getString().c_str(),finalPos.getString().c_str(),frameIndex); - - ts = aStar(unit, finalPos, false, frameIndex, maxNodeCount,&searched_node_count); - } + ts = aStar(unit, finalPos, false, frameIndex, maxNodeCount,&searched_node_count); //post actions switch(ts) { @@ -317,12 +304,7 @@ TravelState PathFinder::findPath(Unit *unit, const Vec2i &finalPos, bool *wasStu int maxBailoutNodeCount = (PathFinder::pathFindBailoutRadius * 2); - if(enableFastPathfinder == true) { - ts= aStarFast(unit, newFinalPos, true, frameIndex, maxBailoutNodeCount,&searched_node_count); - } - else { - ts= aStar(unit, newFinalPos, true, frameIndex, maxBailoutNodeCount,&searched_node_count); - } + ts= aStar(unit, newFinalPos, true, frameIndex, maxBailoutNodeCount,&searched_node_count); } } } @@ -344,12 +326,7 @@ TravelState PathFinder::findPath(Unit *unit, const Vec2i &finalPos, bool *wasStu //printf("$$$$ Unit BAILOUT(1) ASTAR ATTEMPT for [%d - %s] newFinalPos = [%s]\n",unit->getId(),unit->getFullName().c_str(),newFinalPos.getString().c_str()); int maxBailoutNodeCount = (PathFinder::pathFindBailoutRadius * 2); - if(enableFastPathfinder == true) { - ts= aStarFast(unit, newFinalPos, true, frameIndex, maxBailoutNodeCount,&searched_node_count); - } - else { - ts= aStar(unit, newFinalPos, true, frameIndex, maxBailoutNodeCount,&searched_node_count); - } + ts= aStar(unit, newFinalPos, true, frameIndex, maxBailoutNodeCount,&searched_node_count); } } } @@ -428,7 +405,6 @@ TravelState PathFinder::findPath(Unit *unit, const Vec2i &finalPos, bool *wasStu break; } - //if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() >= 1) printf("In [%s::%s Line: %d] fastastar took [%lld] msecs, ts = %d nodeSearchCount = %d.\n",__FILE__,__FUNCTION__,__LINE__,(long long int)chrono.getMillis(),ts,nodeSearchCount); if(minorDebugPathfinderPerformance && chrono.getMillis() >= 1) printf("Unit [%d - %s] astar took [%lld] msecs, ts = %d searched_node_count = %d.\n",unit->getId(),unit->getType()->getName().c_str(),(long long int)chrono.getMillis(),ts,searched_node_count); return ts; @@ -436,511 +412,6 @@ TravelState PathFinder::findPath(Unit *unit, const Vec2i &finalPos, bool *wasStu // ==================== PRIVATE ==================== -TravelState PathFinder::aStarFast(Unit *unit, Vec2i finalPos, bool inBailout, int frameIndex, int maxNodeCount,uint32 *searched_node_count) { - TravelState ts = tsImpossible; - - Chrono chrono; - if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled) chrono.start(); - - if(maxNodeCount < 0) { - maxNodeCount = factions[unit->getFactionIndex()].useMaxNodeCount; - - //printf("AStar set maxNodeCount = %d\n",maxNodeCount); - } - - if(maxNodeCount >= 1 && unit->getPathfindFailedConsecutiveFrameCount() >= 3) { - //int orgmaxNodeCount = maxNodeCount; - maxNodeCount = 200; - //printf("AStar maxpath cut for unit [%d - %s] to %d [orig: %d] [unit->getPathfindFailedConsecutiveFrameCount(): %d]\n",unit->getId(),unit->getFullName().c_str(), maxNodeCount,orgmaxNodeCount,unit->getPathfindFailedConsecutiveFrameCount()); - } - - UnitPathInterface *path= unit->getPath(); - int unitFactionIndex = unit->getFactionIndex(); - //factions[unitFactionIndex].nodePoolCount= 0; - //factions[unitFactionIndex].openNodesList.clear(); - //factions[unitFactionIndex].openPosList.clear(); - //factions[unitFactionIndex].closedNodesList.clear(); - - if(frameIndex >= 0) { - clearUnitPrecache(unit); - } - - // check the pre-cache to see if we can re-use a cached path - if(frameIndex < 0) { - if(factions[unitFactionIndex].precachedTravelState.find(unit->getId()) != factions[unitFactionIndex].precachedTravelState.end()) { - if(factions[unitFactionIndex].precachedTravelState[unit->getId()] == tsMoving) { - bool canMoveToCells = true; - - Vec2i lastPos = unit->getPos(); - for(int i=0; i < factions[unitFactionIndex].precachedPath[unit->getId()].size(); i++) { - Vec2i nodePos = factions[unitFactionIndex].precachedPath[unit->getId()][i]; - if(map->isInside(nodePos) == false || map->isInsideSurface(map->toSurfCoords(nodePos)) == false) { - throw megaglest_runtime_error("Pathfinder invalid node path position = " + nodePos.getString() + " i = " + intToStr(i)); - } - - //if(i < pathFindRefresh || - if(i < unit->getPathFindRefreshCellCount() || - (factions[unitFactionIndex].precachedPath[unit->getId()].size() >= pathFindExtendRefreshForNodeCount && - i < getPathFindExtendRefreshNodeCount(unitFactionIndex))) { - //!!! Test MV - if(canUnitMoveSoon(unit, lastPos, nodePos) == false) { - canMoveToCells = false; - break; - } - lastPos = nodePos; - } - else { - break; - } - } - - if(canMoveToCells == true) { - path->clear(); - UnitPathBasic *basicPathFinder = dynamic_cast(path); - - for(int i=0; i < factions[unitFactionIndex].precachedPath[unit->getId()].size(); i++) { - Vec2i nodePos = factions[unitFactionIndex].precachedPath[unit->getId()][i]; - if(map->isInside(nodePos) == false || map->isInsideSurface(map->toSurfCoords(nodePos)) == false) { - throw megaglest_runtime_error("Pathfinder invalid node path position = " + nodePos.getString() + " i = " + intToStr(i)); - } - - //if(i < pathFindRefresh || - if(i < unit->getPathFindRefreshCellCount() || - (factions[unitFactionIndex].precachedPath[unit->getId()].size() >= pathFindExtendRefreshForNodeCount && - i < getPathFindExtendRefreshNodeCount(unitFactionIndex))) { - path->add(nodePos); - } - //else if(tryLastPathCache == false) { - // break; - //} - - //if(tryLastPathCache == true && basicPathFinder) { - if(basicPathFinder) { - basicPathFinder->addToLastPathCache(nodePos); - } - } - unit->setUsePathfinderExtendedMaxNodes(false); - return factions[unitFactionIndex].precachedTravelState[unit->getId()]; - } - else { - clearUnitPrecache(unit); - } - } - else if(factions[unitFactionIndex].precachedTravelState[unit->getId()] == tsBlocked) { - path->incBlockCount(); - unit->setUsePathfinderExtendedMaxNodes(false); - return factions[unitFactionIndex].precachedTravelState[unit->getId()]; - } - } - } - else { - clearUnitPrecache(unit); - } - - const Vec2i unitPos = unit->getPos(); - finalPos= computeNearestFreePos(unit, finalPos); - - float dist= unitPos.dist(finalPos); - factions[unitFactionIndex].useMaxNodeCount = PathFinder::pathFindNodesMax; - - if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled == true && chrono.getMillis() > 4) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis()); - - // Check the previous path find cache for the unit to see if its good to - // use - const bool showConsoleDebugInfo = Config::getInstance().getBool("EnablePathfinderDistanceOutput","false"); - const bool tryLastPathCache = Config::getInstance().getBool("EnablePathfinderCache","false"); - - if(showConsoleDebugInfo || tryLastPathCache) { - if(showConsoleDebugInfo && dist > 60) printf("Distance from [%d - %s] to destination is %.2f tryLastPathCache = %d\n",unit->getId(),unit->getFullName().c_str(), dist,tryLastPathCache); - - if(tryLastPathCache == true && path != NULL) { - UnitPathBasic *basicPathFinder = dynamic_cast(path); - if(basicPathFinder != NULL && basicPathFinder->getLastPathCacheQueueCount() > 0) { - vector cachedPath= basicPathFinder->getLastPathCacheQueue(); - for(int i = 0; i < cachedPath.size(); ++i) { - Vec2i &pos1 = cachedPath[i]; - // Looking to find if the unit is in one of the cells in the cached path - if(unitPos == pos1) { - // Now see if we can re-use this path to get to the final destination - for(int j = i+1; j < cachedPath.size(); ++j) { - Vec2i &pos2 = cachedPath[j]; - bool canUnitMoveToCell = map->aproxCanMove(unit, pos1, pos2); - if(canUnitMoveToCell == true) { - if(pos2 == finalPos) { - //on the way - ts= tsMoving; - - if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled == true && chrono.getMillis() > 4) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis()); - - //store path - if(frameIndex < 0) { - basicPathFinder->clear(); - } - - int pathCount=0; - for(int k=i+1; k <= j; k++) { - if(k >= cachedPath.size()) { - throw megaglest_runtime_error("k >= cachedPath.size() k = " + intToStr(k) + " cachedPath.size() = " + intToStr(cachedPath.size())); - } - - if(frameIndex >= 0) { - factions[unitFactionIndex].precachedPath[unit->getId()].push_back(cachedPath[k]); - } - else { - //if(pathCount < pathFindRefresh) { - if(pathCount < unit->getPathFindRefreshCellCount()) { - basicPathFinder->add(cachedPath[k]); - } - basicPathFinder->addToLastPathCache(cachedPath[k]); - } - pathCount++; - } - - if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled == true && chrono.getMillis() > 4) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis()); - - if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true && frameIndex < 0) { - char szBuf[4096]=""; - sprintf(szBuf,"[Setting new path for unit] openNodesList.size() [%lu] openPosList.size() [%lu] finalPos [%s] inBailout [%d] ts [%d]", - factions[unitFactionIndex].openNodesList.size(),factions[unitFactionIndex].openPosList.size(),finalPos.getString().c_str(),inBailout,ts); - unit->logSynchData(__FILE__,__LINE__,szBuf); - } - - if(SystemFlags::getSystemSettingType(SystemFlags::debugPathFinder).enabled == true) { - string commandDesc = "none"; - Command *command= unit->getCurrCommand(); - if(command != NULL && command->getCommandType() != NULL) { - commandDesc = command->getCommandType()->toString(); - } - - char szBuf[1024]=""; - sprintf(szBuf,"State: moving, cmd [%s] pos: %s Queue= %d",commandDesc.c_str(),unit->getPos().getString().c_str(), path->getQueueCount()); - unit->setCurrentUnitTitle(szBuf); - } - - if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled == true && chrono.getMillis() > 4) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis()); - - unit->setUsePathfinderExtendedMaxNodes(false); - return ts; - } - //else if(j - i > pathFindRefresh) { - else if(j - i > unit->getPathFindRefreshCellCount()) { - //on the way - ts= tsMoving; - - if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled == true && chrono.getMillis() > 4) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis()); - - //store path - if(frameIndex < 0) { - basicPathFinder->clear(); - } - - int pathCount=0; - for(int k=i+1; k < cachedPath.size(); k++) { - if(k >= cachedPath.size()) { - throw megaglest_runtime_error("#2 k >= cachedPath.size() k = " + intToStr(k) + " cachedPath.size() = " + intToStr(cachedPath.size())); - } - - if(frameIndex >= 0) { - factions[unitFactionIndex].precachedPath[unit->getId()].push_back(cachedPath[k]); - } - else { - //if(pathCount < pathFindRefresh) { - if(pathCount < unit->getPathFindRefreshCellCount()) { - basicPathFinder->add(cachedPath[k]); - } - basicPathFinder->addToLastPathCache(cachedPath[k]); - } - pathCount++; - } - - if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled == true && chrono.getMillis() > 4) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis()); - - if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true && frameIndex < 0) { - char szBuf[4096]=""; - sprintf(szBuf,"[Setting new path for unit] openNodesList.size() [%lu] openPosList.size() [%lu] finalPos [%s] inBailout [%d] ts [%d]", - factions[unitFactionIndex].openNodesList.size(),factions[unitFactionIndex].openPosList.size(),finalPos.getString().c_str(),inBailout,ts); - unit->logSynchData(__FILE__,__LINE__,szBuf); - } - - if(SystemFlags::getSystemSettingType(SystemFlags::debugPathFinder).enabled == true) { - string commandDesc = "none"; - Command *command= unit->getCurrCommand(); - if(command != NULL && command->getCommandType() != NULL) { - commandDesc = command->getCommandType()->toString(); - } - - char szBuf[1024]=""; - sprintf(szBuf,"State: moving, cmd [%s] pos: %s Queue= %d",commandDesc.c_str(),unit->getPos().getString().c_str(), path->getQueueCount()); - unit->setCurrentUnitTitle(szBuf); - } - - if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled == true && chrono.getMillis() > 4) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis()); - - unit->setUsePathfinderExtendedMaxNodes(false); - return ts; - } - } - - pos1 = pos2; - } - - break; - } - } - } - } - } - - //path find algorithm - - //b) loop - bool pathFound = true; - bool nodeLimitReached = false; - - if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled == true && chrono.getMillis() > 4) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis()); - - // First check if unit currently blocked all around them, if so don't try to pathfind - if(inBailout == false && unitPos != finalPos) { - int failureCount = 0; - int cellCount = 0; - - for(int i = -1; i <= 1; ++i) { - for(int j = -1; j <= 1; ++j) { - Vec2i pos = unitPos + Vec2i(i, j); - if(pos != unitPos) { - //!!! Test MV - bool canUnitMoveToCell = canUnitMoveSoon(unit, unitPos, pos); - if(canUnitMoveToCell == false) { - failureCount++; - } - cellCount++; - } - } - } - nodeLimitReached = (failureCount == cellCount); - pathFound = !nodeLimitReached; - - if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled == true && chrono.getMillis() > 1) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] **Check if dest blocked, distance for unit [%d - %s] from [%s] to [%s] is %.2f took msecs: %lld nodeLimitReached = %d, failureCount = %d\n",__FILE__,__FUNCTION__,__LINE__,unit->getId(),unit->getFullName().c_str(), unitPos.getString().c_str(), finalPos.getString().c_str(), dist,(long long int)chrono.getMillis(),nodeLimitReached,failureCount); - if(showConsoleDebugInfo && nodeLimitReached) { - printf("**Check if src blocked [%d - %d], unit [%d - %s] from [%s] to [%s] distance %.2f took msecs: %lld nodeLimitReached = %d, failureCount = %d [%d]\n", - nodeLimitReached, inBailout, unit->getId(),unit->getFullName().c_str(), unitPos.getString().c_str(), finalPos.getString().c_str(), dist,(long long int)chrono.getMillis(),nodeLimitReached,failureCount,cellCount); - } - - if(nodeLimitReached == false) { - // First check if final destination blocked - failureCount = 0; - cellCount = 0; - - for(int i = -1; i <= 1; ++i) { - for(int j = -1; j <= 1; ++j) { - Vec2i pos = finalPos + Vec2i(i, j); - if(pos != finalPos) { - //!!! Test MV - bool canUnitMoveToCell = canUnitMoveSoon(unit, pos, finalPos); - if(canUnitMoveToCell == false) { - failureCount++; - } - cellCount++; - } - } - } - nodeLimitReached = (failureCount == cellCount); - pathFound = !nodeLimitReached; - - if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled == true && chrono.getMillis() > 1) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] **Check if dest blocked, distance for unit [%d - %s] from [%s] to [%s] is %.2f took msecs: %lld nodeLimitReached = %d, failureCount = %d\n",__FILE__,__FUNCTION__,__LINE__,unit->getId(),unit->getFullName().c_str(), unitPos.getString().c_str(), finalPos.getString().c_str(), dist,(long long int)chrono.getMillis(),nodeLimitReached,failureCount); - if(showConsoleDebugInfo && nodeLimitReached) { - printf("**Check if dest blocked [%d - %d], unit [%d - %s] from [%s] to [%s] distance %.2f took msecs: %lld nodeLimitReached = %d, failureCount = %d [%d]\n", - nodeLimitReached, inBailout, unit->getId(),unit->getFullName().c_str(), unitPos.getString().c_str(), finalPos.getString().c_str(), dist,(long long int)chrono.getMillis(),nodeLimitReached,failureCount,cellCount); - } - } - } - // - - //finalPos= computeNearestFreePos(unit, finalPos); - - FastAINodeCache nodeCache(unit); - // Start of New Fast AStar - FastAINode *fromNode = map->getCellNode(unit->getPos()); - FastAINode *toNode = map->getCellNode(finalPos); - //FastAstar *fa = createFastAstar(); - FastAstar *fa = factions[unitFactionIndex].fa; - astarStartSearch(fa,fromNode,toNode, &nodeCache); - - pathFound = false; - unsigned int nodeSearchCount=0; - unsigned int count=0; - AI_Node **solution = NULL; - if(nodeLimitReached == false) { - for(nodeSearchCount=0; pathFound == false && nodeSearchCount < maxNodeCount; ++nodeSearchCount) { - unsigned int search_count=0; - pathFound = astarSearchStep(fa,search_count); - //printf("Fast Pathfind Unit [%d - %s] finished = %d search_count = %d i = %d\n",unit->getId(),unit->getType()->getName().c_str(),finished,search_count,i); - } - - solution = getSolution(fa,count); - } - if(searched_node_count != NULL) { - *searched_node_count = nodeSearchCount; - } - - if(count <= 1 || getLastSearchState(fa) != SEARCH_STATE_SUCCEEDED) { - if(minorDebugPathfinder) printf("Fast Pathfind Unit [%d - %s] NOT FOUND PATH frameIndex = %d nodeSearchCount = %d\n",unit->getId(),unit->getType()->getName().c_str(),frameIndex,nodeSearchCount); - - //blocked - if(SystemFlags::getSystemSettingType(SystemFlags::debugPathFinder).enabled == true) { - string commandDesc = "none"; - Command *command= unit->getCurrCommand(); - if(command != NULL && command->getCommandType() != NULL) { - commandDesc = command->getCommandType()->toString(); - } - - std::pair lastHarvest = unit->getLastHarvestResourceTarget(); - - char szBuf[4096]=""; - sprintf(szBuf,"State: blocked, cmd [%s] pos: [%s], lastHarvest = [%s - %d], reason C= %d, D= %d, F = %d", - commandDesc.c_str(),unit->getPos().getString().c_str(), lastHarvest.first.getString().c_str(),lastHarvest.second, path->getBlockCount(), path->isBlocked(), path->isStuck()); - unit->setCurrentUnitTitle(szBuf); - } - - if(frameIndex < 0) { - unit->setUsePathfinderExtendedMaxNodes(false); - } - - ts= tsBlocked; - if(frameIndex < 0) { - path->incBlockCount(); - } - - if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true && frameIndex < 0) { - char szBuf[4096]=""; - sprintf(szBuf,"[path for unit BLOCKED] openNodesList.size() [%lu] openPosList.size() [%lu] finalPos [%s] ts [%d]", - factions[unitFactionIndex].openNodesList.size(),factions[unitFactionIndex].openPosList.size(),finalPos.getString().c_str(),ts); - unit->logSynchData(__FILE__,__LINE__,szBuf); - } - - //if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled == true && chrono.getMillis() > 4) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis()); - - unit->setLastStuckFrameToCurrentFrame(); - unit->setLastStuckPos(finalPos); - - // Now see if the unit is eligble for pathfind max nodes boost? - if(nodeSearchCount >= maxNodeCount) { - unit->incrementPathfindFailedConsecutiveFrameCount(); - } - else { - unit->resetPathfindFailedConsecutiveFrameCount(); - } - } - else { - if(minorDebugPathfinder) printf("Fast Pathfind Unit [%d - %s] FOUND PATH count = %d frameIndex = %d nodeSearchCount = %d\n",unit->getId(),unit->getType()->getName().c_str(),count,frameIndex,nodeSearchCount); - - ts= tsMoving; - - UnitPathInterface *path= unit->getPath(); - - //if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled == true && chrono.getMillis() > 4) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis()); - if(frameIndex < 0) { - if(maxNodeCount == pathFindNodesAbsoluteMax) { - unit->setUsePathfinderExtendedMaxNodes(true); - } - else { - unit->setUsePathfinderExtendedMaxNodes(false); - } - } - //store path - if(frameIndex < 0) { - path->clear(); - } - - UnitPathBasic *basicPathFinder = dynamic_cast(path); - - for(int i=0; i < count; ++i) { - FastAINode *node = dynamic_cast(solution[i]); - const Vec2i &nodePos = node->getPos(); - if(nodePos != unit->getPos()) { - if(map->isInside(nodePos) == false || map->isInsideSurface(map->toSurfCoords(nodePos)) == false) { - throw megaglest_runtime_error("Pathfinder invalid node path position = " + nodePos.getString() + " i = " + intToStr(i)); - } - - //if(minorDebugPathfinder) printf("nodePos [%s]\n",nodePos.getString().c_str()); - - if(frameIndex >= 0) { - factions[unitFactionIndex].precachedPath[unit->getId()].push_back(nodePos); - } - else { - //if(i < pathFindRefresh || - if(i < unit->getPathFindRefreshCellCount() || - (nodeSearchCount >= pathFindExtendRefreshForNodeCount && - i < getPathFindExtendRefreshNodeCount(unitFactionIndex))) { - path->add(nodePos); - } - else if(tryLastPathCache == false) { - break; - } - - //if(tryLastPathCache == true && basicPathFinder) { - if(basicPathFinder) { - basicPathFinder->addToLastPathCache(nodePos); - } - } - } - } - - //if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled == true && chrono.getMillis() > 4) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis()); - - if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true && frameIndex < 0) { - char szBuf[4096]=""; - sprintf(szBuf,"[Setting new path for unit] openNodesList.size() [%lu] openPosList.size() [%lu] finalPos [%s] ts [%d]", - factions[unitFactionIndex].openNodesList.size(),factions[unitFactionIndex].openPosList.size(),finalPos.getString().c_str(),ts); - unit->logSynchData(__FILE__,__LINE__,szBuf); - - string pathToTake = ""; - for(int i = 0; i < path->getQueueCount(); ++i) { - Vec2i &pos = path->getQueue()[i]; - if(pathToTake != "") { - pathToTake += ", "; - } - pathToTake += pos.getString(); - } - unit->logSynchData(__FILE__,__LINE__,szBuf); - sprintf(szBuf,"Path for unit to take = %s",pathToTake.c_str()); - } - - if(SystemFlags::getSystemSettingType(SystemFlags::debugPathFinder).enabled == true) { - string commandDesc = "none"; - Command *command= unit->getCurrCommand(); - if(command != NULL && command->getCommandType() != NULL) { - commandDesc = command->getCommandType()->toString(); - } - - char szBuf[1024]=""; - sprintf(szBuf,"State: moving, cmd [%s] pos: %s, Queue= %d",commandDesc.c_str(),unit->getPos().getString().c_str(), path->getQueueCount()); - unit->setCurrentUnitTitle(szBuf); - } - - //if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled == true && chrono.getMillis() > 4) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis()); - } - //releaseFastAstar(fa); - - // End of New Fast AStar - - //factions[unitFactionIndex].openNodesList.clear(); - //factions[unitFactionIndex].openPosList.clear(); - //factions[unitFactionIndex].closedNodesList.clear(); - - //if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled == true && chrono.getMillis() > 4) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s] Line: %d took msecs: %lld --------------------------- [END OF METHOD] ---------------------------\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis()); - - if(frameIndex >= 0) { - factions[unitFactionIndex].precachedTravelState[unit->getId()] = ts; - } - //else { - if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() >= 1) printf("In [%s::%s Line: %d] fastastar took [%lld] msecs, ts = %d nodeSearchCount = %d.\n",__FILE__,__FUNCTION__,__LINE__,(long long int)chrono.getMillis(),ts,nodeSearchCount); - //if(chrono.getMillis() >= 1) printf("In [%s::%s Line: %d] fastastar took [%lld] msecs, ts = %d nodeSearchCount = %d.\n",__FILE__,__FUNCTION__,__LINE__,(long long int)chrono.getMillis(),ts,nodeSearchCount); - //} - - return ts; -} - bool PathFinder::addToOpenSet(Unit *unit, Node *node,const Vec2i finalPos, Vec2i sucPos, bool &nodeLimitReached,int maxNodeCount,Node **newNodeAdded, bool bypassChecks) { bool result = false; diff --git a/source/glest_game/ai/path_finder.h b/source/glest_game/ai/path_finder.h index 47f7e0ae..c019f8e4 100644 --- a/source/glest_game/ai/path_finder.h +++ b/source/glest_game/ai/path_finder.h @@ -24,7 +24,7 @@ #include "skill_type.h" #include "map.h" #include "unit.h" -#include "fast_path_finder.h" + //#include //using namespace std::tr1; @@ -114,8 +114,6 @@ public: //mapFromToNodeList.clear(); //lastFromToNodeListFrame = -100; badCellList.clear(); - - fa = createFastAstar(); } ~FactionState() { //fa = NULL; @@ -135,8 +133,6 @@ public: //std::map > > mapFromToNodeList; std::map > badCellList; - - FastAstar *fa; }; typedef vector FactionStateList; @@ -173,7 +169,6 @@ public: void loadGame(const XmlNode *rootNode); private: - TravelState aStarFast(Unit *unit, Vec2i finalPos, bool inBailout, int frameIndex, int maxNodeCount=-1,uint32 *searched_node_count=NULL); TravelState aStar(Unit *unit, const Vec2i &finalPos, bool inBailout, int frameIndex, int maxNodeCount=-1,uint32 *searched_node_count=NULL); //Node *newNode(FactionState &faction,int maxNodeCount); inline static Node *newNode(FactionState &faction, int maxNodeCount) { diff --git a/source/glest_game/world/map.cpp b/source/glest_game/world/map.cpp index d29a1505..f474ddc2 100644 --- a/source/glest_game/world/map.cpp +++ b/source/glest_game/world/map.cpp @@ -279,142 +279,6 @@ void SurfaceCell::loadGame(const XmlNode *rootNode, int index, World *world) { // class Map // ===================================================== -FastAINode * FastAINode::getNodeForEdgeIndex(int index,void *userData) const { - FastAINode *resultNode = NULL; - switch(index) { - case 0: // north - resultNode = map->getCellNode(pos.x,pos.y-1,false); - break; - case 1: // north east - resultNode = map->getCellNode(pos.x+1,pos.y-1,false); - break; - case 2: // east - resultNode = map->getCellNode(pos.x+1,pos.y,false); - break; - case 3: // south east - resultNode = map->getCellNode(pos.x+1,pos.y+1,false); - break; - case 4: // south - resultNode = map->getCellNode(pos.x,pos.y+1,false); - break; - case 5: // south west - resultNode = map->getCellNode(pos.x-1,pos.y+1,false); - break; - case 6: // west - resultNode = map->getCellNode(pos.x-1,pos.y,false); - break; - case 7: // north west - resultNode = map->getCellNode(pos.x-1,pos.y-1,false); - break; - } - bool checkCellObjects = true; - if(checkCellObjects == true && resultNode != NULL) { - FastAINodeCache *nodeCache = (FastAINodeCache *)userData; - std::map >::const_iterator iterFind = nodeCache->cachedCanMoveSoonList.find(pos); - if(iterFind != nodeCache->cachedCanMoveSoonList.end() && - iterFind->second.find(resultNode->getPos()) != iterFind->second.end()) { - const std::map &mapCache2 = iterFind->second; - std::map::const_iterator iterFind2 = mapCache2.find(resultNode->getPos()); - - if(iterFind2->second == false) { - resultNode = NULL; - } - } - else { - const Vec2i &nodePos = resultNode->getPos(); - - if(resultNode->getPos() != nodeCache->unit->getCurrentPathFinderDesiredFinalPos()) { - if(map->aproxCanMoveSoon(nodeCache->unit, pos, resultNode->getPos()) == false) { - resultNode = NULL; - } - } - - nodeCache->cachedCanMoveSoonList[pos][nodePos] = (resultNode != NULL); - } - } - - return resultNode; -} - -float FastAINode::getDistance(const AI_Node *node,void *userData) { - return pos.dist(dynamic_cast(node)->pos); -} -float FastAINode::getCost(void *userData) { - float result = 1.0f; - -// FastAINodeCache *nodeCache = (FastAINodeCache *)userData; -// if(map->aproxCanMoveSoon(nodeCache->unit, pos, pos) == false) { -// result = 100000; -// } - -// bool checkCellObjects = true; -// if(checkCellObjects == true) { -// FastAINode *resultNode = map->getCellNode(pos,false); -// if(resultNode != NULL) { -// FastAINodeCache *nodeCache = (FastAINodeCache *)userData; -// std::map >::const_iterator iterFind = nodeCache->cachedCanMoveSoonList.find(pos); -// if(iterFind != nodeCache->cachedCanMoveSoonList.end() && -// iterFind->second.find(resultNode->getPos()) != iterFind->second.end()) { -// const std::map &mapCache2 = iterFind->second; -// std::map::const_iterator iterFind2 = mapCache2.find(resultNode->getPos()); -// -// if(iterFind2->second == false) { -// resultNode = NULL; -// result = 9999999; -// } -// } -// else { -// const Vec2i &nodePos = resultNode->getPos(); -// -// if(resultNode->getPos() != nodeCache->unit->getCurrentPathFinderDesiredFinalPos()) { -// if(map->aproxCanMoveSoon(nodeCache->unit, pos, resultNode->getPos()) == false) { -// resultNode = NULL; -// result = 9999999; -// } -// } -// -// nodeCache->cachedCanMoveSoonList[pos][nodePos] = (resultNode != NULL); -// } -// } -// } - return result; -} - -unsigned int FastAINode::getEdgeCount(void *userData) const { - unsigned int result = 0; - for(unsigned int index = 0; index < NODE_EDGE_COUNT; ++index) { - FastAINode *resultNode = getNodeForEdgeIndex(index,userData); - if(resultNode != NULL) { - result++; - } - } - return result; -} - -AI_Node * FastAINode::getEdge(int index,void *userData) const { - FastAINode *result = NULL; - - unsigned int edgeCount = getEdgeCount(userData); - if(edgeCount < NODE_EDGE_COUNT) { - int edgeIndex = -1; - - for(unsigned int index2 = 0; index2 < NODE_EDGE_COUNT; ++index2) { - result = getNodeForEdgeIndex(index2,userData); - if(result != NULL) { - edgeIndex++; - - if(edgeIndex == index) { - return result; - } - } - result = NULL; - } - return result; - } - result = getNodeForEdgeIndex(index,userData); - return result; -}; - // ===================== PUBLIC ======================== const int Map::cellScale= 2; @@ -423,7 +287,6 @@ const int Map::mapScale= 2; Map::Map() { cells= NULL; surfaceCells= NULL; - cellNodes=NULL; startLocations= NULL; title=""; @@ -446,8 +309,6 @@ Map::~Map() { cells = NULL; delete [] surfaceCells; surfaceCells = NULL; - delete [] cellNodes; - cellNodes = NULL; delete [] startLocations; startLocations = NULL; } @@ -545,14 +406,6 @@ Checksum Map::load(const string &path, TechTree *techTree, Tileset *tileset) { //cells cells= new Cell[getCellArraySize()]; - cellNodes = new FastAINode[getCellArraySize()]; - for(unsigned int x = 0; x < w; ++x) { - for(unsigned int y = 0; y < h; ++y) { - int arrayIndex = y * w + x; - FastAINode &cellNode = cellNodes[arrayIndex]; - cellNode.setData(Vec2i(x,y),this); - } - } surfaceCells= new SurfaceCell[getSurfaceCellArraySize()]; //read heightmap diff --git a/source/glest_game/world/map.h b/source/glest_game/world/map.h index be5fa38e..c27be678 100644 --- a/source/glest_game/world/map.h +++ b/source/glest_game/world/map.h @@ -26,7 +26,6 @@ #include "selection.h" #include #include "unit_type.h" -#include "fast_path_finder.h" #include "command.h" #include "checksum.h" #include "leak_dumper.h" @@ -204,47 +203,6 @@ public: std::map > cachedCanMoveSoonList; }; -class FastAINode : public AI_Node { -protected: - Vec2i pos; - const Map *map; - int32 hashCode; - static const int NODE_EDGE_COUNT = 8; - - FastAINode * getNodeForEdgeIndex(int index,void *userData) const; - -public: - - FastAINode() { - this->map = NULL; - hashCode=0; - } - FastAINode(Vec2i &pos,const Map *map) { - this->pos = pos; - this->map = map; - Checksum result; - result.addInt(pos.x); - result.addInt(pos.y); - hashCode = result.getSum(); - } - virtual ~FastAINode() {} - void setData(Vec2i pos, const Map *map) { - this->pos = pos; - this->map = map; - Checksum result; - result.addInt(pos.x); - result.addInt(pos.y); - hashCode = result.getSum(); - } - inline const Vec2i & getPos() const { return pos; } - - virtual float getDistance(const AI_Node *node, void *userData); - virtual float getCost(void *userData); - virtual unsigned int getEdgeCount(void *userData) const; - virtual AI_Node * getEdge(int index, void *userData) const; - inline virtual int32 getHashCode() const { return hashCode; } -}; - class Map { public: static const int cellScale; //number of cells per surfaceCell @@ -263,7 +221,6 @@ private: int maxPlayers; Cell *cells; SurfaceCell *surfaceCells; - FastAINode *cellNodes; Vec2i *startLocations; Checksum checksumValue; float maxMapHeight; @@ -306,30 +263,6 @@ public: return getCell(pos.x, pos.y); } - //get - inline FastAINode *getCellNode(Vec2i pos, bool errorOnInvalid=true) const { - return getCellNode(pos.x, pos.y, errorOnInvalid); - } - inline FastAINode *getCellNode(int x, int y, bool errorOnInvalid=true) const { - int arrayIndex = y * w + x; - if(arrayIndex < 0 || arrayIndex >= getCellArraySize()) { - if(errorOnInvalid == false) { - return NULL; - } - //abort(); - throw megaglest_runtime_error("arrayIndex >= getCellArraySize(), arrayIndex = " + intToStr(arrayIndex) + " w = " + intToStr(w) + " h = " + intToStr(h)); - } - else if(cellNodes == NULL) { - if(errorOnInvalid == false) { - return NULL; - } - - throw megaglest_runtime_error("cellNodes == NULL"); - } - - return &cellNodes[arrayIndex]; - } - inline int getCellArraySize() const { return (w * h); }