C#A *算法StackOverflowException

时间:2015-01-26 17:34:19

标签: c# path-finding stack-overflow

我在完善A *算法方面遇到了一些麻烦。我工作得很好,但需要一些微调。我在检查我的磁贴是否有效时收到StackOverflowException。异常发生在aStar()方法或isValid()函数中。这是我的代码:

    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
    }

我似乎无法追查问题的根源,但有时只会发生(通常在路上有障碍时,但并非总是如此)。

我的代码中每个Tile(BLANK,OPEN,CLOSED)都有一个枚举(AType),而不是我的代码中的一个打开和关闭的列表。 OPEN枚举确实不会影响除经过测试且不是最佳动作的标记拼贴以外的任何内容。 CLOSED枚举仅应用于被识别为最佳移动的所有Tiles,从而最终构建路径。 BLANK枚举只是Tile的默认状态(无论是在打开还是关闭列表中)。

2 个答案:

答案 0 :(得分:1)

A *没有递归步骤。您应该将工作项从优先级队列中拉出来。

您的代码是尾递归的。这里不需要递归。只需将整个方法包装在while (true)循环中:

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;
}
}

我怀疑StackOverflowEx在进行此更改后已消失,但算法无效,因为我在任何地方都看不到优先级队列。

答案 1 :(得分:0)

你基本上做了什么:

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

现在,递归可以非常方便,但在这种情况下它不是,因为它不是必需的,它只会被调用太多,导致StackOverFlow。 所以你需要重新设计这个函数,这样你就不会自己调用它,而是让while循环具有一定的条件。

这样的事情:

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;
      }
   }