00001 #ifndef AI_A_STAR_H
00002 #define AI_A_STAR_H
00003
00004 #include "AI_Global.h"
00005 #include "utils/AI_Array.h"
00006
00007
00008 #define GRAPH_INITIAL_SIZE 0
00009 #define GRAPH_GROW_SIZE 8
00010
00011
00033 class AI_AStar
00034 {
00035
00036 public:
00037 class Link;
00038 class Node;
00039 class Graph;
00040 class Session;
00041
00043 typedef AI_Array<Link*> LinkArray;
00045 typedef LinkArray::iterator LinkArrayIt;
00047 typedef AI_Array<Node*> NodeArray;
00049 typedef NodeArray::iterator NodeArrayIt;
00050
00054 class Node {
00055
00056 protected:
00058 int m_i_index;
00060 LinkArray m_arr_links;
00062 void *m_ptr_user_data;
00063
00064
00065 public:
00066 Node ();
00067
00068
00069 void removeLink ( Link *ptr_link );
00070 void addLink( Link *ptr_link );
00071 void reset(void);
00072
00073
00074 void set (int i_index);
00075 void setUserData( void *ptr_data );
00076
00077
00078 void *getUserData( void ) const;
00079 int getIndex( void ) const;
00080 LinkArray &getLinks( void );
00081
00082
00083 Link *isLinkedTo( Node *ptr_other );
00084 };
00085
00086
00090 class Link {
00091
00092 protected:
00094 Node *m_ptr_node1;
00096 Node *m_ptr_node2;
00098 float m_f_length;
00100 float m_f_min_width;
00102 float m_f_max_width;
00104 void *m_ptr_user_data;
00106 Session *m_ptr_session;
00107
00108
00109 public:
00110
00111 Link();
00112
00113
00114 void set( Node *ptr_node1, Node *ptr_node2, float f_length, float f_min, float f_max, Session *ptr_session=NULL );
00115 void setUserData( void *ptr_data );
00116
00117
00118 void *getUserData( void ) const;
00119 Node *getFirstNode ( void ) const;
00120 Node *getSecondNode ( void ) const;
00121 const float getMinWidth ( void ) const;
00122 const float getMaxWidth ( void ) const;
00123 const float getLength ( void ) const;
00124 Node *getOtherNode ( Node *ptr_node );
00125 Session *getSession( void );
00126
00127 };
00128
00129
00144 class Graph {
00145 protected:
00147 NodeArray m_arr_nodes;
00149 LinkArray m_arr_links;
00151 int m_i_first_node_index;
00152
00153 public:
00154
00155 Graph();
00156 ~Graph();
00157
00158
00159 Node *addNode ( void *ptr_user_data = NULL );
00160 Link *addLink ( Node *ptr_node1, Node *ptr_node2, float f_lenght, float f_min, float f_max, Session *ptr_session=NULL );
00161 void reset( void );
00162 void clear( void );
00163 void setBaseNodeIndex( const int i);
00164 const int getBaseNodeIndex( void ) const;
00165 const int getLinksNumber( void ) const;
00166 const int getNodesNumber( void ) const;
00167 Node *getNode(const int i) const;
00168 Link *getLink(const int i) const;
00169 };
00170
00171
00178 class Informator {
00179 public:
00180 virtual float getHeuristic ( Node *ptr_node1, Node *ptr_node2 ) = 0;
00181 };
00182
00183
00194 class Session {
00195 friend AI_AStar;
00196
00197
00198 private:
00201 struct PathSegment {
00203 Node *ptr_node_first;
00205 Node *ptr_node_second;
00206 };
00207
00210 struct PathDirection {
00212 Node *ptr_node;
00214 float f_distance;
00216 float f_guess;
00217
00218 public:
00219 PathDirection(void);
00220 PathDirection(Node *ptr_node, float f_distance, float f_guess);
00221 };
00222
00224 typedef AI_Array<PathDirection>::iterator DirectionVectorIt;
00225
00226
00227 private:
00229 Graph m_graph;
00231 float m_f_agent_width;
00233 AI_Array<PathSegment> m_arr_segments;
00235 AI_Array<PathDirection> m_arr_directions;
00237 unsigned char *m_ptr_byte_visited;
00239 int m_i_visited_size;
00241 float m_f_distance;
00243 Node *m_ptr_node_actual;
00245 Node *m_ptr_node_start;
00247 Node *m_ptr_node_final;
00249 NodeArray m_arr_way;
00250
00251
00252 protected:
00253
00254 void setNodeVisited( int i );
00255 void pushDirection( Node *ptr_node, float f_distance, float f_depth );
00256 void pushSegment( Node *ptr_node1, Node *ptr_node2 );
00257 void pushWay( Node *ptr_node );
00258
00259
00260 bool isNodeVisited( int i );
00261 Node *getActualNode( void );
00262 float getActualDistance( void );
00263 PathSegment &getBackSegment( void );
00264
00265
00266 bool beginSearch ( void );
00267 void endSearch ( void );
00268 bool isFinishReached( void );
00269 bool moveBestDirection( void );
00270 void removeBackSegment( void );
00271
00272 public:
00273
00274 Session();
00275 ~Session();
00276
00277
00278 Node *addNode ( void *ptr_user_data );
00279 Link *addLink ( Node *ptr_node1, Node *ptr_node2, float f_lenght, float f_min, float f_max );
00280 void reset ( AI_AStar *ptr_astar );
00281
00282
00283 void setMission ( Node *ptr_node_start, Node *ptr_node_final );
00284 int getWaySize( void );
00285 Node *getWayNode( int i );
00286
00287
00288 void setAgentWidth( float f_width );
00289 void setAStar( AI_AStar *ptr_astar );
00290
00291
00292 float getAgentWidth( void );
00293 Node *getStartNode( void );
00294 Node *getFinalNode( void );
00295 };
00296
00297
00298
00299 private:
00301 Informator *m_ptr_informator;
00303 Graph m_graph;
00304
00305
00306
00307 public:
00308 AI_AStar(void);
00309 ~AI_AStar(void);
00310
00311
00312 Node *addNode ( void *ptr_user_data = NULL );
00313 Link *addLink ( Node *ptr_node1, Node *ptr_node2, float f_lenght, float f_min, float f_max );
00314 void clear(void);
00315
00316
00317 void setInformator (Informator *ptr_informator);
00318
00319
00320 int getLinksNumber( void ) const;
00321 Link *getLink ( int i ) const;
00322 int getNodesNumber( void ) const;
00323 Node *getNode ( int i ) const;
00324
00325
00326 bool findWay ( Session &session );
00327 };
00328
00329
00332 inline
00333 void AI_AStar::Node::set (int i_index)
00334 {
00335 m_i_index = i_index;
00336 }
00337
00338
00341 inline
00342 void AI_AStar::Node::setUserData( void *ptr_data )
00343 {
00344 m_ptr_user_data = ptr_data;
00345 }
00346
00347
00350 inline
00351 void *AI_AStar::Node::getUserData( void ) const
00352 {
00353 return m_ptr_user_data;
00354 }
00355
00356
00359 inline
00360 void AI_AStar::Link::set(Node *ptr_node1, Node *ptr_node2, float f_length, float f_min, float f_max, Session *ptr_session)
00361 {
00362 m_ptr_user_data = NULL;
00363 m_ptr_node1 = ptr_node1;
00364 m_ptr_node2 = ptr_node2;
00365 m_f_length = f_length;
00366 m_f_min_width = f_min;
00367 m_f_max_width = f_max;
00368 m_ptr_session = ptr_session;
00369 }
00370
00371
00374 inline
00375 AI_AStar::Graph::Graph() :
00376 m_arr_nodes(GRAPH_INITIAL_SIZE, GRAPH_GROW_SIZE, NULL),
00377 m_arr_links(GRAPH_INITIAL_SIZE, GRAPH_GROW_SIZE, NULL),
00378 m_i_first_node_index(0)
00379 {
00380 NodeArrayIt it_n = m_arr_nodes.Begin();
00381 for (int i=0; i<m_arr_nodes.AllocSize(); i++, it_n++)
00382 *it_n=NULL;
00383
00384 LinkArrayIt it_l = m_arr_links.Begin();
00385 for (int i=0; i<m_arr_links.AllocSize(); i++, it_l++)
00386 *it_l=NULL;
00387 }
00388
00389
00392 inline
00393 AI_AStar::Graph::~Graph()
00394 {
00395 clear();
00396 }
00397
00398
00401 inline
00402 void AI_AStar::Graph::setBaseNodeIndex( const int i)
00403 {
00404 m_i_first_node_index = i;
00405 }
00406
00407
00410 inline
00411 const int AI_AStar::Graph::getBaseNodeIndex( void ) const
00412 {
00413 return m_i_first_node_index;
00414 }
00415
00416
00419 inline
00420 const int AI_AStar::Graph::getLinksNumber( void ) const
00421 {
00422 return m_arr_links.Size();
00423 }
00424
00425
00428 inline
00429 const int AI_AStar::Graph::getNodesNumber( void ) const
00430 {
00431 return m_arr_nodes.Size();
00432 }
00433
00434
00437 inline
00438 AI_AStar::Node *AI_AStar::Graph::getNode(const int i) const
00439 {
00440 return m_arr_nodes[i];
00441 }
00442
00443
00446 inline
00447 AI_AStar::Link *AI_AStar::Graph::getLink(const int i) const
00448 {
00449 return m_arr_links[i];
00450 }
00451
00452
00453
00456 inline
00457 AI_AStar::Node::Node () :
00458 m_ptr_user_data(NULL)
00459 {
00460 }
00461
00462
00466 inline
00467 AI_AStar::Link *AI_AStar::Node::isLinkedTo( Node *ptr_other )
00468 {
00469 for (LinkArrayIt it=m_arr_links.Begin(); it!=m_arr_links.End(); it++)
00470 {
00471 if ( ptr_other==(*it)->getOtherNode ( this ) )
00472 {
00473 return (*it);
00474 }
00475 }
00476
00477 return NULL;
00478 }
00479
00480
00483 inline
00484 void AI_AStar::Node::removeLink ( Link *ptr_link )
00485 {
00486
00487
00488 if ( m_arr_links.Size()>0 )
00489 {
00490 LinkArrayIt it = m_arr_links.End();
00491 do {
00492 it--;
00493
00494 if (*it==ptr_link)
00495 {
00496 m_arr_links.Erase(it);
00497 return;
00498 }
00499 } while( it!=m_arr_links.Begin() );
00500 }
00501 }
00502
00503
00506 inline
00507 int AI_AStar::Node::getIndex( void ) const
00508 {
00509 return m_i_index;
00510 }
00511
00512
00515 inline
00516 AI_AStar::LinkArray &AI_AStar::Node::getLinks( void )
00517 {
00518 return m_arr_links;
00519 }
00520
00521
00524 inline
00525 void AI_AStar::Node::addLink( Link *ptr_link )
00526 {
00527 m_arr_links.Append( ptr_link );
00528 }
00529
00530
00533 inline
00534 void AI_AStar::Node::reset(void)
00535 {
00536 m_arr_links.Reset();
00537 }
00538
00539
00542 inline
00543 AI_AStar::Link::Link() :
00544 m_ptr_session(NULL),
00545 m_ptr_node1(NULL),
00546 m_ptr_node2(NULL),
00547 m_ptr_user_data(NULL)
00548 {
00549 }
00550
00551
00554 inline
00555 AI_AStar::Node *AI_AStar::Link::getOtherNode ( Node *ptr_node )
00556 {
00557 if ( m_ptr_node1==ptr_node )
00558 return m_ptr_node2;
00559
00560 return m_ptr_node1;
00561 }
00562
00563
00566 inline
00567 AI_AStar::Node *AI_AStar::Link::getFirstNode ( void ) const
00568 {
00569 return m_ptr_node1;
00570 }
00571
00572
00575 inline
00576 AI_AStar::Node *AI_AStar::Link::getSecondNode ( void ) const
00577 {
00578 return m_ptr_node2;
00579 }
00580
00581
00584 inline
00585 AI_AStar::Session *AI_AStar::Link::getSession( void )
00586 {
00587 return m_ptr_session;
00588 }
00589
00590
00593 inline
00594 const float AI_AStar::Link::getMinWidth ( void ) const
00595 {
00596 return m_f_min_width;
00597 }
00598
00599
00602 inline
00603 const float AI_AStar::Link::getMaxWidth ( void ) const
00604 {
00605 return m_f_max_width;
00606 }
00607
00608
00611 inline
00612 const float AI_AStar::Link::getLength ( void ) const
00613 {
00614 return m_f_length;
00615 }
00616
00617
00620 inline
00621 void *AI_AStar::Link::getUserData( void ) const
00622 {
00623 return m_ptr_session;
00624 }
00625
00626
00629 inline
00630 AI_AStar::Session::Session() :
00631 m_ptr_byte_visited(NULL),
00632 m_i_visited_size(0),
00633 m_f_agent_width(0)
00634 {
00635 }
00636
00637
00640 inline
00641 AI_AStar::Session::~Session()
00642 {
00643 m_graph.reset();
00644
00645 if (m_ptr_byte_visited)
00646 {
00647 delete(m_ptr_byte_visited);
00648 }
00649 }
00650
00651
00654 inline
00655 AI_AStar::Node *AI_AStar::Session::addNode ( void *ptr_user_data )
00656 {
00657 return m_graph.addNode( ptr_user_data );
00658 }
00659
00660
00669 inline
00670 AI_AStar::Link *AI_AStar::Session::addLink ( Node *ptr_node1, Node *ptr_node2, float f_lenght, float f_min, float f_max)
00671 {
00672 return m_graph.addLink( ptr_node1, ptr_node2, f_lenght, f_min, f_max, this );
00673 }
00674
00675
00678 inline
00679 bool AI_AStar::Session::isFinishReached( void )
00680 {
00681 return (m_ptr_node_actual==m_ptr_node_final);
00682 }
00683
00684
00687 inline
00688 bool AI_AStar::Session::isNodeVisited( int i )
00689 {
00690 unsigned char c = m_ptr_byte_visited[ i / 8 ];
00691 if (c & 1<<(i%8))
00692 {
00693 return true;
00694 }
00695 return false;
00696 }
00697
00698
00701 inline
00702 void AI_AStar::Session::setNodeVisited( int i )
00703 {
00704 unsigned char &c = m_ptr_byte_visited[ i / 8 ];
00705 c |= 1<<(i%8);
00706 }
00707
00708
00711 inline
00712 void AI_AStar::Session::setAgentWidth( float f_width )
00713 {
00714 m_f_agent_width = f_width;
00715 }
00716
00717
00720 inline
00721 float AI_AStar::Session::getAgentWidth( void )
00722 {
00723 return m_f_agent_width;
00724 }
00725
00726
00729 inline
00730 AI_AStar::Node *AI_AStar::Session::getActualNode( void )
00731 {
00732 return m_ptr_node_actual;
00733 }
00734
00735
00738 inline
00739 float AI_AStar::Session::getActualDistance( void )
00740 {
00741 return m_f_distance;
00742 }
00743
00744
00747 inline
00748 void AI_AStar::Session::pushDirection( Node *ptr_node, float f_distance, float f_guess )
00749 {
00750 PathDirection &dir = m_arr_directions.PushBack();
00751
00752 dir.ptr_node = ptr_node;
00753 dir.f_distance = f_distance;
00754 dir.f_guess = f_guess;
00755 }
00756
00757
00760 inline
00761 void AI_AStar::Session::pushSegment( Node *ptr_node1, Node *ptr_node2 )
00762 {
00763 PathSegment &segment = m_arr_segments.PushBack();
00764
00765 segment.ptr_node_first = ptr_node1;
00766 segment.ptr_node_second = ptr_node2;
00767 }
00768
00769
00772 inline
00773 AI_AStar::Node *AI_AStar::Session::getStartNode( void )
00774 {
00775 return m_ptr_node_start;
00776 }
00777
00778
00781 inline
00782 AI_AStar::Node *AI_AStar::Session::getFinalNode( void )
00783 {
00784 return m_ptr_node_final;
00785 }
00786
00787
00790 inline
00791 AI_AStar::Session::PathSegment &AI_AStar::Session::getBackSegment( void )
00792 {
00793 return m_arr_segments.Back();
00794 }
00795
00796
00799 inline
00800 void AI_AStar::Session::removeBackSegment( void )
00801 {
00802 m_arr_segments.PopBack();
00803 }
00804
00805
00808 inline
00809 void AI_AStar::Session::pushWay( Node *ptr_node )
00810 {
00811 m_arr_way.PushBack( ptr_node );
00812 }
00813
00814
00817 inline
00818 int AI_AStar::Session::getWaySize( void )
00819 {
00820 return m_arr_way.Size();
00821 }
00822
00823
00826 inline
00827 AI_AStar::Node *AI_AStar::Session::getWayNode( int i )
00828 {
00829 return m_arr_way[getWaySize()-i-1];
00830 }
00831
00832
00835 inline
00836 void AI_AStar::Session::setMission ( Node *ptr_node_start, Node *ptr_node_final )
00837 {
00838 m_ptr_node_start = ptr_node_start;
00839 m_ptr_node_final = ptr_node_final;
00840 }
00841
00842
00846 inline
00847 void AI_AStar::Session::reset ( AI_AStar *ptr_astar )
00848 {
00849 m_graph.reset();
00850 m_graph.setBaseNodeIndex( ptr_astar->getNodesNumber() );
00851 }
00852
00853
00856 inline
00857 AI_AStar::Session::PathDirection::PathDirection(void) :
00858 ptr_node(NULL)
00859 {
00860 }
00861
00862
00865 inline
00866 AI_AStar::Session::PathDirection::PathDirection(Node *ptr_node, float f_distance, float f_guess) :
00867 ptr_node(ptr_node),
00868 f_distance(f_distance),
00869 f_guess(f_guess)
00870 {
00871 }
00872
00873
00876 inline
00877 AI_AStar::AI_AStar(void) :
00878 m_ptr_informator(NULL)
00879 {
00880 }
00881
00882
00885 inline
00886 AI_AStar::~AI_AStar(void)
00887 {
00888 }
00889
00890
00895 inline
00896 void AI_AStar::clear(void)
00897 {
00898 m_graph.clear();
00899 }
00900
00901
00904 inline
00905 AI_AStar::Node *AI_AStar::addNode ( void *ptr_user_data )
00906 {
00907 return m_graph.addNode( ptr_user_data );
00908 }
00909
00910
00919 inline
00920 AI_AStar::Link *AI_AStar::addLink ( Node *ptr_node1, Node *ptr_node2, float f_lenght, float f_min, float f_max)
00921 {
00922 return m_graph.addLink(ptr_node1, ptr_node2, f_lenght, f_min, f_max);
00923 }
00924
00925
00928 inline
00929 int AI_AStar::getLinksNumber( void ) const
00930 {
00931 return m_graph.getLinksNumber();
00932 }
00933
00934
00937 inline
00938 AI_AStar::Link *AI_AStar::getLink ( int i ) const
00939 {
00940 return m_graph.getLink(i);
00941 }
00942
00943
00946 inline
00947 int AI_AStar::getNodesNumber( void ) const
00948 {
00949 return m_graph.getNodesNumber();
00950 }
00951
00952
00955 inline
00956 AI_AStar::Node *AI_AStar::getNode ( int i ) const
00957 {
00958 return m_graph.getNode(i);
00959 }
00960
00961
00964 inline
00965 void AI_AStar::setInformator (Informator *ptr_informator)
00966 {
00967 m_ptr_informator = ptr_informator;
00968 }
00969
00970
00971 #endif