back to index

Iterative Maze Solver Example

Iterative Maze Solver Example, a project by Eric Spencer.


Iterative/hasNext maze solver. A transcript of an exchange with ChatGPT about iterative maze solving in Java, in the context of a CS2 data structures course.

User

A CS2 course covers the main data structures in Java, following the ACM 2020 curricular guidelines. In that context, give coding examples of an iterative maze solver, and explain each step. The maze has a border and walls marked with '*', unvisited squares marked with a blank space ' ', and visited squares marked with 'x'.

ChatGPT

An iterative maze solver in Java, under those conventions:


import java.util.ArrayDeque;
import java.util.Queue;

public class MazeSolver {
    private static final char WALL = '*';
    private static final char UNVISITED = ' ';
    private static final char VISITED = 'x';

    public static void solveMaze(char[][] maze, int startX, int startY) {
        int rows = maze.length;
        int columns = maze[0].length;

        Queue<int[]> queue = new ArrayDeque<>();
        queue.add(new int[]{startX, startY});

        while (!queue.isEmpty()) {
            int[] currentPos = queue.poll();
            int x = currentPos[0];
            int y = currentPos[1];

            // Check if the current position is the maze exit
            if (isExit(x, y, rows, columns)) {
                System.out.println("Maze solved!");
                return;
            }

            // Mark the current position as visited
            maze[x][y] = VISITED;

            // Check and enqueue neighboring positions if they are valid and unvisited
            enqueueIfValid(queue, maze, x - 1, y);
            enqueueIfValid(queue, maze, x + 1, y);
            enqueueIfValid(queue, maze, x, y - 1);
            enqueueIfValid(queue, maze, x, y + 1);
        }

        System.out.println("No solution found.");
    }

    private static void enqueueIfValid(Queue<int[]> queue, char[][] maze, int x, int y) {
        int rows = maze.length;
        int columns = maze[0].length;

        if (x >= 0 && x < rows && y >= 0 && y < columns && maze[x][y] == UNVISITED) {
            queue.add(new int[]{x, y});
        }
    }

    private static boolean isExit(int x, int y, int rows, int columns) {
        return x == 0 || x == rows - 1 || y == 0 || y == columns - 1;
    }

    public static void main(String[] args) {
        char[][] maze = {
            {'*', '*', '*', '*', '*', '*', '*'},
            {'*', ' ', ' ', ' ', ' ', ' ', '*'},
            {'*', ' ', '*', '*', '*', ' ', '*'},
            {'*', ' ', '*', ' ', ' ', ' ', '*'},
            {'*', ' ', '*', '*', '*', '*', '*'},
            {'*', ' ', ' ', ' ', ' ', ' ', '*'},
            {'*', '*', '*', '*', '*', '*', '*'}
        };

        solveMaze(maze, 1, 1);
    }
}

The code works as follows.

  1. The constants WALL, UNVISITED, and VISITED hold the characters used in the maze.
  2. The solveMaze method takes the maze as a 2D character array (char[][]) and the starting coordinates startX and startY. It initializes a queue of positions to visit.
  3. A while loop continues until the queue is empty. Inside the loop, the first position is removed with queue.poll() and its coordinates are assigned to x and y.
  4. The isExit method checks whether the current position is the maze exit. If it is, the method prints "Maze solved!" and returns.
  5. Otherwise the current position is marked as visited by setting maze[x][y] to VISITED.
  6. Neighboring positions (up, down, left, right) are enqueued if they are valid and unvisited. The enqueueIfValid method performs that check.
  7. If the queue empties without the exit being found, the method prints "No solution found."
  8. The main method creates a sample maze as a 2D character array: a 7x7 grid surrounded by walls (*), with some open spaces ( ) and an entrance at (1, 1).
  9. solveMaze is then called with the maze and the starting coordinates.

Started from (1, 1), the solver explores neighboring positions until it reaches the exit or exhausts the queue. Visited positions are marked with 'x'.

User

Is this method a breadth-first search?

ChatGPT

Yes. The solver above follows a breadth-first search (BFS).

