首先,我是一个使用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无法通行并且回溯......哈哈。虽然我开始做很多我教授所说的“黑客代码”,我不断添加补丁来修复问题,因为我不想删除我的“宝贝”并重新开始。虽然我愿意重做它,看看我的一些代码是多么混乱和无组织困扰我,迫不及待地想要采用数据结构。
任何建议都将受到赞赏。
答案 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中的任务非常简单:每次都回到我们来自的位置,并在列表中跟踪这些位置。最后,您将拥有一个列表,该列表构成从C
到S
的最短路径。然后你只需要反转这个列表就可以得到答案了。
我会给出一些伪代码来解释它。互联网上有很多真实的代码示例(在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
在每次迭代中,您需要:
根据您发布的ASCII图表,并不是绝对清楚板子的高度超过3&amp;实际上有一条路径 - 但我们假设存在。
正确的A *算法不会“卡住” - 当打开列表为空时,不存在路径&amp;它终止返回一个无路径null
。
我怀疑你可能没有关闭开放节点(这应该在你开始处理它们时完成),或者可能不会在每次迭代时处理所有开放节点。
使用Map<GridPosition, AStarNode>
将有助于检查所有相邻位置,无论是在开放还是封闭的位置/列表中。