【问题标题】:Depth first search - 2D Game map深度优先搜索 - 2D 游戏地图
【发布时间】:2012-03-21 18:46:52
【问题描述】:

我创建了一个 2D 迷宫,我想找到红色->蓝色节点之间的最快路径。我不确定如何实施深度优先搜索。我知道可以使用邻接矩阵或列表来表示节点之间的连接。不过,我不确定如何构建它。

为简洁起见:我需要返回一个包含搜索到的图块坐标的列表(在寻找目标节点时),这样我就可以描述在迷宫中的搜索。或者我将如何为此构造一个邻接矩阵?以及对应的顶点列表?

深度优先搜索一般结构

  1. 访问节点(单元格)(将访问标志更改为真)
  2. 推送到堆栈
  3. 如果没有(弹出堆栈)则获取未访问的顶点(窥视堆栈) - 更新迷宫模型视图

重复 1 - 3 直到堆栈为空

这是迷宫类的当前代码。

public class Maze {

    //Tile ids
    public static short OBSTICLE = 0;
    public static short START_LOC_VALUE = -2;
    public static short GOAL_LOC_VALUE = -3;

    private int rows, cols;
    private int numTiles;
    private int[][] map;
    private int[][] adjMatrix;
    private Queue theQueue; 

    public Maze(int rows, int cols){
        this.rows = rows;
        this.cols = cols;

        theQueue = new Queue();

        numTiles = rows*cols;

        map = new int[rows][cols];
        adjMatrix = new int[rows][cols];

        for (int i=0; i<rows; i++) {
            for (int j=0; j<cols; j++) {
                map[i][j] = 1;
            }
        }
    }

    /*
     * Generate Maze
     * @param numObstacles - number of obstacles
     */
    public void generateMaze(int numObstacles){
        for (int i = 0; i < numObstacles; i++)
            setTile((int)(Math.random()*rows),(int)(Math.random()*cols), Maze.OBSTICLE);

       //setTile((int)(Math.random()*rows),(int)(Math.random()*cols),Maze.START_LOC_VALUE);
       //setTile((int)(Math.random()*rows),(int)(Math.random()*cols),Maze.GOAL_LOC_VALUE);
        createAdjMatrix();
    }

    public void createAdjMatrix(){
        for (int i=0; i<rows; i++) {
            for (int j=0; j<cols; j++) {
                if (map[i][j] == 1) {
                    addEdge(i,j);
                }
            }
        }
    }

     /*
     * Set Tile
     * @param x - x cord
     * @param y - y cord
     * @param entity - OBSTICLE,START_LOC_VALUE or GOAL_LOC_VALUE ID
     */
    public void setTile(int x, int y, short entity){
        this.map[x][y] = entity;
    }

    public void addEdge(int start, int end) {//Start and end arguments index multidimensional array
            adjMatrix[start][end] = 1;
            adjMatrix[end][start] = 1;
    }

    public void bfs(int startDest, int goalDest) // breadth-first search
        { 
            // begin at vertex 0
            vertexList[startDest].wasVisited = true; // mark it
            displayVertex(startDest); // display it
            theQueue.enQueue(startDest); // insert at tail
            int v2;

            while (!theQueue.isEmpty()) // until queue empty,
            {
                int v1 = theQueue.deQueue(); // remove vertex at head

                // until it has no unvisited neighbors
                while ((v2 = getAdjUnvisitedVertex(v1)) != -1)
                { // get one,

                    vertexList[v2].wasVisited = true; // mark it
                    displayVertex(v2); // display it
                    theQueue.enQueue(v2); // insert it

                } // end while(unvisited neighbors)
            } // end while(queue not empty)

            // queue is empty, so we’re done
            for (int j = 0; j < nVerts; j++) // reset flags
                vertexList[j].wasVisited = false;
        }// end bfs()