BFS explores all nodes at the current level before moving to the next. In maze solving that means every neighbor of the current position is visited before the search moves deeper, so all positions at the same distance from the start are visited before any position at the next distance.

The Queue holds the traversal state. The search starts at the starting position, enqueues neighboring positions, and processes them in the order they were enqueued.

User

Is the example maze solvable?

ChatGPT

The example maze is not solvable. An isolated wall in the middle blocks every path to the exit.

The maze for reference:


*******
*     *
* *** *
* *   *
* ***** 
*     *
*******

The wall at row 4, column 3 disconnects the rest of the maze from the exit. No path exists from the starting position.

Two options follow: a different example maze that is solvable, or a modification of this one.

User

Make it solvable. Also allow the maze to have a starting point on the perimeter. The isExit function as written appears to prevent that.

ChatGPT

Both the maze and the isExit function change: the maze to make it solvable, isExit to accept a starting point on the perimeter.

Updated maze:


*********
*    *  *
* ** *  *
*    *  *
*  ***** 
*       *
*********

The starting position may now sit on the perimeter, and a path to the exit exists.

Updated code with the modified isExit function:


import java.util.ArrayDeque;
import java.util.Queue;

public class MazeSolver {
    private static final char WALL = '*';
    private static final char UNVISITED = ' ';
    private static final char VISITED = 'x';

    public static void solveMaze(char[][] maze, int startX, int startY) {
        int rows = maze.length;
        int columns = maze[0].length;

        Queue<int[]> queue = new ArrayDeque<>();
        queue.add(new int[]{startX, startY});

        while (!queue.isEmpty()) {
            int[] currentPos = queue.poll();
            int x = currentPos[0];
            int y = currentPos[1];

            // Check if the current position is the maze exit
            if (isExit(x, y, rows, columns)) {
                System.out.println("Maze solved!");
                return;
            }

            // Mark the current position as visited
            maze[x][y] = VISITED;

            // Check and enqueue neighboring positions if they are valid and unvisited
            enqueueIfValid(queue, maze, x - 1, y);
            enqueueIfValid(queue, maze, x + 1, y);
            enqueueIfValid(queue, maze, x, y - 1);
            enqueueIfValid(queue, maze, x, y + 1);
        }

        System.out.println("No solution found.");
    }

    private static void enqueueIfValid(Queue<int[]> queue, char[][] maze, int x, int y) {
        int rows = maze.length;
        int columns = maze[0].length;

        if (x >= 0 && x < rows && y >= 0 && y < columns && maze[x][y] == UNVISITED) {
            queue.add(new int[]{x, y});
        }
    }

    private static boolean isExit(int x, int y, int rows, int columns) {
        return x == 0 || x == rows - 1 || y == 0 || y == columns - 1;
    }

    public static void main(String[] args) {
        char[][] maze = {
            {'*', '*', '*', '*', '*', '*', '*', '*', '*'},
            {'*', ' ', ' ', ' ', '*', ' ', ' ', ' ', '*'},
            {'*', ' ', '*', '*', ' ', ' ', '*', ' ', '*'},
            {'*', ' ', ' ', ' ', '*', ' ', ' ', ' ', '*'},
            {'*', ' ', ' ', '*', '*', '*', '*', ' ', '*'},
            {'*', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '*'},
            {'*', '*', '*', '*', '*', '*', '*', '*', '*'}
        };

        solveMaze(maze, 1, 1);
    }
}

User

That maze still does not look solvable. Also, if movement is restricted to the cardinal directions, a solution on the perimeter reachable only by a diagonal move will not work.

ChatGPT

Correct. Allowing the starting position on the perimeter does not by itself make the maze solvable. The maze changes again, and the starting position with it.

Updated solvable maze:


*********
*       *
* *** * *
* *   * *
* ***** 
*       *
*********

A passage runs from the starting position to the exit.

Updated code with the modified maze:


import java.util.ArrayDeque;
import java.util.Queue;

public class MazeSolver {
    private static final char WALL = '*';
    private static final char UNVISITED = ' ';
    private static final char VISITED = 'x';

