好的我正在尝试创建一个动态路径系统,以便玩家可以在没有预定义路径的情况下从A点移动到B点。注意这个游戏都是基于文本的没有图形。玩家可以在10个方向上移动:上,下,n,e,s,w,sw,se,nw和ne。
整个世界的地图都在一个数据库中,数据库的每一行都包含一个房间或一个节点,每个房间/节点都有它能够前往的方向。房间可能不是连续的。一个例子:
Map Number, Room Number, Direction_N, Direction_S, Direction_E, Direction_W, etc.
1 1 1/3 1/100 1/1381 1/101
Direction_N表示它转到地图1房间3,方向_地图1房间100等...
好的,我通过建议重新编写代码(顺便说一句,谢谢你们!)这里是修改后的代码。它现在似乎找到了房间,甚至距离很远!但现在的问题是找到通往目的地的最短路径,我尝试遍历该集合,但路径不正确......
在下面的图片链接中,我的中心有红色方块,左上角有红色方块的停止点。这将返回visitedStartRooms = 103和visitedStopRooms = 86,当时它只有大约16个房间。 把我想念的那块拼图错了,我不知道如何整理那些收藏中的房间以获得真正的最短路线。
这是新代码
public void findRoute(ROOM_INFO startRoom, ROOM_INFO destinationRoom)
{
Dictionary<ROOM_INFO, bool> visitedStartRooms = new Dictionary<ROOM_INFO, bool>();
Dictionary<ROOM_INFO, bool> visitedStopRooms = new Dictionary<ROOM_INFO, bool>();
List<string> directions = new List<string>();
startQueue.Enqueue(startRoom); // Queue up the initial room
destinationQueue.Enqueue(destinationRoom);
visitedStartRooms.Add(startRoom, true);// say we have been there, done that
visitedStopRooms.Add(destinationRoom, true);
string direction = "";
bool foundRoom = false;
while (startQueue.Count != 0 || destinationQueue.Count != 0)
{
ROOM_INFO currentStartRoom = startQueue.Dequeue(); // remove room from queue to check out.
ROOM_INFO currentDestinationRoom = destinationQueue.Dequeue();
ROOM_INFO startNextRoom = new ROOM_INFO();
ROOM_INFO stopNextRoom = new ROOM_INFO();
if (currentStartRoom.Equals(destinationRoom))
{
break;
}
else
{
// Start from destination and work to Start Point.
foreach (string exit in currentDestinationRoom.exitData)
{
stopNextRoom = extractMapRoom(exit); // get adjacent room
if (stopNextRoom.Equals(startRoom))
{
visitedStopRooms.Add(stopNextRoom, true);
foundRoom = true;
break;
}
if (stopNextRoom.mapNumber != 0 && stopNextRoom.roomNumber != 0)
{
if (!visitedStopRooms.ContainsKey(stopNextRoom))
{
if (visitedStartRooms.ContainsKey(stopNextRoom))
{
foundRoom = true;
}
else
{
destinationQueue.Enqueue(stopNextRoom);
visitedStopRooms.Add(stopNextRoom, true);
}
}
}
}
if (foundRoom)
{
break;
}
}
// start from the start and work way to destination point
foreach (string exit in currentStartRoom.exitData)
{
startNextRoom = extractMapRoom(exit); // get adjacent room
if (startNextRoom.Equals(destinationRoom))
{
visitedStartRooms.Add(startNextRoom, true);
foundRoom = true;
break;
}
if (startNextRoom.mapNumber != 0 && startNextRoom.roomNumber != 0)
{
if (!visitedStartRooms.ContainsKey(startNextRoom))
{
if (visitedStopRooms.ContainsKey(startNextRoom))
{
foundRoom = true;
break;
}
else
{
startQueue.Enqueue(startNextRoom);
visitedStartRooms.Add(startNextRoom, true);
}
}
}
}
if (foundRoom)
{
break;
}
}
}
答案 0 :(得分:1)
你有个好的开始。有一些基本的改进会有所帮助。首先,为了能够重建您的路径,您应该创建一个新的数据结构来存储访问过的房间。但是对于每个条目,您希望存储房间,以及路径中的前一个房间返回起点。对此的良好数据结构是字典,其中密钥是房间标识符,并且值是先前的房间标识符。要知道您是否访问过某个房间,您需要查看它是否存在于该数据结构中,而不是您的openList队列中。使用这种新结构,您可以正确检查您是否已经访问过一个房间,并且您可以通过反复查找同一结构中的前一个房间来重建路径,直到您到达起始位置。
第二项改进将大大提高性能。而不仅仅是从起点开始进行广度优先搜索,直到你碰到目的地,就像你现在所做的那样,而是创建与开始房间搜索一样的匹配数据结构,但让它们用于目的地房间。在您从一开始就看到一个房间后,看看距离目的地一个房间。重复这个......距离开始两个房间,然后距离目的地两个房间..等等,一直工作,直到你发现一个房间,从你开始搜索和从目的地搜索。建立从这个房间回到开始,然后回到目的地的路径,这将是你最短的路径。
您要解决的问题是未加权边缘的最短路径问题或所有边缘的权重相等的问题。边缘的重量是从一个房间移动到另一个房间的时间/成本。如果从一个房间移动到另一个房间的成本取决于您正在谈论的那对房间,那么问题就更复杂了,您开始使用的算法以及我建议修改的算法将无法正常工作是。以下是一些关于它的链接:
Shortest path (fewest nodes) for unweighted graph
http://en.wikipedia.org/wiki/Shortest_path_problem
您可能也对使用不同方法的A *算法感兴趣。它使用一种hueristic方法将搜索集中在更可能包含最短路径的解决方案空间的子集中。 http://en.wikipedia.org/wiki/A%2a_search_algorithm 但是A *在您的情况下可能有点过分,因为所有房间的所有边缘的重量都是相同的。