Search code examples
c#path-findingstack-overflow

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).


Solution

  • 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.