    public static void solveMaze(char[][] maze, int startX, int startY) {
        int rows = maze.length;
        int columns = maze[0].length;

        Queue<int[]> queue = new ArrayDeque<>();
        queue.add(new int[]{startX, startY});

        while (!queue.isEmpty()) {
            int[] currentPos = queue.poll();
            int x = currentPos[0];
            int y = currentPos[1];

            // Check if the current position is the maze exit
            if (isExit(x, y, rows, columns)) {
                System.out.println("Maze solved!");
                return;
            }

            // Mark the current position as visited
            maze[x][y] = VISITED;

            // Check and enqueue neighboring positions if they are valid and unvisited
            enqueueIfValid(queue, maze, x - 1, y);
            enqueueIfValid(queue, maze, x + 1, y);
            enqueueIfValid(queue, maze, x, y - 1);
            enqueueIfValid(queue, maze, x, y + 1);
        }

        System.out.println("No solution found.");
    }

    private static void enqueueIfValid(Queue<int[]> queue, char[][] maze, int x, int y) {
        int rows = maze.length;
        int columns = maze[0].length;

        if (x >= 0 && x < rows && y >= 0 && y < columns && maze[x][y] == UNVISITED) {
            queue.add(new int[]{x, y});
        }
    }

    private static boolean isExit(int x, int y, int rows, int columns) {
        return x == 0 || x == rows - 1 || y == 0 || y == columns - 1;
    }

    public static void main(String[] args) {
        char[][] maze = {
            {'*', '*', '*', '*', '*', '*', '*', '*', '*'},
            {'*', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '*'},
            {'*', ' ', '*', '*', ' ', '*', ' ', ' ', '*'},
            {'*', ' ', '*', ' ', ' ', '*', ' ', ' ', '*'},
            {'*', ' ', '*', '*', '*', '*', ' ', ' ', '*'},
            {'*', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '*'},
            {'*', '*', '*', '*', '*', '*', '*', '*', '*'}
        };

        solveMaze(maze, 1, 1);
    }
}

The starting position is (1, 1), the top left corner of the maze.

User

Try another maze to solve.

ChatGPT

A new solvable maze:


*********
*       *
* *** * *
* *   * *
* * * * *
*   *   *
*********

A path runs from the starting position to the exit.

The code with the new maze:


import java.util.ArrayDeque;
import java.util.Queue;

public class MazeSolver {
    private static final char WALL = '*';
    private static final char UNVISITED = ' ';
    private static final char VISITED = 'x';

    public static void solveMaze(char[][] maze, int startX, int startY) {
        int rows = maze.length;
        int columns = maze[0].length;

        Queue<int[]> queue = new ArrayDeque<>();
        queue.add(new int[]{startX, startY});

        while (!queue.isEmpty()) {
            int[] currentPos = queue.poll();
            int x = currentPos[0];
            int y = currentPos[1];

            // Check if the current position is the maze exit
            if (isExit(x, y, rows, columns)) {
                System.out.println("Maze solved!");
                return;
            }

            // Mark the current position as visited
            maze[x][y] = VISITED;

            // Check and enqueue neighboring positions if they are valid and unvisited
            enqueueIfValid(queue, maze, x - 1, y);
            enqueueIfValid(queue, maze, x + 1, y);
            enqueueIfValid(queue, maze, x, y - 1);
            enqueueIfValid(queue, maze, x, y + 1);
        }

        System.out.println("No solution found.");
    }

    private static void enqueueIfValid(Queue<int[]> queue, char[][] maze, int x, int y) {
        int rows = maze.length;
        int columns = maze[0].length;

        if (x >= 0 && x < rows && y >= 0 && y < columns && maze[x][y] == UNVISITED) {
            queue.add(new int[]{x, y});
        }
    }

    private static boolean isExit(int x, int y, int rows, int columns) {
        return x == 0 || x == rows - 1 || y == 0 || y == columns - 1;
    }

