簡體   English   中英

C#A *算法StackOverflowException

[英]C# A* Algorithm StackOverflowException

我在完善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
    }

我似乎無法追蹤問題的根源,但它僅在某些情況下發生(通常是在路上有障礙,但並非總是如此)。

在我的地圖的每個圖塊(空白,打開,關閉)中都有一個枚舉(AType),而不是代碼中的打開和關閉列表。 OPEN枚舉確實不會影響任何東西,除了經過測試且不是最佳移動的標記圖塊。 CLOSED枚舉僅應用於所有被確定為最佳移動的圖塊,從而最終構建路徑。 BLANK枚舉只是Tile的默認狀態(不在打開或關閉列表中)。

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消失了,但是該算法無法正常工作,因為我在任何地方都看不到優先級隊列。

您基本上在做什么:

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

現在,遞歸可以非常方便,但是在這種情況下,它不是必需的,因為它不是必需的,它只會被調用太多,從而導致StackOverFlow 因此,您需要重新設計該函數,以便它不會調用自身,而要while特定條件下進行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;
      }
   }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM