CS 201: Data Structures (Spring 2017)

HW04: Maze solver

Due: Monday, 04/17 at 22:00

1. Goals

To use the Stack ADT to solve a maze.

2. Setup

This is a pair programming assignment. Check Moodle for new partner pairings.

The code that you write for this assignment will build on top of two ADTs (List and Stack) and their implementations. Recall that the way Java has dealt with Stacks is rather odd: Stack is a class rather than an interface, and the documentation recommends that you use a Deque instead. Rather than using Java's built-in Stack methods, I've provided you with a Stack interface (Stack.java) and an implementation (CarlStack.class). The stack implementation is just a class file, because you don't need to see how it is implemented in order to use it. For this assignment, you must use the Stack interface and implementation that I have provided; you may not use the built-in Java Stack or Deque. View the Javadoc for CarlStack.

3. Specification

In this assignment, you will build on existing code that I have written in order to solve a maze. Download the starter code for this assignment. My code has most of the implementation of a load method and a method that will print the maze once you complete the load method. The first step in this homework is practicing your code reading skills to understand what I've written. I suggest that before meeting with you partner, you look through the code and the assignment, and then discuss the organization of the code at your first meeting.

The maze file format

Mazes are stored in text files and follow a particular format. We assume that our mazes are rectangular, and that they have walls along the entire outside of the maze, with no gaps in these outer walls. We will also specify a “start square” (S) and a “finish square” (F) to indicate the goal of the maze-solver: to get from S to F.

Maze files should have the following structure:

<Number of columns> <Number of rows>
<0-based column number of the start square> <0-based row number of the start square> 
<0-based column number of the finish square> <0-based row number of the finish square> 
<Row 0 description>
<Row 1 description>
...

Each row description includes a single character for each square in that row, and each character describes the left and bottom walls for its square. Specifically:

Putting this together in a small example, if the input file contains the following:

3 2     [The maze has 3 columns and 2 rows]
0 0     [The start square is at the upper left]
2 0     [The finish square is at the upper right]
L.|     [(0,0) has left and bottom walls; (1,0) has neither left nor bottom; (2,0) has just left]
L__     [(0,1) has left and bottom walls; (1,1) has just bottom; (2,1) has just bottom]
which yields this maze:
+---+---+---+
| S     | F |
+---+   +   +
|           |
+---+---+---+

Note that we specify only the left and bottom walls for each square, and not the top and right walls. This is sufficient to describe the whole maze (why?).

Loading and printing the maze

The first part of the assignment is to finish the load method in Maze.

Now, you're ready to try out whether your methods function correctly. You'll be loading and printing a maze. Modify main so that with the following command line:

java Maze maze.txt
the file maze.txt is loaded and printed. This should just involve constructing the maze and calling the load and print methods: it requires very little code. (Look in Maze.java for a print method: this method will work correctly once you have a working getMazeSquare method.)

Before you move on, draw a maze on paper, and then make a maze file that represents that maze. Try loading the maze and printing it using the following command:

java Maze <mazeFile>
where <mazeFile> is replaced with the name of your maze file.

Solving the maze

Now it's time to solve the maze using the following algorithm. I'm giving you the steps in prose; your job is to turn them into code. Please use this specific algorithm.
  1. Mark every square in the maze as unvisited.
  2. Create an empty stack of maze squares.
  3. Add the start square to the stack, and mark the start square as visited.
  4. If the stack is empty, you're done and the maze is unsolvable.
  5. If the top item is the finish square, you're done and the stack contains a solution to the maze.
  6. If all squares adjacent to the top item (i.e., the squares up, down, right, or left from the top item; no diagonal adjacency) are either blocked by a wall or are marked visited already, pop the top item from the stack and go to step 4.
  7. Otherwise, select a square that is adjacent to the top of the stack, unvisited, and accessible from the top of the stack (no wall between them). Mark this square as visited and push it on the stack. Go to step 4.

You should implement this method in Maze. Specifically:

Thus, you'll need to decide how to print a maze solution with the solution marked. Try to avoid duplicating code as much as possible: can you modify my print method so that it can print a maze with or without a solution? If you modify print, make sure that the comment reflects what it does now.

Testing your solver

One of the most important steps in writing code is testing to make sure it works (and debugging it when it doesn't!). We'll talk about testing throughout the term, and many assignments will include a testing component. This is to help you verify that your solution really does work, and is something that I try to do whenever I write code (and that I generally regret if I don't spend enough time on!). For this assignment, you should create several maze files that differ in critical ways (e.g., one requires going left to find the solution, another requires going right). Test your program on these maze files: does it solve all of them? You should create at least 2 maze files, but you may create more: the important thing about tests isn't how many you have but how well the tests cover the space of possibilities. Try to think about situations that you think could cause your code to fail, and create mazes that will tell you whether your code actually fails in that situation.

4. Code notes

5. Submission and grading

Submit to Moodle a zip archive containing: Follow the previously established guidelines, such as: In the future, even if I do not repeat these guidelines, please abide by them whenever they seem applicable.

Assignment requirements

This is a partial list of the things that we'll be looking for when evaluating your work; it does not include expectations about style, which are detailed in the style guide.

Grading

This assignment modified from one designed by Jeff Ondich.

Start early, have fun, and discuss questions on Moodle.