www.pudn.com > Sterren_ASe_Explorer.rar > PathFinder.cpp
/* Copyright (C) William van der Sterren, 2002. * All rights reserved worldwide. * * This software is provided "as is" without express or implied * warranties. You may freely copy and compile this source into * applications you distribute provided that the copyright text * below is included in the resulting source code, for example: * "Portions Copyright (C) William van der Sterren, 2002" */ /* Copyright (C) James Matthews, 2001. * All rights reserved worldwide. * * This software is provided "as is" without express or implied * warranties. You may freely copy and compile this source into * applications you distribute provided that the copyright text * below is included in the resulting source code, for example: * "Portions Copyright (C) James Matthews, 2001" */ ////////////////////////////////////////////////////////////////// // Class: CAStar class (27/6/2001) // File: AStar.cpp // Author: James Matthews // // Implements the A* algorithm. // // // Please visit http://www.generation5.org/ for the latest // in Artificial Intelligence news, interviews, articles and // discussion forums. // #include#include "PathFinder.h" CAStar::CAStar() : udTerrainCost(0), udTerrainHeuristic(0), udThreatCost(0), udThreatHeuristic(0) { m_pOpen = m_pClosed = NULL; m_pStack = NULL; m_pBest = NULL; udValid = NULL; udNotifyChild = NULL; udNotifyList = NULL; } CAStar::~CAStar() { ClearNodes(); } void CAStar::ClearNodes() { _asNode *temp = NULL, *temp2 = NULL; if (m_pOpen) { while (m_pOpen) { temp = m_pOpen->next; delete m_pOpen; m_pOpen = temp; } } if (m_pClosed) { while (m_pClosed) { temp = m_pClosed->next; delete m_pClosed; m_pClosed = temp; } } } ///////////////////////////////////////////////// // CAStar::GeneratePath(int, int, int, int) // // Main A* algorithm. The step functions are used // to keep code redundancy to a minimum. // bool CAStar::GeneratePath(int sx, int sy, int dx, int dy) { StepInitialize(sx, sy, dx, dy); int retval = 0; while (retval == 0) { retval = Step(); }; if (retval == -1 || !m_pBest) { m_pBest = NULL; return false; } return true; } void CAStar::StepInitialize(int sx, int sy, int dx, int dy) { ClearNodes(); m_iSX = sx; m_iSY = sy; m_iDX = dx; m_iDY = dy; m_iDNum = Coord2Num(dx,dy); _asNode *temp = new _asNode(sx, sy); _asNode dest(dx, dy); temp->SetG(0); temp->SetH(udTerrainHeuristic(temp, &dest) + udThreatHeuristic(temp, &dest)); temp->UpdateF(); temp->SetID(Coord2Num(sx, sy)); m_pOpen = temp; udFunc(udNotifyList, NULL, m_pOpen, ASNL_STARTOPEN, m_pNCData); udFunc(udNotifyChild, NULL, temp, 0, m_pNCData); } int CAStar::Step() { if (!(m_pBest = GetBest())) return -1; // check for arrival at destination if ( m_pBest->GetID() == m_iDNum ) return 1; CreateChildren(m_pBest); return 0; } _asNode *CAStar::GetBest() { if (!m_pOpen) return NULL; _asNode *temp = m_pOpen, *temp2 = m_pClosed; m_pOpen = temp->next; udFunc(udNotifyList, NULL, temp, ASNL_DELETEOPEN, m_pNCData); m_pClosed = temp; m_pClosed->next = temp2; udFunc(udNotifyList, NULL, m_pClosed, ASNL_ADDCLOSED, m_pNCData); return temp; } void CAStar::CreateChildren(_asNode *node) { _asNode temp; int x = node->GetX(); int y = node->GetY(); for (int i=-1;i<2;i++) { for (int j=-1;j<2;j++) { temp.SetXY(x+i, y+j); if (i == 0 && j == 0 || !udFunc(udValid, node, &temp, 0, m_pCBData)) continue; LinkChild(node, &temp); } } } void CAStar::LinkChild(_asNode *node, _asNode *temp) { int x = temp->GetX(); int y = temp->GetY(); float g = node->GetG() + udTerrainCost(node, temp) + udThreatCost(node, temp); float t = temp->GetThreatAimQuality(); int id = Coord2Num(x,y); _asNode *check = NULL; if (check = CheckList(m_pOpen, id)) { node->AddChild(check); // A better route found, so update // the node and variables accordingly. if ( g < check->GetG() ) { check->SetParent(node); check->SetThreatAimQuality(t); check->SetG(g); check->UpdateF(); udFunc(udNotifyChild, node, check, ASNC_OPENADD_UP, m_pNCData); } else { udFunc(udNotifyChild, node, check, ASNC_OPENADD, m_pNCData); } } else if (check = CheckList(m_pClosed, id)) { node->AddChild(check); if ( g < check->GetG() ) { check->SetParent(node); check->SetThreatAimQuality(t); check->SetG(g); check->UpdateF(); udFunc(udNotifyChild, node, check, ASNC_CLOSEDADD_UP, m_pNCData); // The fun part... //! \todo remove UpdateParents call //UpdateParents(check); } else { udFunc(udNotifyChild, node, check, ASNC_CLOSEDADD, m_pNCData); } } else { _asNode dest(m_iDX, m_iDY); _asNode *newnode = new _asNode(x,y); newnode->SetParent(node); newnode->SetThreatAimQuality(t); newnode->SetG(g); newnode->SetH(udTerrainHeuristic(newnode, &dest) + udThreatHeuristic(newnode, &dest)); newnode->UpdateF(); newnode->SetID(Coord2Num(x,y)); AddToOpen(newnode); node->AddChild(newnode); udFunc(udNotifyChild, node, newnode, ASNC_NEWADD, m_pNCData); } } _asNode *CAStar::CheckList(_asNode *node, int anID) { while (node) { if (node->GetID() == anID) return node; node = node->next; } return NULL; } void CAStar::AddToOpen(_asNode *addnode) { _asNode *node = m_pOpen; _asNode *prev = NULL; if (!m_pOpen) { m_pOpen = addnode; m_pOpen->next = NULL; udFunc(udNotifyList, NULL, addnode, ASNL_STARTOPEN, m_pNCData); return; } while( node ) { if ( addnode->GetF() > node->GetF() ) { prev = node; node = node->next; } else { if (prev) { prev->next = addnode; addnode->next = node; udFunc(udNotifyList, prev, addnode, ASNL_ADDOPEN, m_pNCData); } else { _asNode *temp = m_pOpen; m_pOpen = addnode; m_pOpen->next = temp; udFunc(udNotifyList, temp, addnode, ASNL_STARTOPEN, m_pNCData); } return; } } prev->next = addnode; udFunc(udNotifyList, prev, addnode, ASNL_ADDOPEN, m_pNCData); } int CAStar::udFunc(_asFunc func, _asNode *param1, _asNode *param2, int data, void *cb) { if (func) return func(param1, param2, data, cb); return 1; }