Version: 0.3.38

Graphs#

Module:

Graphs

Git Repository:

Lab 05—Graphs

Objectives:
  • Apply graphs concepts using Mazes

  • Implement Path finding algorithms

A maze is a “confusing and intricated network of passages” 1see Merriam Webster dictionary. We will play with simple two dimensional mazes as the one shown in Figure Fig. 3, but the idea generalizes to 3D, 4D grids, as well as to other shapes of grids, such as radial or triangular grids. Our aim is modest however: See how we can find a path that leads to the exit, and how we can generate “random” mazes of various sizes.

The Lab 05 Github repository contains a Java project to make things more concrete. The Java application can load a maze from a text file, solve a maze and generate SVG images (see the Appendix 5 for details on how to use it).

Mazes & Graphs#

As shown on Figure Fig. 3, 2D mazes are grids where the player can move in four directions: North, east, south and west. Some moves are not possible, because of walls.

Exercise

Create your own \(5 \times 5\) maze (with pen and paper). How did you proceed?

Exercise

Consider for instance the maze you just created: How would you represent it as a graph?

  1. How would you represents cells, walls and passages?

  2. Use a diagram, an adjacency list or a adjacency matrix to represent your maze.

Exercise

What algorithm(s) can we use to solve a maze?

  1. What is the solution of your maze? What is such a solution in terms of graphs?

  2. What graph algorithm can we use to solve mazes?

Maze Escape#

Your next task is to implement three algorithms that find how to reach the exit of the maze, namely a depth-first search, a breadth-first search and Dijkstra’s algorithm.

Exercise

Use the file DFS.java and write a depth-first search, which, given the entry of a maze, finds the sequence of moves that leads to the exit.

  1. Study and complete the file Search.java (from the solver package).

  2. Complete the file DFS.java

  3. The test suite DFSTest may be helpful.

Exercise

Use the file BFS.java and implement the breadth-first search (BFS), to find the sequence of moves that leads to the exit.

  1. Study and possibly modify the file Search.java (from the solver package).

  2. Complete the file BFS.java

  3. The test suite BFSTest may be helpful.

Exercise

Use the file Dijkstra.java and implement the Dijkstra’s algorithm, to to find the sequence of moves that leads to the exit.

Analysis#

Let us see how these search algorithms will perform on three mazes shown by Table 3. Maze A is no walls, Maze B is just a long corridor, and Maze C is more like a real-life maze, with turns and dead-ends.

Table 3 Sample Mazes#
  1. An empty Maze

  1. A long corridor

  1. A “regular” maze

../../_images/maze_1.svg ../../_images/maze_2.svg ../../_images/maze_3.svg

Let us assume that these algorithms all explore possible moves in the following order: North, East, South, West. For instance, at a cell with a wall north and west, the algorithm would first explore east, and then south.

Exercise

Consider first Maze A. Of the three search algorithms you implemented in Section 2, which algorithm will find the exit first?

  1. In which order will the DFS visit the cells?

  2. In which order will the BFS visit the cells?

  3. In which order will Dijkstra’s algorithm visit the cells?

Exercise

Consider now Maze B, the long corridor. Of the three search algorithms you implemented in Section 2, which algorithm will find the exit first?

  1. In which order will the DFS visit the cells?

  2. In which order will the BFS visit the cells?

  3. In which order will Dijkstra’s algorithm visit the cells?

Exercise

Finally, consider Maze C. Of the three search algorithms you implemented in Section 2, which algorithm will find the exit first?

  1. In which order will the DFS visit the cells?

  2. In which order will the BFS visit the cells?

  3. In which order will Dijkstra’s algorithm visit the cells?

Generating “Random” Mazes#

Consider now how we could generate a “random” maze? Placing walls at random would not yield a interesting mazes: Parts may not be reachable or not constrained enough. A perfect maze is thus a maze that obeys to the two following properties 2Buck, J. (2015). Mazes for Programmers: Code Your Own Twisty Little Passages. Pragmatic Bookshelf..

  • Every cell in the grid is reachable ;

  • There is exactly one path between every pair of cells (a path excludes reusing cells).

Exercise 17

Sketch an algorithm that checks whether a given maze is perfect. How would you proceed?

  1. Look at the class PerfectionChecker and complete the isPerfect method.

  2. The PerfectionTest contains some test cases.

There are many algorithms to generate such perfect mazes. One of them, the Aldous-Broder algorithm [2] uses the idea of “random walk”. It proceeds as follows:

  1. Create a grid full of walls.

  2. Pick a cell \(c\) at random.

  3. Move to a neighbor \(n\) cell of your choice. If it has not yet been visited, dig a passage back to Cell \(c\), and mark Cell \(n\) as visited.

  4. If any cell has not yet been visited, return to Step 3.

This algorithm is non-deterministic: Every run on the same input is likely to be different because we pick cells at random (so the name “random-walk”).

Exercise

How many cells will this algorithms visit in the best case? How many in the worst case? Explain why.

Exercise

What would be your solution to generate a random perfect maze? How would you approach this problem.

Exercise

Implement your solution and generate a few mazes. Can you see some sort or recurrent patterns? If so, what could lead to that?

  1. Complete the class MyGenerator.

  2. Generate a few mazes from various size, say \(5 \times 5\) and \(10 \times 20\) for instance.

  3. Can you see a pattern?

Using the CLI#

The code in the companion repository will help you work with mazes stored in text file. Consider the following example (also shown on Fig. 7), which describes a \(5 \times 5\) maze: We store mazes as a grid of characters, where ’S’ stands for the starting point and ’E’ for the exit. Below is a sample \(5 \times 5\) maze shown as a text file:

$ cat sample_maze.txt
+-+-+-+-+-+
|S|       |
+ + +-+ + +
|   | | | |
+ + + + +-+
| | | | | |
+ +-+ + + +
| |       |
+ +-+-+-+ +
| |      E|
+-+-+-+-+-+

The Github repository contains a command-line interface application (CLI), which you can use to manipulate maze. Here are the three main features:

  • Solve the maze tored in a text file, using the solve command. For instance

    $ ./maze.sh solve sample_maze.txt
    5 x 5 grid loaded from sample_maze.txt
    Solution: [south, east, north, east, east, south, south, south,
    east, south]
    

    You can select a specific algorithm option the --algorithm=DFS for instance.

  • Export a maze (in a given text file) into an SVG picture using the command export. For instance, to get the SVG file shown as Fig. 7, you can run the command

    $ ./maze.sh export --solution sample_maze.txt sample_maze.svg
    5 x 5 grid loaded from sample_maze.txt
    Solution: [(1, 0), (0, 1), (-1, 0), (0, 1), (0, 1), (1, 0),
    (1, 0), (1, 0), (0, 1), (1, 0)]
    
  • Generate a new random maze using the generate command. For instance, to generate a maze over a \(15 \times 3\) grid, you use the following:

    $ ./maze.sh generate -c=15 -r=3 test.txt
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    |S  |   |       |             |
    + + + + + +-+ + + +-+ +-+ + + +
    | | | |   |   |   |   | | | | |
    o+ +-+ +-+-+-+-+-+-+ +-+ + +-+ +
    |       |           |     |  E|
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+