    public static void main(String[] args) {
        char[][] maze = {
            {'*', '*', '*', '*', '*', '*', '*', '*', '*'},
            {'*', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '*'},
            {'*', ' ', '*', '*', ' ', '*', ' ', ' ', '*'},
            {'*', ' ', '*', ' ', ' ', '*', ' ', ' ', '*'},
            {'*', ' ', '*', ' ', '*', '*', ' ', ' ', '*'},
            {'*', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '*'},
            {'*', '*', '*', '*', '*', '*', '*', '*', '*'}
        };

        solveMaze(maze, 1, 1);
    }
}

The starting position is (1, 1), the top left corner of the maze.

User

Try making a maze of size 4x4.

ChatGPT

A solvable 4x4 maze:


****
*   *
* * *
*   *
****

A path runs from the starting position to the exit.

The code with the new maze:


import java.util.ArrayDeque;
import java.util.Queue;

public class MazeSolver {
    private static final char WALL = '*';
    private static final char UNVISITED = ' ';
    private static final char VISITED = 'x';

    public static void solveMaze(char[][] maze, int startX, int startY) {
        int rows = maze.length;
        int columns = maze[0].length;

        Queue<int[]> queue = new ArrayDeque<>();
        queue.add(new int[]{startX, startY});

        while (!queue.isEmpty()) {
            int[] currentPos = queue.poll();
            int x = currentPos[0];
            int y = currentPos[1];

            // Check if the current position is the maze exit
            if (isExit(x, y, rows, columns)) {
                System.out.println("Maze solved!");
                return;
            }

            // Mark the current position as visited
            maze[x][y] = VISITED;

            // Check and enqueue neighboring positions if they are valid and unvisited
            enqueueIfValid(queue, maze, x - 1, y);
            enqueueIfValid(queue, maze, x + 1, y);
            enqueueIfValid(queue, maze, x, y - 1);
            enqueueIfValid(queue, maze, x, y + 1);
        }

        System.out.println("No solution found.");
    }

    private static void enqueueIfValid(Queue<int[]> queue, char[][] maze, int x, int y) {
        int rows = maze.length;
        int columns = maze[0].length;

        if (x >= 0 && x < rows && y >= 0 && y < columns && maze[x][y] == UNVISITED) {
            queue.add(new int[]{x, y});
        }
    }

    private static boolean isExit(int x, int y, int rows, int columns) {
        return x == 0 || x == rows - 1 || y == 0 || y == columns - 1;
    }

    public static void main(String[] args) {
        char[][] maze = {
            {'*', '*', '*', '*'},
            {'*', ' ', ' ', '*'},
            {'*', ' ', '*', '*'},
            {'*', ' ', ' ', '*'},
            {'*', '*', '*', '*'}
        };

        solveMaze(maze, 1, 1);
    }
}

The starting position is (1, 1), the top left corner of the maze.

User

What are the advantages of using an iterative approach for maze solving compared to a recursive approach?

ChatGPT

Five advantages.

  1. Iterative algorithms typically use less memory. Recursion relies on the function call stack to hold intermediate state, which can be substantial for large mazes or deeply nested recursion. An iterative solver holds that state in a queue or a stack instead.
  2. Recursion depth is bounded by the system stack size. A very large or complex maze can exceed that limit and produce a stack overflow error. Iterative algorithms do not use the call stack for search state.
  3. Control flow is more explicit. An iterative maze solver runs as a sequential loop, so its progress is easier to follow and debug than a chain of recursive calls.
  4. Iterative algorithms are easier to modify or extend. Because the state lives in an ordinary queue or stack, extra conditions, checks, and changes of behavior can be introduced without changing the call structure.
  5. Some languages support tail recursion optimization, which removes the extra stack space required by recursive calls. Not all languages or compilers provide it. Where it is absent, the iterative form is the more reliable choice.

User

How can a maze be represented using data structures suitable for iterative maze solving?

ChatGPT

A maze can be represented as a two-dimensional array or as a grid-based data structure.

A two-dimensional array:


