简单的星形算法塔防路径被困

时间:2013-11-02 23:38:45

标签: java a-star

首先,我是一个使用Java的100级CS大学课程。我们的任务是进行塔防游戏,我遇到了路径问题。我从搜索中发现A *似乎是最好的。虽然当我把U放在路径上时,我的路径会被卡住。我将展示一些初学者的伪代码,因为我还没有学过数据结构类,而且我的代码看起来很混乱(正在研究)。

假设我不会使用对角线。

while(Castle not reached){
    new OpenList
    if(up, down, left, right == passable && isn't previous node){
         //Adds in alternating order to create a more diagonal like path
         Openlist.add(passable nodes)
    }
    BestPath.add(FindLeasDistancetoEnd(OpenList));
    CheckCastleReached(BestPath[Last Index]);
{

private node FindLeastDistancetoEnd(node n){
    return first node with Calculated smallest (X + Y to EndPoint)
}

我已经剥离了A *(太多了,我的问题最有可能)。所以我将父母添加到我的节点并计算正确的父节点,虽然我不相信这会解决我的问题。这是我的问题的视觉效果。

X =无法通行(塔)

O = OpenList

b = ClosedList(BestPath)

C = Castle(EndPoint)

S =开始

OOOOXX
SbbbBX   C
OOOOXX

现在国会大厦B是我的问题所在。将塔放置在该配置中并重新计算我的导航路径时,它会卡住。由于前一个节点被忽略而其余节点无法通过,所以没有任何内容被放入OpenList中。

现在写出来我想我可以让B无法通行并且回溯......哈哈。虽然我开始做很多我教授所说的“黑客代码”,我不断添加补丁来修复问题,因为我不想删除我的“宝贝”并重新开始。虽然我愿意重做它,看看我的一些代码是多么混乱和无组织困扰我,迫不及待地想要采用数据结构。

任何建议都将受到赞赏。

2 个答案:

答案 0 :(得分:2)

是的,数据结构可以帮助您解决这类问题。我将尝试解释A *如何工作并在之后提供更好的Pseudocode。

A *是Best-First搜索算法。这意味着它应该猜测哪个选项最好,并尝试首先探索这些选项。这需要您跟踪选项列表,通常称为“前”(如前面所示)。它不会跟踪到目前为止找到的路径,就像您当前的算法一样。该算法分两个阶段工作......

阶段1

基本上,你从起始位置S开始,所有相邻位置(北,西,南和东)都在前面。然后算法找到Front中最有希望的选项(让我们称之为P),并对其进行扩展。位置P将从Front移除,但其所有邻居都将被添加。好吧,不是所有的邻居;只有实际选择的邻居才能去。我们不能走进塔楼,我们不想回到我们以前见过的地方。从新阵线中,选择最有希望的选项,依此类推。当最有希望的选项是目标C时,算法将停止并进入第2阶段。

通常情况下,最有希望的选择是最接近目标的选项,因为乌鸦飞行(忽略障碍物)。通常,它总是会首先探索最接近目标的那个。这导致算法以一种直线走向目标。但是,如果该线被某个障碍物阻挡,则障碍物的位置应添加到前方。它们不是可行的选择。因此,在下一轮中,前线中的其他位置将被选为最佳选项,并且搜索将继续从那里开始。这就是它像你的例子中那样走出死胡同的方式。看看这个插图得到我的意思:https://upload.wikimedia.org/wikipedia/commons/5/5d/Astar_progress_animation.gif前面是空心的蓝色圆点,它们标记着它们已经处于从红色到绿色的阴影中的点,以及带有厚蓝色圆点的无法​​通行的地方

在第2阶段,我们需要一些额外的信息来帮助我们在找到目标时找到最短路径。为此,我们在每个位置存储我们来自的位置。如果算法有效,我们来自的位置必然比任何其他邻居更接近S。如果你不理解我的意思,请看下面的伪代码。

第2阶段

当找到城堡C时,下一步是找到回到起点的路,收集最佳路径。在第1阶段,我们将我们来自的位置存储在我们探索的每个位置。我们知道这个位置必须始终接近S(不要忽视障碍)。因此,阶段2中的任务非常简单:每次都回到我们来自的位置,并在列表中跟踪这些位置。最后,您将拥有一个列表,该列表构成从CS的最短路径。然后你只需要反转这个列表就可以得到答案了。

我会给出一些伪代码来解释它。互联网上有很多真实的代码示例(在Java中也是如此)。此伪代码假定您使用2D数组来表示网格。另一种方法是使用Node对象,这在Pseudocode中更容易理解,但是更难编程,我怀疑你仍然使用2D数组。

//Phase 1
origins = new array[gridLength][gridWidth]; //Keeps track of 'where we came from'.
front = new Set(); //Empty set. You could use an array for this.
front.add(all neighbours of S);
while(true) { //This keeps on looping forever, unless it hits the "break" statement below.
    best = findBestOption(front);
    front.remove(best);
    for(neighbour in (best's neighbours)) {
        if(neighbour is not a tower and origins[neighbour x][neighbour y] == null) { //Not a tower, and not a position that we explored before.
            front.add(neighbour);
            origins[neighbour x][neighbour y] = best;
        }
    }
    if(best == S) {
        break; //Stops the loop. Ends phase 1.
    }
}

//Phase 2
bestPath = new List(); //You should probably use Java's ArrayList class for this if you're allowed to do that. Otherwise select an array size that you know is large enough.
currentPosition = C; //Start at the endpoint.
bestPath.add(C);
while(currentPosition != S) { //Until we're back at the start.
    currentPosition = origins[currentPosition.x][currentPosition.y];
    bestPath.add(currentPosition);
}
bestPath.reverse();

对于伪代码中的findBestOption方法:

findBestOption(front) {
    bestPosition = null;
    distanceOfBestPosition = Float.MAX_VALUE; //Some very high number to start with.
    for(position in front) {
        distance = Math.sqrt(position.x * position.x - C.x * C.x + position.y * position.y - C.y * C.y); //Euclidean distance (Pythagoras Theorem). This does the diagonal thing for you.
        if(distance < distanceOfBestPosition) {
            distanceOfBestPosition = distance;
            bestPosition = position;
        }
    }
}

我希望这会有所帮助。随意问一下!

答案 1 :(得分:0)

正确实施A *算法。请参阅:http://en.wikipedia.org/wiki/A%2A_search_algorithm

在每次迭代中,您需要:

  1. 开放节点排序为启发式顺序
  2. 挑选最好的;
  3. - 检查您是否已达到目标,如果是,可能会终止;
  4. 现在将其标记为“已关闭”,因为它将从中充分探索。
  5. 从中探索所有邻居(通过添加开放节点地图/或列表,如果尚未已关闭)。
  6. 根据您发布的ASCII图表,并不是绝对清楚板子的高度超过3&amp;实际上有一条路径 - 但我们假设存在。

    正确的A *算法不会“卡住” - 当打开列表为空时,不存在路径&amp;它终止返回一个无路径null

    我怀疑你可能没有关闭开放节点(这应该在你开始处理它们时完成),或者可能不会在每次迭代时处理所有开放节点。

    使用Map<GridPosition, AStarNode>将有助于检查所有相邻位置,无论是在开放还是封闭的位置/列表中。