Colorado State University Computer Science Department

CS-200, Fall 1998 
Assignment #8



 

It's A-Maze-ing!

For this assignment, you and your team must write a C++ Maze class and a main program that reads in a maze from standard input, finds a way to get from the starting position to the goal position, and reports the results. You will solve each maze in two ways, one way using a stack and another way using a queue, and discuss the results.

A Maze

For this assignment, a maze is specified by a map of characters, like

  +---------+
4 |     |  G|
  |---- |   |
3 |         |
  | |       |
2 | |       |
  | | ------|
1 | |       |
  | |       |
0 |S|       |
  +---------+
   0 1 2 3 4

The diagram shows a map of 11x11 characters, but it is to be stored as a one-dimensional character array of 121 elements. Imagine a robot moving through the maze from the starting position, S, to the goal position, G. The robot makes up, right, down, and left movements of two positions at a time. The numbers show the row and column numbers that are the allowed robot positions. So, S is at position (0,0), representing the row and column as (row, column). If the robot moves up from S, it arrives at (1,0). Note that this is not (x,y) as on a plot, where x is the left to right position. Instead, we are using notation like (y,x). The goal, G, is at (4,4). The shortest path from S to G in this maze is 8 steps long, following positions (0,0), (1,0), (2,0), (3,0), (3,1), (3,2), (3,3), (3,4), (4,4). Obviously, the robot cannot go through any walls.

As your robot explores, it will leave a breadcrumb at every position that it has visited. A visited position will be marked by an asterisk, '*', in the map. For example, here is the result of one exploration after finding the goal. Notice that not all states were visited. It stopped as soon as it found the goal.

+---------+
|  * *|* G|
|---- |	  |
|* * * *  |
| |    	  |
|*|* *    |
| | ------|
|*|*      |
| |       |
|S|       |
+---------+

The Search Algorithm

The search algorithm will choose the next state for the roboto to explore. The state is represented by the row and column that the robot is in. You must also keep track of the path length from the start state to each state visited. Do this by representing a state with a three-element integer array, with the row in the first element, the column in the second element, and the number of steps in the path so far as the third. So, the start state will be an integer array with elements 0, 0, 0. If a step up is taken, the robot is in state 1, 0, 1. When it reaches the goal in the example above, it is in state 4, 4, 8. There are many ways to search such a maze. You are to implement the following algorithm:

For each maze,
{   Erase all breadcrumbs.
    Set the current state to the starting state.
    Push the current state and zero steps on a stack.
    While the goal has not been found,
    {    Pop the state and steps from the stack. Set the current state to this state.
         Mark the current state as visited.
         Try each action, a, in order from the set (up, right, down, left)
         {    If there is not a wall in the a direction from the current state, then
              {    Get the new state, given the current state and the action a.
                   If the new state is the goal state, then
                       Set a flag variable that will cause the outer while loop to terminate.
                   else if the new state has not been visited, then
                       Push the current state and current steps + 1 onto the stack.
                   else
                       Just delete the the current state.
              } else (there is a wall in the a direction)
                   do nothing.
         } (end of action loop)
         Delete the storage used for the current state.
    } (end of while not goal loop)
    Return the number of steps associated with the goal state.
}

You must run this algorithm once as is, and a second time using a queue in place of the stack.

The Maze Class

The maze class handles the storage for the map, tests for walls and the goal state, and the dropping and testing of breadcrumbs.

Private variables will include the start state, the number of rows and columns and a dynamic 1-D character array for the map. This is the trickiest part. We will use the map to record all information, including the boundary walls, the start and goal states, the interior walls, and the states that have been visited so far. The array will contain all of the characters shown in the above maps, except the numbers along the side and bottom. Walls are marked with '|' and '-', the start state is marked by 'S', the goal state is marked by 'G', and the breadcrumbs with '*'.

When the robot moves, it either moves two characters to the right or left, or up or down the equivalent of two rows in the 1-D character array. It will be convenient if you define a private function, with a name like MapIndex, in the Maze class that translates a state into an index into the map. For example, in the maze above, the robot can be at 25 positions from (0,0) to (4,4), but the character array is actually 11x11 characters, or 121 characters total. The upper left '+' is at index 0 and the lower right '+' is at index 120. The start state is (0,0), but this is index 100 in the one-dimensional character array. The goal state is at (4,4), or index 21. This should give you some ideas about how to check for walls. If the robot is in state (0,0) and wants to move right, just check the character at index 101 to see if it is '|' or '-'. If you want to move up, you must check index 100-11, or 89. Remember to write your MapIndex function in a general way that works for any maze of a given number of rows and columns.