char[][] maze = {
    {'*', '*', '*', '*', '*', '*'},
    {'*', ' ', ' ', ' ', ' ', '*'},
    {'*', '*', '*', '*', ' ', '*'},
    {'*', ' ', ' ', ' ', ' ', '*'},
    {'*', '*', '*', '*', '*', '*'}
};

Each cell of the maze is one character. '*' is a wall or obstacle, ' ' (space) is an unvisited or empty cell, and any other character can mark a different type of cell, such as the starting position or the exit.

The other option is a grid-based data structure, such as a two-dimensional ArrayList or a custom MazeCell class:


List<List<Character>> maze = new ArrayList<>();
maze.add(Arrays.asList('*', '*', '*', '*', '*', '*'));
maze.add(Arrays.asList('*', ' ', ' ', ' ', ' ', '*'));
maze.add(Arrays.asList('*', '*', '*', '*', ' ', '*'));
maze.add(Arrays.asList('*', ' ', ' ', ' ', ' ', '*'));
maze.add(Arrays.asList('*', '*', '*', '*', '*', '*'));

The grid-based form resizes dynamically. It costs more memory and slower access than a plain two-dimensional array.

User

Which iterative algorithms are commonly used for maze solving, and how do they work?

ChatGPT

Two are common: breadth-first search and depth-first search.

Breadth-first search (BFS)

Depth-first search (DFS)

The choice between the two depends on whether the shortest path is required or any valid path will do.

User

Are there more?

ChatGPT

Two more.

Iterative deepening depth-first search (IDDFS)

A* search

User

What is Manhattan distance?

ChatGPT

Manhattan distance is a distance measure for grid-based environments, such as mazes, where movement is restricted to horizontal and vertical directions and no diagonal movement is allowed. It is named after the city block layout of Manhattan, where the shortest distance between two points is measured along the grid lines.

In maze solving and pathfinding, Manhattan distance is the minimum number of horizontal and vertical moves required to reach a target position from a given position. It is the sum of the absolute differences between the x-coordinates and between the y-coordinates of the two positions.

Formally, the Manhattan distance between two points (x1, y1) and (x2, y2) is:

Manhattan distance = |x2 - x1| + |y2 - y1|

For two points A(3, 5) and B(8, 2), the absolute differences give:

|8 - 3| + |2 - 5| = 5 + 3 = 8

The Manhattan distance between A(3, 5) and B(8, 2) is 8. A* search uses it as a heuristic to estimate the distance between a given cell and the destination.

User

Are there more algorithms not yet mentioned?

ChatGPT

Two more.

Best-first search (greedy search)

Recursive division method

User

Are there even more algorithms?

ChatGPT

Three more.

Wall follower (left-hand rule or right-hand rule)

Randomized Prim's algorithm

Kruskal's algorithm

User

List a few more.

ChatGPT

Three more.

Dead-end filling

Trémaux's algorithm

Hunt and kill

User

List more.

ChatGPT

Three more.

Eller's algorithm

Wilson's algorithm

Binary tree algorithm

User

How can complex maze structures, such as mazes with loops or multiple entry and exit points, be handled with an iterative approach?

ChatGPT

Complex maze structures call for adapted algorithms or new strategies. Four approaches.

Modified depth-first search

Backtracking algorithms

Graph traversal algorithms

Iterative maze generation

User

Is there a way to show every single step the algorithm takes as it works through the maze?

ChatGPT

Four approaches.

Graphical user interface

Console output

Animation

Step-by-step logging

User

Provide Java code that outputs each step to the console as described above.

ChatGPT

Java code that prints each step of a maze-solving algorithm to the console:


public class MazeSolver {
    private char[][] maze;  // The maze represented as a 2D character array
    private int startRow;   // Starting row index
    private int startCol;   // Starting column index
    private int endRow;     // Ending row index
    private int endCol;     // Ending column index

    public MazeSolver(char[][] maze, int startRow, int startCol, int endRow, int endCol) {
        this.maze = maze;
        this.startRow = startRow;
        this.startCol = startCol;
        this.endRow = endRow;
        this.endCol = endCol;
    }