     /*
     * Drawn Maze
     * @param g - Graphics object
     */
    public void draw(Graphics g){
        for (int y = 0; y < cols; y++) 
            for (int x = 0; x < rows; x++) {
                int val = map[x][y];

                if (val==Maze.OBSTICLE) {
                    g.setColor(Color.BLACK);
                    g.fillRect(x*20, y*20, 20, 20);
                }else if(val == Maze.START_LOC_VALUE){
                    g.setColor(Color.RED);
                    g.fillRect(x*20, y*20, 20, 20);
                }else if(val==Maze.GOAL_LOC_VALUE){
                    g.setColor(Color.BLUE);
                    g.fillRect(x*20, y*20, 20, 20);
                }else{
                    g.setColor(Color.BLACK);
                    g.drawRect(x*20, y*20, 20, 20); 
                }
            } 
    }
}

当前 DFS 代码..

public void dfs(int vertexStart) // depth-first search
        { 
            // begin at vertexStart
            vertexList[vertexStart].wasVisited = true; // mark it
            displayVertex(vertexStart); // display it
            theStack.push(vertexStart); // push it

            while (!theStack.isEmpty()) // until stack empty,
            {
                // get an unvisited vertex adjacent to stack top
                int v = getAdjUnvisitedVertex(theStack.peek());

                if (v == -1) // if no such vertex,
                    theStack.pop(); // pop a new one
                else // if it exists,
                {
                    vertexList[v].wasVisited = true; // mark it
                    displayVertex(v); // display it
                    theStack.push(v); // push it
                }
            } // end while
    }

下图描绘了迷宫结构,它是伪随机生成的;最终的迷宫实现将被完善。

谢谢,如果你能指引我正确的方向,我会很高兴......

【问题讨论】:

    标签: java algorithm simulation


    【解决方案1】:

    对于 2D 迷宫,您可以简单地使用 Breadth First Search 而不是深度优先搜索,如果您有 n*n 迷宫,它将在 O(n2) 中找到它。

    但还有另一种选择,这是一种标签和 BFS,适用于您的迷宫(无需绘制图表)。

    编号算法

    理解广度优先搜索的一个有趣的方法是这样做(对于迷宫):

    1. 将所有单元格设置为0,将块设置为-1

    2. 从你的源位置开始设置为1,全部标记为0 邻居到 2,并将所有 2 保存在列表中。之后标记全部为0 2 到 3 的邻居,清除 2 的列表并保存 3 的列表,然后继续 到达目的地。在每个级别只是不改变 源值。

    3. 现在假设你在目的地并且你想找到路径,你的 目的地得分为m,找到得分为m-1的邻居,....并输出路径。

    事实上,正常且简单的 BFS 方式是使用 Q,但我提供这个是因为它很简单,因为它模拟了 Q 方式。

    使用邻接矩阵

    为了创建邻接矩阵,你应该命名节点和边,所以你可以有一个像下面这样的边和节点类(我用伪 C# 写的):

    public class Edge
    {
    
       public Edge(Node start, Node end, decimal weight)
       {
          StartNode = ...,...,...
       }
       public Node StartNode;
       public Node EndNode;
       public decimal weight;
       public bool IsDirected;
    }
    
    public class Node
    {
       public Node(int index)
       {
            this.Index = index;
       }
       public int Index;
       public List<Edge> Edges = new List<Edge>();
       public bool Visited = false;
    }
    

    现在您的图表是您的节点对象的列表:

    public class Graph
    {
       public List<Node> Nodes = new List<Node>();
    }
    

    对于迷宫建模,您应该选择单元格作为节点,并在相邻单元格之间绘制边缘。 我将把它留给你如何添加节点到你的图表。

    【讨论】:

    • 我将如何为此构造一个邻接矩阵?以及对应的顶点列表?为了执行 BFS。
    • @Hmm,我用类似的解决方案更新了我的答案,直到你读到这个,我会写邻接矩阵。
    • 好的,感谢您提供更多信息,只需要一些关于邻接矩阵的信息 - 以确定小区邻居,谢谢。
    • @Hmm,我为邻接矩阵添加了额外的信息,您可以将其嵌入到您的节点中。第二种方式(使用数字)不使用图形,它使用迷宫单元。
    • @Hmm,是的,这已经足够了,现在您可以使用 (i-1,j),.... 找到单元格 (i,j) 的邻接单元格,然后运行编号算法它。我建议你实现两种方式(使用图形和使用编号)来很好地理解它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-31
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多