You must write public methods for all of the necessary functions. These functions are

  1. Construct a Maze object: Given the number of rows and columns and a character array holding the map, initialize all private data structures.
  2. Destruct a Maze object. Be sure to delete all dynamic variables.
  3. Reset the maze: Replace all '*' with blanks. Also change the character at the start state position to 'S'.
  4. Get the start state.
  5. Test a given state to see if it is the goal.
  6. Test a state and a direction to see if there is a wall there.
  7. Test a state to see if it has been visited: Is there a '*' there?
  8. Mark a state as having been visited: Put a '*' there.
  9. Given a state and an action, return the new state.
  10. Print the current map, which will include all breadcrumbs.
  11. Overload the assignment operator.

Mapping a 2-D Array Index into a 1-D Array Index

Translating a row and column index to an index into the equivalent 1-D arary is very straightforward. It gets a little tricky for this assignment, because you must also translate from the robot position that skips every other array index as it moves.

Let's say the robot's position is at (r,c). For the example maze above, r and c are integers in the range 0 to 4. We want to find the linear function, f(r,c), that results in the 1-D index, which ranges from 0 to 11x11, or 121, for this example. Assume we are storing the characters of the maze in a 1-D character array in the order that they are read in. (Is this column major, or row major?)

Let's look at some example values of f(r,c). When the robot is in the upper left position, (r,c)=(4,0) for this maze. The 1-D index of the first '+' is 0, for the second '+' it is 10, for the first '|' it is 11, and for (r,c)=(4,0), it is 12. So f(4,0)=12. For the goal position, (r,c)=(4,4), and the 1-D index value is f(4,4)=20.

Now let's derive f. What is the form of f? We said earlier that it is linear. The most general linear form is

f(r,c) = u x r + v x c + w

How do we determine the constants u, v, and w? One way is trial and error, but this gets discouraging real fast. A more systematic way is to solve a set of simultaneous linear equations. To determine the values of the three constants, how many equations do we need? Three. We have two examples from above, f(4,0)=12 and f(4,4)=20. Let's pick a third that makes it real easy to find w. What is f(0,0)? The lower right '+' is at index 120, so the lower left '+' is at 110. The '|' above that '+' is at 110-11=99, so S, which is (0,0), is at index 100. So, f(0,0)=100.

Now our simultaneous linear equations are

f(0,0) = u x 0 + v x 0 + w = 100

f(4,0) = u x 4 + v x 0 + w = 12

f(4,4) = u x 4 + v x 4 + w = 20

The first equation tells us that w = 100. From this and the second equation, we get

u x 4 + 100 = 12

4u = -88

u = -22

Now we can solve for v in the third equation.

-22 x 4 + v x 4 + 100 = 20

-88 + v x 4 + 100 = 20

v x 4 = 8

v = 2

So, we now know that

f(r,c) = -22 x r + 2 x c + 100

For this assignment, you must generalize this for any maze with a given number of rows and columns. Your index mapping function must include these parameters, so f is now a function of four arguments, f(r,c,rows,columns), although if you write a mapping function as a method for your Maze class, rows and columns will be private variables and not arguments. You can derive this more general function f using the same simultaneous linear equation procedure, but the examples used to generate the equations must include the rows and columns parameters.

The Input Data File

The input data file contains a sequence of four mazes, each specified by the rows and columns on one line, followed by the initial character map. Click here to get the input data file.

Example Program Output

Here is what your output should look like when run on the first maze from the input data file:
+---------+
|     |  G|
|---- |	  |
|* *     *|
| |    	  |
|*|* * * *|
| | ------|
|*|* * * *|
| |       |
|S|* * * *|
+---------+
+---------+
|  * *|* G|
|---- |	  |
|* * * *  |
| |    	  |
|*|* *    |
| | ------|
|*|*      |
| |       |
|S|       |
+---------+
Maze 1 was solved with paths of 
       10 steps using a stack and
       8 steps using a queue.
The output from the other mazes will appear after this. While writing your solution, you should add lots of calls to cout to produce output you can use to debug your program. See this file of debugging output that was produced by a successful program.

WHAT TO TURN IN


Return to CS-200 Home Page

Copyright © 1998: Colorado State University for CS200. All rights reserved.