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