Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does A* not find the optimal path?

I implemented the A*-pathfinding in a simple Winforms application. Where one can also define obstacles on the grid so the agent can navigate around them.

The Problem is my agent can't foresee paths. This is why he does not always take the optimal path.

Here you can see my exact problem.

How can I make the pathfinder anticipate the shorter paths? There is also an issue with dead ends once the agent took the wrong path.

This Method gets the adjascent cells and calculates the values:

public void addAdjascent(Vector pos) 
    {

        foreach(Cell cell in allCells)
        {
            bool containedInClosedList = closedList.Any(c => c.id == cell.id);

            if (!containedInClosedList)
            {


            if (cell.positionCR.X == pos.X - 1 && cell.positionCR.Y == pos.Y)
            {

                bool containedInBlockedList = blockedList.Any(c => c.id == cell.id);

                if(!containedInBlockedList)
                {
                    cell.H = calcH(goal,cell);
                    cell.G = calcG(start, cell);
                    cell.F = cell.G + cell.H;
                    openList.Add(cell);
                }



            }

            if (cell.positionCR.X == pos.X + 1 && cell.positionCR.Y == pos.Y)
            {
                bool containedInBlockedList = blockedList.Any(c => c.id == cell.id);

                if (!containedInBlockedList)
                {
                    cell.H = calcH(goal, cell);
                    cell.G = calcG(start, cell);
                    cell.F = cell.G + cell.H;
                    openList.Add(cell);
                }
            }

            if (cell.positionCR.X == pos.X  && cell.positionCR.Y == pos.Y - 1)
            {
                bool containedInBlockedList = blockedList.Any(c => c.id == cell.id);

                if (!containedInBlockedList)
                {
                    cell.H = calcH(goal, cell);
                    cell.G = calcG(start, cell);
                    cell.F = cell.G + cell.H;
                    openList.Add(cell);
                }


            }

            if (cell.positionCR.X == pos.X && cell.positionCR.Y == pos.Y + 1)
            {
                bool containedInBlockedList = blockedList.Any(c => c.id == cell.id);

                if (!containedInBlockedList)
                {
                    cell.H = calcH(goal, cell);
                    cell.G = calcG(start, cell);
                    cell.F = cell.G + cell.H;
                    openList.Add(cell);
                }                    
            }

            if (cell.positionCR.X == pos.X - 1 && cell.positionCR.Y == pos.Y - 1)
            {
                bool containedInBlockedList = blockedList.Any(c => c.id == cell.id);

                if (!containedInBlockedList)
                {
                    cell.H = calcH(goal, cell);
                    cell.G = calcG(start, cell);
                    cell.F = cell.G + cell.H;
                    openList.Add(cell);
                }
            }

            if (cell.positionCR.X == pos.X - 1 && cell.positionCR.Y == pos.Y + 1)
            {
                bool containedInBlockedList = blockedList.Any(c => c.id == cell.id);

                if (!containedInBlockedList)
                {
                    cell.H = calcH(goal, cell);
                    cell.G = calcG(start, cell);
                    cell.F = cell.G + cell.H;
                    openList.Add(cell);
                }
            }

            if (cell.positionCR.X == pos.X + 1 && cell.positionCR.Y == pos.Y - 1)
            {
                bool containedInBlockedList = blockedList.Any(c => c.id == cell.id);

                if (!containedInBlockedList)
                {
                    cell.H = calcH(goal, cell);
                    cell.G = calcG(start, cell);
                    cell.F = cell.G + cell.H;
                    openList.Add(cell);
                }
            }

            if (cell.positionCR.X == pos.X + 1 && cell.positionCR.Y == pos.Y + 1)
            {
                bool containedInBlockedList = blockedList.Any(c => c.id == cell.id);

                if (!containedInBlockedList)
                {
                    cell.H = calcH(goal, cell);
                    cell.G = calcG(start, cell);
                    cell.F = cell.G + cell.H;
                    openList.Add(cell);
                }
            }

            }

        }
    }

Here is the code for the calculation of G and H values:

    public int calcG(Vector start,Cell cell) 
    {
        int distance = closedList.Count;

        return distance;
    }

    public int calcH(Vector goal, Cell cell) 
    {

        int distance;

        int distanceX = (goal.X) - cell.positionCR.X;
        int distanceY = (goal.Y) - cell.positionCR.Y;

        if (distanceX < 0)
        {
            distanceX = distanceX * -1;
        }

        if (distanceY < 0)
        {
            distanceY = distanceY * -1;
        }

        distance = distanceX + distanceY;

        return distance;

    }

And finally I calculate the next cell I want to step on:

public void step() 
    {
        addAdjascent(stepPos);
        bool foundDestination = false;
        int min = 8000;

        foreach(Cell openCell in openList)
        {
            if (openCell.F < min) 
            {
                min = openCell.F;
            }
        }

        if(openList.Count > 0)
        {
            foreach (Cell openCell in openList)
            {
                if (openCell.positionCR.X == goal.X && openCell.positionCR.Y == goal.Y)
                {
                    closedList.Add(openCell);
                    stepPos = openCell.positionCR;
                    foundDestination = true;
                }
            }
        }            

        if(!foundDestination)
        {
            closedList.Add(openList.First(item => item.F == min));
            stepPos = openList.First(item => item.F == min).positionCR;

        }

        openList.Clear();
    }
like image 277
チーズパン Avatar asked Dec 09 '25 00:12

チーズパン


1 Answers

The problem with your implementation is that you've not fully implemented the A* algorithm. You've only implemented (in your step method) the next best guess for a single step in the algorithm.

The algoritm is meant to be executed in full until the finish has been reached and no more shorter paths (estimate) are in your open list. After doing this, you can construct the shortest path from the results. And then you can take the right step.

A* was never meant to give a an immediate answer as of what your next step should be without actually calculating the entire path. If implemented correctly, it will give you the optimal path, as long as your heuristic to estimate the remainder from a given point never overestimates the actual remaining distance.

I would suggest doing some further reading on how the A* algorithm is supposed to be implemented. A good start would probably be wikipedia.

like image 100
René Wolferink Avatar answered Dec 11 '25 13:12

René Wolferink