Глубина первого поиска - 2D Game map - PullRequest
9 голосов
/ 03 марта 2012

Я создал двухмерный лабиринт и хочу найти самый быстрый путь между узлами, окрашенными в красный и синий цвета. Я не уверен, как бы я мог осуществить поиск в глубину. Я знаю, что матрица смежности или список могут быть использованы для представления связей между узлами. Хотя я не уверен, как его построить.

для краткости : Мне нужно вернуть список с искомыми координатами плиток (при поиске узла цели), чтобы я мог изобразить поиск в лабиринте. Или как бы я построить матрицу смежности для этого? и соответствующий список вершин?

Общая глубина первого поиска

  1. Посетить узел (ячейку) (изменить флаг посещения на true)
  2. Push to Stack
  3. получить непосещенную вершину (peek stack), если ее нет (pop pop) - обновить представление модели лабиринта

Повторяйте 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
    }

На следующих рисунках изображена структура лабиринта, она была сгенерирована псевдослучайно; окончательная реализация лабиринта будет уточнена.

Maze

Спасибо, я буду очень полон, если бы вы могли направить меня в правильном направлении ...

1 Ответ

7 голосов
/ 03 марта 2012

Для 2D Maze вы можете просто использовать Поиск по ширине вместо поиска по глубине. Он будет найден в O (n 2 ), если у вас n * n лабиринт.

Но есть еще один вариант, который является своего рода маркировкой и 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;
}

Теперь ваш график представляет собой список объектов Node:

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

И для моделирования вашего Лабиринта вы должны выбрать ячейки в качестве узла и нарисовать ребро между соседними ячейками.Я оставлю вам, как добавить узел к вашему графику.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...