【问题标题】:Pathfinding issues寻路问题
【发布时间】:2012-06-23 21:26:51
【问题描述】:

好的,我正在尝试制作一个动态路径系统,以便玩家可以在没有预定义路径的情况下从 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 表示它去 Map 1 Room 3,Direction_S Map 1 Room 100 等等...

好的,我根据建议重新编写了代码(顺便谢谢你们!)这里是修改后的代码。它现在似乎找到了房间,甚至是很远的距离!但是现在的问题是找到到目的地的最短路径,我尝试遍历集合但路径不正确......

在下面的图片链接中,我在中心的红色正方形中有起点,在左上角的红色正方形中有终点。这将返回visitedStartRooms = 103 和visitedStopRooms = 86,此时只有大约16 个房间。 问我缺少的难题是我不知道如何整理这些集合中的房间以获得真正的最短路线。

Example of map

这是新代码

        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;
            }
        }

    }

【问题讨论】:

  • 算法中的一个问题是您使用队列来查看您是否访问过一个房间。但是如果你访问了一个已经出队的房间,你会认为你还没有访问过它,所以你会花很多时间重新搜索已经走过的路径。这可能就是长距离性能下降如此之快的原因。

标签: path-finding


【解决方案1】:

你有一个好的开始。有一些基本的改进会有所帮助。首先,为了能够重建您的路径,您应该创建一个新的数据结构来存储访问过的房间。但是对于每个条目,您要存储房间,以及返回起点的路径中的前一个房间。一个好的数据结构是一个字典,其中键是房间标识符,值是以前的房间标识符。要知道您是否访问过一个房间,您需要查看它是否存在于该数据结构中,而不是您的 openList 队列中。使用这种新结构,您可以正确检查您是否访问过一个房间,并且您可以通过重复查找同一结构中的前一个房间来重建返回路径,直到您到达起点。

第二个改进将大大提高性能。与其像现在一样从起点开始直到遇到目的地,而是像现在这样创建匹配的数据结构,而不是像开始房间搜索那样创建匹配的数据结构,但让它们用于目标房间。在你从一开始看一个房间之后,再看一个远离目的地的房间。重复这个……离起点两个房间,然后离目的地两个房间……等等,一直往外走,直到你发现一个房间,你从起点的搜索和从目的地的搜索都访问过这个房间。建立从这个房间到起点,再到目的地的路径,这将是你的最短路径。

您要解决的问题是具有未加权边或所有边的权重相等的最短路径问题。边缘的重量是从一个房间移动到另一个房间的时间/成本。如果从一个房间搬到另一个房间的成本取决于您所谈论的那对房间,那么问题就会更加复杂,并且您开始使用的算法以及我建议修改的算法将无法正常工作是。以下是一些关于它的链接:

Shortest path (fewest nodes) for unweighted graph

http://en.wikipedia.org/wiki/Shortest_path_problem

您可能还对使用不同方法的 A* 算法感兴趣。它使用启发式方法将搜索集中在更可能包含最短路径的解决方案空间的子集中。 http://en.wikipedia.org/wiki/A%2a_search_algorithm 但是在您的情况下,A* 可能是矫枉过正,因为所有房间的所有边的重量都是相同的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多