Unuk 1.0
src/libUnuk/AStar.cpp
Go to the documentation of this file.
00001 #include <stdlib.h>
00002 #include "AStar.h"
00003 #include "Node.h"
00004 
00005 AStar::AStar(void) {
00006   m_open          = NULL;
00007   m_stack         = NULL;
00008   m_best          = NULL;
00009   
00010   udCost          = NULL;
00011   udValid         = NULL;
00012   udNotifyChild   = NULL;  
00013   udNotifyList    = NULL;
00014 }
00015 
00016 AStar::~AStar(void) {
00017   ClearNodes();
00018 }
00019 
00020 bool AStar::GeneratePath(int startx, int starty, int destx, int desty) {
00021   // Grab the next node from the f position.
00022   InitStep(startx, starty, destx, desty);
00023 
00024   int retval = 0;
00025   while(retval == 0) {
00026     // Go find the next node.
00027     retval = Step();
00028   }
00029   
00030   if(retval == 0 || !m_best) {
00031     // Set m_best to NULL so we can go and check for the next best node.
00032     m_best = NULL;
00033     return false;
00034   }
00035   return true;
00036 }
00037 
00038 int AStar::Step(void) {
00039   // If we don't get the most efficent route, then go back
00040   // and check some more nodes plox!
00041   if(!(m_best == GetBest())) { return -1; }
00042   // Ok, we found the best route.
00043   if(m_best->id  == m_ID)    { return 1; }
00044   
00045   // Please set the best route as a child node.
00046   CreateChildren(m_best);
00047  
00048   return 0;
00049 }
00050 
00051 int AStar::InitStep(int startx, int starty, int destx, int desty) {
00052   // Prepare for the next pass by clearing our previous nodes.
00053   ClearNodes();
00054   
00055   // Initialize our variables.
00056   m_startx = startx;
00057   m_starty = starty;
00058   m_destx  = destx;
00059   m_desty  = desty;
00060   m_ID = Coord2Id(destx, desty);
00061  
00062   // Set the node for our start location.
00063   Node *temp = new Node(startx, starty);
00064   temp->g = 0;
00065   temp->h = abs(destx - startx) + abs(desty - starty);
00066   temp->f = temp->g + temp->h;
00067   temp->id = Coord2Id(startx, starty);
00068   m_open = temp;
00069 
00070   return 0;
00071 }
00072 
00073 void AStar::AddToOpen(Node *addnode) {
00074   Node *node = m_open;
00075   Node *prev = NULL;
00076   
00077   if(!m_open) {
00078     // Add a a new node to the open list.
00079     m_open = addnode;
00080   
00081     m_open->next = NULL;
00082 
00083     // Start a new open list with our new node.
00084     //Func(udNotifyList, NULL, addnode, NL_STARTOPEN, NCData);
00085  
00086     return;
00087   }
00088   
00089   while(node) {
00090     // If our addnode's f is greater than the currently open node
00091     // then add the open node to the to previous to make room for
00092     // add node to be on the open list.
00093     if(addnode->f > node->f) {
00094       prev = node;
00095       // Now we have our new node go to next.
00096       node = node->next;
00097     } else {
00098       // go to the next node, and set it on our open list to check it's
00099       // f value.
00100       if(prev) {
00101         prev->next = addnode;
00102         addnode->next = node;
00103         Func(udNotifyList, prev, addnode, NL_ADDOPEN, NCData);
00104       } else {
00105         // We will only ever run through this once per instance. We have no nodes currently
00106         // so we set an open list with this node.
00107         Node *temp = m_open;
00108       
00109         m_open = addnode;
00110         m_open->next = temp;
00111         //Func(udNotifyList, temp, addnode, NL_STARTOPEN, NCData);
00112       } 
00113       return;
00114     }
00115   }
00116   // Get the next node and add it to the open list.
00117   prev->next = addnode;
00118   //Func(udNotifyList, prev, addnode, NL_ADDOPEN, NCData);              
00119 }
00120 
00121 void AStar::ClearNodes(void) {
00122   Node *temp  = NULL;
00123   Node *temp2 = NULL;
00124   
00125   if(m_open) {
00126     while(m_open) {
00127       temp = m_open->next;
00128       delete m_open;
00129       m_open = temp;
00130     }
00131   }
00132   if(m_closed) {
00133     while(m_closed) {
00134       temp = m_closed->next;
00135       delete m_closed;
00136       m_closed = temp;
00137     }
00138   }
00139 }
00140 
00141 void AStar::CreateChildren(Node *node) {
00142   Node temp;
00143   int x = node->x;
00144   int y = node->y;
00145  
00146   // Loop through the grid and add the children to the list.
00147   for(int i = -1; i < 2; i++) {
00148     for(int j = -1; j < 2; j++) {
00149       temp.x = x+i;
00150       temp.y = y+j;
00151       if((i == 0) && (j == 0) || !Func(udValid, node, &temp, NC_INITIALADD, CBData)) continue;
00152         
00153       LinkChild(node, &temp);
00154     }
00155   }     
00156 }
00157 
00158 void AStar::LinkChild(Node *node, Node *temp) {
00159   // Initialize variables for our temp node.
00160   int x = temp->x;
00161   int y = temp->y;
00162   int g = temp->g + Func(udCost, node, temp, 0, CBData);
00163   // Grabbing a unique ID before adding the node to the open list.
00164   int id = Coord2Id(x, y);
00165   
00166   Node *check = NULL;
00167   
00168   if(check = CheckList(m_open, id)) {
00169     node->children[node->numChildren++] = check;
00170     
00171     // We have found an awesome route, update the node and variables.
00172     if(g < check->g) {
00173       check->parent = node;
00174       check->g      = g;
00175       check->f      = g+check->h;
00176       //Func(udNotifyChild, node, check, NC_OPENADD_UP, NCData);
00177     } else {
00178       //Func(udNotifyChild, node, check, 2, NCData);
00179     }
00180   } else if(check = CheckList(m_closed, id)) {
00181     node->children[node->numChildren++] = check;
00182       
00183     if(g < check->g) {
00184     check->parent = node;
00185     check->g      = g;
00186     check->f      = g+check->h;
00187     //Func(udNotifyChild, node, check, 3, NCData);
00188 
00189     // Update the parents.
00190     UpdateParents(check);
00191     } else {
00192       //Func(udNotifyChild, node, check, 4, NCData);
00193     }
00194   } else {
00195     Node *newnode = new Node(x, y);
00196     newnode->parent = node;
00197     newnode->g  = g;
00198     newnode->h  = abs(x - m_destx) + abs(y - m_desty);
00199     newnode->f  = newnode->g + newnode->h;
00200     newnode->id = Coord2Id(x, y);
00201         
00202     AddToOpen(newnode);
00203     node->children[node->numChildren++] = newnode;
00204     
00205     //Func(udNotifyChild, node, newnode, 5, NCData);
00206   }
00207 }  
00208 
00209 
00210 void AStar::UpdateParent(Node *node) {
00211   int g = node->g;
00212   int c = node->numChildren;
00213   
00214   Node *child = NULL;
00215   for(int i = 0; i < c; i++) {
00216     child = node->children[i];
00217     if(g + 1 < child->g) {
00218       child->g = g + 1;
00219       child->f = child->g + child->h;
00220       child->parent = node;
00221       Push(child);
00222     } 
00223   }
00224   Node *parent;
00225   
00226   while(m_stack) {
00227     parent = Pop();
00228     c = parent->numC22hildren;
00229     for(int i = 0; i < c; i++) {
00230       child = parent->children[i];
00231 
00232       if(parent->g + 1 < child->g) {
00233         child->g = parent->g + Func(udCost, parent, child, NC_INITIALADD, CBData);
00234         child->f = child->g + child->h;
00235         child->parent = parent;
00236         Push(child);
00237       }
00238     }
00239   }
00240 }
00241 
00242 void AStar::Push(Node *node) {
00243   if(!m_stack) {
00244      m_stack = new Stack;
00245      m_stack->data = node;
00246      m_stack->next = NULL;
00247   } else {
00248     Stack *temp = new Stack;
00249     temp->data  = node;
00250     temp->next  = m_stack;
00251     m_stack = temp;
00252   }    
00253 }
00254 
00255 Node AStar::*Pop(void) {
00256   Node *data  = m_stack->data;
00257   Stack *temp = m_stack;
00258 
00259   m_stack = temp->next;
00260   delete temp;
00261 
00262   return data;
00263 }
00264 
00265 Node AStar::*CheckList(Node *node, int id) {
00266   while(node) {
00267     if(node->id == id)  return node; 
00268     
00269     node = node->next;
00270   }
00271   return NULL;
00272 }
00273 
00274 // Get the best node in the open list to enable us to find
00275 // the best route to take.
00276 Node AStar::*GetBest(void) {
00277   if(!m_open) { return NULL; }
00278   
00279   Node *temp  = m_open;
00280   Node *temp2 = m_closed;
00281   m_open = temp->next;
00282 
00283   //Func(udNotifyList, NULL, temp, NL_DELETEOPEN, NCData);                           
00284   m_closed = temp;
00285   m_closed->next = temp2;
00286   //Func(udNotifyList, NULL, m_closed, NL_ADDCLOSED, NCData);
00287 
00288   return temp;
00289 }
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Defines