    public void solveMaze() {
        boolean[][] visited = new boolean[maze.length][maze[0].length];
        // Initialize visited array to keep track of visited cells

        solve(startRow, startCol, visited);
    }

    private boolean solve(int row, int col, boolean[][] visited) {
        // Check if the current position is out of bounds or a wall
        if (row < 0 || row >= maze.length || col < 0 || col >= maze[0].length || maze[row][col] == '*') {
            return false;
        }

        // Check if the current position is the destination
        if (row == endRow && col == endCol) {
            return true;
        }

        // Check if the current position has already been visited
        if (visited[row][col]) {
            return false;
        }

        // Mark the current position as visited
        visited[row][col] = true;

        // Output the current state of the maze
        printMaze();

        // Recursively explore neighboring cells
        if (solve(row - 1, col, visited)) {
            return true;
        }
        if (solve(row + 1, col, visited)) {
            return true;
        }
        if (solve(row, col - 1, visited)) {
            return true;
        }
        if (solve(row, col + 1, visited)) {
            return true;
        }

        // If none of the neighboring cells leads to the destination, backtrack
        visited[row][col] = false;

        // Output the backtracked state of the maze
        printMaze();

        return false;
    }

    private void printMaze() {
        for (char[] row : maze) {
            for (char cell : row) {
                System.out.print(cell + " ");
            }
            System.out.println();
        }
        System.out.println();
    }

    public static void main(String[] args) {
        char[][] maze = {
                {'*', '*', '*', '*', '*', '*', '*', '*', '*'},
                {'*', ' ', ' ', ' ', '*', ' ', ' ', ' ', '*'},
                {'*', ' ', '*', ' ', '*', ' ', '*', ' ', '*'},
                {'*', ' ', '*', ' ', ' ', ' ', '*', ' ', '*'},
                {'*', ' ', '*', '*', '*', '*', '*', ' ', '*'},
                {'*', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '*'},
                {'*', '*', '*', '*', '*', '*', '*', '*', '*'}
        };

        int startRow = 1;
        int startCol = 1;
        int endRow = 5;
        int endCol = 7;

        MazeSolver solver = new MazeSolver(maze, startRow, startCol, endRow, endCol);
        solver.solveMaze();
    }
}

This solver is recursive. It prints the current state of the maze at each step, including the backtracked state where that applies. The maze is a 2D character array in which '*' denotes a wall and ' ' an unvisited cell. Other characters can carry additional symbols.

At each step of the solve the maze is written to the console, so the progress of the algorithm and its route toward the destination are visible.

The maze shown is a simple example and can be replaced with any other configuration.

User

How would the next() function work to retrieve the next move or location in the maze traversal?

ChatGPT

A next() function that returns the next move or location can be added to the existing maze-solving code:


public class MazeSolver {
    // ...

    private List<int[]> path;  // List to store the path taken during traversal
    private int currentStep;   // Index of the current step in the path list

    public MazeSolver(char[][] maze, int startRow, int startCol, int endRow, int endCol) {
        // ...
        path = new ArrayList<>();
        currentStep = 0;
    }

    public int[] next() {
        if (currentStep >= path.size()) {
            // Traversal has been completed, return null or handle end of traversal as needed
            return null;
        }

        int[] nextMove = path.get(currentStep);
        currentStep++;
        return nextMove;
    }

    // ...

    private boolean solve(int row, int col, boolean[][] visited) {
        // ...

        // Recursively explore neighboring cells
        if (solve(row - 1, col, visited)) {
            path.add(new int[]{row - 1, col});  // Add the current move to the path list
            return true;
        }
        if (solve(row + 1, col, visited)) {
            path.add(new int[]{row + 1, col});  // Add the current move to the path list
            return true;
        }
        if (solve(row, col - 1, visited)) {
            path.add(new int[]{row, col - 1});  // Add the current move to the path list
            return true;
        }
        if (solve(row, col + 1, visited)) {
            path.add(new int[]{row, col + 1});  // Add the current move to the path list
            return true;
        }

        // ...
    }

    // ...
}

A path list stores the path taken during the traversal. Each element of path is a move or location in the maze, held as an array of two integers [row, col].

