[英]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.