arrow left
Back to Developer Education

    Solving a Maze with Breadth First Search

    Solving a Maze with Breadth First Search

    How can we find the fastest way from point A to point B? Solving problems like this is very common in computing. An enemy AI in a video game needs to be able to find the fastest way to the player. Google Maps needs to find the fastest way to your destination. Here, we just want to solve a maze. <!--more-->

    There are several pathfinding algorithms. The one we'll focus on today is Breadth-first Search or BFS. This algorithm is guaranteed to give the fastest path on an unweighted graph.

    What is a Graph?

    Picture of a graph. The black circles are vertices and the red lines are edges.

    This is a graph. Unlike in a tree, a graph is allowed to have circular references. Each point of the graph is called a vertex. The lines that connect the vertices are called edges.

    Some graphs may be weighted, meaning that some edges are longer than others. Some edges may be directed, as in, the connection can only go in one direction.

    A graph with weights and directed edges

    We’ll be focusing on unweighted graphs because BFS isn’t very useful otherwise. BFS can work on directed graphs, but figuring how to do that will be left as an exercise to the reader.

    Creating a HashMap

    We need to be able to store a graph on the computer’s memory. Each vertex can simply be represented as a list of its neighbors.

    // in case you can't tell, these examples are using Java
    class Vertex {
        private LinkedList<Vertex> adjacents;
    
        public Vertex() {
            this.adjacents = new LinkedList<>();
        }
    
        public void addAdjacent(Vertex adjacentVertex) {
            adjacents.add(adjacentVertex);
        }
    
        public LinkedList<Vertex> getAdjacents() {
            return this.adjacents;
        }
    
        // you probably want to override the hash() function
    }
    

    A graph can be a HashMap containing a name for each vertex, and the vertex. If you don't know what a HashMap is, you may want to look at this article.

    class Graph {
        private HashMap<String, Vertex> vertices;
    
        public Graph() {
            this.vertices = new HashMap<>();
        }
    
        public Vertex addVertex(String name) {
            Vertex vertex = new Vertex();
            vertices.put(name, vertex);
            return vertex;
        }
    
        public void addEdge(String vertex1, String vertex2) {
            Vertex v1 = vertices.get(vertex1);
            Vertex v2 = vertices.get(vertex2);
    
            v1.addAdjacent(v2);
            v2.addAdjacent(v1);
        }
    }
    

    Traversing the Graph

    We need a Queue of vertices to traverse. Whenever we reach a certain vertex, we add all its adjacent vertices to the queue, unless that vertex was already reached. We'll need a HashSet to store which vertices we've already reached. We'll make a breadthFirstTraversal method which contains the following.

    public void breadthFirstTraversal(String start, String end) {
        Vertex startVert = vertices.get(start);
        Vertex endVert = vertices.get(end);
    
        LinkedList<Vertex> queue = new LinkedList<>(); // LinkedList implements Queue
        HashSet<Vertex> visited = new HashSet<>();
    
        visited.add(startVert); // this is the first vertex
    
        Vertex current = startVert; // the current vertex to check
        while (current != endVert) { // repeats until the end is reached
    
            LinkedList<Vertex> adjacents = current.getAdjacents(); // get adjacents
    
            for (Vertex v: adjacents) { // add all the adjacents
                if (!visited.contains(v)) { // but only if it hasn't already been traversed
                    visited.add(v);
                    queue.add(v);
                }
            }
    
            current = queue.remove(); // goes to the next vertex
        }
    }
    

    Creating a Path

    Of course, all this algorithm does is traverse the graph. We need a path. Luckily, this is surprisingly simple. For each vertex, we'll need to store the previous vertex. We can just change the HashSet to be a HashMap to do this. We'll need a list of vertices for the path. We'll start by adding the last vertex's previous, then its previous, and so on until we reach the beginning.

    public LinkedList<Vertex> breadthFirstSearch(String start, String end) {
        Vertex startVert = vertices.get(start);
        Vertex endVert = vertices.get(end);
    
        LinkedList<Vertex> queue = new LinkedList<>(); // LinkedList implements Queue
        HashMap<Vertex, Vertex> visited = new HashMap<>();
    
        visited.put(startVert, null); // this is the first vertex
    
        Vertex current = startVert; // the current vertex to check
        while (current != endVert) { // repeats until the end is reached
    
            LinkedList<Vertex> adjacents = current.getAdjacents(); // get adjacents
    
            for (Vertex v: adjacents) { // add all the adjacents
                if (!visited.containsKey(v)) { // but only if it hasn't already been traversed
                    visited.put(v, current);
                    queue.add(v);
                }
            }
    
            current = queue.remove(); // goes to the next vertex
        }
    
        // create the path
        LinkedList<Vertex> path = new LinkedList<>();
        path.addFirst(current);
        while (current != startVert) {
            current = visited.get(current);
            path.addFirst(current); // addFirst is used to get the correct order
        }
    
        return path;
    }
    

    The next several images demonstrate how exactly this code works:

    Solving the Maze

    In case you were wondering, all you would need to do to solve a maze with this is to turn it into a graph

    A maze. The maze contains a lot of black circles with letters inside of them, connected by red lines

    Published on: Aug 7, 2020
    Updated on: Jul 12, 2024
    CTA

    Start your journey with Cloudzilla

    With Cloudzilla, apps freely roam across a global cloud with unbeatable simplicity and cost efficiency