Reputation: 4735
Is there a better way to handle my FindAdjacent() function for my A Star algorithm? It's awfully messy, and it doesn't set the parent node correctly. When it tries to find the path, it loops infinitely because the parent of the node has a pent of the node and the parents are always each other.
Any help would be amazing. This is my function:
void AStarImpl::FindAdjacent(Node* pNode)
{
for (int i = -1; i <= 1; i++)
{
for (int j = -1; j <= 1; j++)
{
if (pNode->mX != Map::GetInstance()->mMap[pNode->mX + i][pNode->mY + j].mX
|| pNode->mY != Map::GetInstance()->mMap[pNode->mX + i][pNode->mY + j].mY)
{
if (pNode->mX + i <= 14 && pNode->mY + j <= 14)
{
if (pNode->mX + i >= 0 && pNode->mY + j >= 0)
{
if (Map::GetInstance()->mMap[pNode->mX + i][pNode->mY + j].mTypeID != NODE_TYPE_SOLID)
{
if (find(mOpenList.begin(), mOpenList.end(), &Map::GetInstance()->mMap[pNode->mX + i][pNode->mY + j]) == mOpenList.end())
{
Map::GetInstance()->mMap[pNode->mX+i][pNode->mY+j].mParent = &Map::GetInstance()->mMap[pNode->mX][pNode->mY];
mOpenList.push_back(&Map::GetInstance()->mMap[pNode->mX+i][pNode->mY+j]);
}
}
}
}
}
}
}
mClosedList.push_back(&Map::GetInstance()->mMap[pNode->mX][pNode->mY]);
}
If you'd like any more code, just ask and I can post it.
Upvotes: 0
Views: 1994
Reputation: 76194
You can reduce the amount of nested ifs by using continue
. Generally speaking, the following two code blocks are equivalent:
while(conditionA){
if(conditionB){
doStuff();
}
}
while(conditionA){
if (!conditionB){continue;}
doStuff();
}
We can use this principle to reduce the amount of nested ifs in your code.
void AStarImpl::FindAdjacent(Node* pNode)
{
for (int i = -1; i <= 1; i++)
{
for (int j = -1; j <= 1; j++)
{
if (pNode->mX == Map::GetInstance()->mMap[pNode->mX + i][pNode->mY + j].mX && pNode->mY == Map::GetInstance()->mMap[pNode->mX + i][pNode->mY + j].mY){continue;}
if (pNode->mX + i > 14 || pNode->mY + j > 14){continue;}
if (pNode->mX + i < 0 || pNode->mY + j < 0){continue;}
if (Map::GetInstance()->mMap[pNode->mX + i][pNode->mY + j].mTypeID == NODE_TYPE_SOLID){continue;}
if (find(mOpenList.begin(), mOpenList.end(), &Map::GetInstance()->mMap[pNode->mX + i][pNode->mY + j]) != mOpenList.end()){continue;}
Map::GetInstance()->mMap[pNode->mX+i][pNode->mY+j].mParent = &Map::GetInstance()->mMap[pNode->mX][pNode->mY];
mOpenList.push_back(&Map::GetInstance()->mMap[pNode->mX+i][pNode->mY+j]);
}
}
mClosedList.push_back(&Map::GetInstance()->mMap[pNode->mX][pNode->mY]);
}
If I understand your first if
condition correctly, you're just trying to assert that pNode is not its own neighbor. In which case you can change the code to:
void AStarImpl::FindAdjacent(Node* pNode)
{
for (int i = -1; i <= 1; i++)
{
for (int j = -1; j <= 1; j++)
{
if (i == 0 && j == 0){continue;}
if (pNode->mX + i > 14 || pNode->mY + j > 14){continue;}
if (pNode->mX + i < 0 || pNode->mY + j < 0){continue;}
if (Map::GetInstance()->mMap[pNode->mX + i][pNode->mY + j].mTypeID == NODE_TYPE_SOLID){continue;}
if (find(mOpenList.begin(), mOpenList.end(), &Map::GetInstance()->mMap[pNode->mX + i][pNode->mY + j]) != mOpenList.end()){continue;}
Map::GetInstance()->mMap[pNode->mX+i][pNode->mY+j].mParent = &Map::GetInstance()->mMap[pNode->mX][pNode->mY];
mOpenList.push_back(&Map::GetInstance()->mMap[pNode->mX+i][pNode->mY+j]);
}
}
mClosedList.push_back(&Map::GetInstance()->mMap[pNode->mX][pNode->mY]);
}
Ideally, your FindAdjacent method should not have to modify the open or closed sets at all. instead, make it return all neighbors, regardless of whether they are open or closed. If you want to add these neighbors to the opened or closed set, or check that they are a member of those sets, that should be done in the method that actually implements the aStar algorithm.
Vector<Node> AStarImpl:FindAdjacent(Node* pNode)
{
Vector<Node> neighbors;
for (int i = -1; i <= 1; i++)
{
for (int j = -1; j <= 1; j++)
{
if (i == 0 && j == 0){continue;}
if (pNode->mX + i > 14 || pNode->mY + j > 14){continue;}
if (pNode->mX + i < 0 || pNode->mY + j < 0){continue;}
if (Map::GetInstance()->mMap[pNode->mX + i][pNode->mY + j].mTypeID == NODE_TYPE_SOLID){continue;}
neighbors.push_back(Map::GetInstance()->mMap[pNode->mX+i][pNode->mY+j]);
}
}
return neighbors;
}
You perform some of the same operations multiple times. You can make your intentions more clear by storing the results of those operations in variables. Doing this won't make your code any shorter, but it might make it more readable.
Vector<Node> AStarImpl:FindAdjacent(Node* pNode)
{
Vector<Node> neighbors;
for (int i = -1; i <= 1; i++)
{
for (int j = -1; j <= 1; j++)
{
if (i == 0 && j == 0){continue;}
int x = pNode->mX + i;
int y = pNode->mY + j;
if (x > 14 || y > 14){continue;}
if (x < 0 || y < 0){continue;}
Node candidate = Map::GetInstance()->mMap[x][y];
if (candidate.mTypeID == NODE_TYPE_SOLID){continue;}
neighbors.push_back(candidate);
}
}
return neighbors;
}
Upvotes: 2