The next() function returns the element at the currentStep index in the path list, then increments currentStep to point at the following move.

next() is called repeatedly until it returns null, or until whatever end-of-traversal condition applies.

The solve() method must also be changed to append the current move or location to the path list whenever the algorithm chooses a valid neighboring cell.

User

Make sure the function is iterative, not recursive.

ChatGPT

An iterative next() function can be built on breadth-first search or depth-first search with a stack or a queue.

A stack-based depth-first search:


import java.util.*;

public class MazeSolver {
    private char[][] maze;  // The maze represented as a 2D character array
    private int startRow;   // Starting row index
    private int startCol;   // Starting column index
    private int endRow;     // Ending row index
    private int endCol;     // Ending column index

    public MazeSolver(char[][] maze, int startRow, int startCol, int endRow, int endCol) {
        this.maze = maze;
        this.startRow = startRow;
        this.startCol = startCol;
        this.endRow = endRow;
        this.endCol = endCol;
    }

    public int[] next() {
        Stack<int[]> stack = new Stack<>();
        boolean[][] visited = new boolean[maze.length][maze[0].length];
        stack.push(new int[]{startRow, startCol});

        while (!stack.isEmpty()) {
            int[] current = stack.pop();
            int row = current[0];
            int col = current[1];
            visited[row][col] = true;

            // Check if the current position is the destination
            if (row == endRow && col == endCol) {
                return current;
            }

            // Explore neighboring cells
            if (row - 1 >= 0 && !visited[row - 1][col] && maze[row - 1][col] != '*') {
                stack.push(new int[]{row - 1, col});
            }
            if (row + 1 < maze.length && !visited[row + 1][col] && maze[row + 1][col] != '*') {
                stack.push(new int[]{row + 1, col});
            }
            if (col - 1 >= 0 && !visited[row][col - 1] && maze[row][col - 1] != '*') {
                stack.push(new int[]{row, col - 1});
            }
            if (col + 1 < maze[0].length && !visited[row][col + 1] && maze[row][col + 1] != '*') {
                stack.push(new int[]{row, col + 1});
            }
        }

        // No more moves, traversal is complete
        return null;
    }

    public static void main(String[] args) {
        char[][] maze = {
                {'*', '*', '*', '*', '*', '*', '*', '*', '*'},
                {'*', ' ', ' ', ' ', '*', ' ', ' ', ' ', '*'},
                {'*', ' ', '*', ' ', '*', ' ', '*', ' ', '*'},
                {'*', ' ', '*', ' ', ' ', ' ', '*', ' ', '*'},
                {'*', ' ', '*', '*', '*', '*', '*', ' ', '*'},
                {'*', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '*'},
                {'*', '*', '*', '*', '*', '*', '*', '*', '*'}
        };

        int startRow = 1;
        int startCol = 1;
        int endRow = 5;
        int endCol = 7;

        MazeSolver solver = new MazeSolver(maze, startRow, startCol, endRow, endCol);
        int[] nextMove;
        while ((nextMove = solver.next()) != null) {
            int row = nextMove[0];
            int col = nextMove[1];
            System.out.println("Next move: (" + row + ", " + col + ")");
        }
    }
}

The next() function uses a stack to perform an iterative depth-first search of the maze. It visits each cell and checks whether it is the destination. If the current cell is the destination, it returns the current position as the next move. Otherwise it explores neighboring cells and pushes them onto the stack if they are valid and unvisited.

In the main() method, next() is called in a loop until it returns null, and each retrieved move is printed to the console.

User

How can complex maze structures or multiple solutions be handled using the iterator-based approach?

ChatGPT

The iterator-based maze solver needs changes to support these cases.

Multiple solutions

Complex maze structures

User

Which data structures and algorithms support the iterator-based maze solver efficiently?

ChatGPT

Five options.

Graph data structure

Breadth-first search

Depth-first search

A* algorithm

Disjoint-set data structure (union-find)

Thread generated with ChatGPT [https://chat.openai.com] and downloaded with Botrush [https://botrush.io]