简体   繁体   中英

C# A* Algorithm StackOverflowException

I am having a bit of trouble perfecting my A* algorithm. I works pretty well but needs some fine tuning. I am getting a StackOverflowException while checking to see if my tile is valid. The Exception occurs either at the aStar() method or the isValid() function. Here is my code:

    private void aStar(int x, int y) { //Problem
        Point[] refPoints = { new Point(x - 1, y), new Point(x, y - 1), new Point(x, y + 1), new Point(x + 1, y) };
        Point lowPoint = new Point(x, y);
        int lowCost = 1000;

        for (int i = 0; i < refPoints.Length; i++) {
            if (isValid(refPoints[i], true)) { //Problem
                map[refPoints[i].X, refPoints[i].Y].H = Math.Abs(refPoints[i].X - player.X) + Math.Abs(refPoints[i].Y - player.Y);
                map[refPoints[i].X, refPoints[i].Y].G = map[x, y].G + 10;
                map[refPoints[i].X, refPoints[i].Y].F = map[refPoints[i].X, refPoints[i].Y].H + map[refPoints[i].X, refPoints[i].Y].G;

                if (map[refPoints[i].X, refPoints[i].Y].F < lowCost) {
                    lowCost = map[refPoints[i].X, refPoints[i].Y].F;
                    lowPoint = refPoints[i];
                }

                map[refPoints[i].X, refPoints[i].Y].AType = AType.OPEN;
            }
        }

        if (!(lowPoint.Equals(player))) {
            map[lowPoint.X, lowPoint.Y].AType = AType.CLOSED;
            path.Add(lowPoint);
            aStar(lowPoint);
        }
    }

    private void aStar(Point p) {
        aStar(p.X, p.Y); //Problem
    }

    private bool isValid(int x, int y, bool aStar) { //Problem
        if (aStar) {
            return (x >= 0 && x < tileX && y >= 0 && y < tileY && !map[x, y].TileType.Equals(TileType.BLOCK) && 
                !map[x, y].AType.Equals(AType.CLOSED) && !map[x, y].AType.Equals(AType.OPEN));
        } else {
            return (x >= 0 && x < tileX && y >= 0 && y < tileY && !map[x, y].TileType.Equals(TileType.BLOCK));
        }
    }

    private bool isValid(Point p, bool aStar) {
        return isValid(p.X, p.Y, aStar); //Problem
    }

I cannot seem to trace the origin of the problem but it only happens sometimes (usually when there is an obstacle in the way, but not always).

Instead of an open and closed list in my code I have an enum (AType) in each Tile of my map (BLANK, OPEN, CLOSED). The OPEN enum really doesn't affect anything except mark tiles that have been tested and are not the best move. The CLOSED enum is just applied to all Tiles that are identified as the best move thus eventually building a path. The BLANK enum is just the default state of the Tile (neither in the open or closed list).

A* does not have a recursive step. You should be pulling work items out of a priority queue.

Your code is tail recursive. There is no need for recursion here. Just wrap the entire method in a while (true) loop:

private void aStar(int x, int y) {
    while (true) {
    //...
    if (!(lowPoint.Equals(player))) {
        map[lowPoint.X, lowPoint.Y].AType = AType.CLOSED;
        path.Add(lowPoint);
        continue;
    }
    else break;
}
}

I suspect the StackOverflowEx is gone after making this change but the algorithm will not work because I don't see a priority queue anywhere.

What you're basically doing:

void foo(Point a)
{
   ...
   foo(a.X, a.Y);
}
void foo(int x, int y)
{
   foo(new Point(x, y));
}

Now, recursion can be very handy, but in this case it isn't, because it isn't necessary and it'll simply get called too much, causing a StackOverFlow . So you need to redesign the function so you it doesn't call itself, but instead having a while loop with a certain condition.

Something like this:

void aStar(int x, int y)
{
   // just declarations to show you
   Path path;
   Point currentPoint;
   while (true)
   {
      // Your modified function goal. Instead of calling the function, just let the loop continue
      // if node is goal, break
      if (!(lowPoint.Equals(player)))
      {
        map[lowPoint.X, lowPoint.Y].AType = AType.CLOSED;
        path.Add(lowPoint);
        aStar(lowPoint);
      }
      else
      {
        break;
      }
   }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM