MP 3
MP 3
Maze Solver
This week, you will implement a maze solver using a recursive depth-first search, as well as a couple debug
functions to help find errors and to verify the solved maze. The goal of this assignment is to give you
experience with recursion, dynamic allocation, and structures, including pointer-based data structures like
linked lists.
Mazes are represented as text files, as shown in the example below:
11 11
%%%%%%%%%%%
S % %
% % %%%%% %
% % % % %
% % % % %%%
% % %W% %
% %%%%%%% %
% %W% %
% % % %%%%%
% %W E
%%%%%%%%%%%
The first two numbers are the width and height of the maze, followed by the structure of the maze. Each
‘%’ represents a wall within the maze, while spaces represent empty cells. The ‘S’ indicates the starting
position of the maze, and the ‘E’ indicates the the ending position of the maze. Finally, each ‘W’ indicates
a wormhole connected directly to all other wormholes.
Your program must determine whether the maze can be solved by finding a path from ‘S’ to ‘E’ by only
moving up, down, left, or right (moving diagonally or through walls is not allowed). After attempting to
solve the maze, your program must print out the maze with the solved path (if it exists) and all cells visited
during the search, and finally check whether your solution is valid or not. The following is a sample output:
Start of maze at (0, 1)
%%%%%%%%%%%
S.%+++++++%
%.%+%%%%%+%
%.%+%+++%+%
%.%+%+%+%%%
%.%+++%!% %
%.%%%%%%% %
%.%!% %
%.%.% %%%%%
%... %!..E
%%%%%%%%%%%
Maze is correct!
The ‘.’ characters represent the cells on the solution path for the maze (notice that the solution jumps
through a wormhole), while the ‘+’ characters represent cells that are not a part of the solution but were
visited during the search. Wormholes that are on the path or have been visited are changed to the ‘!’
character.
The Pieces
main.c contains the code to call the functions that you implement in maze.c as well as the
code for reading the maze input file
maze.h contains the function definitions and enumerated constants for the maze symbols
maze.c contains the functions that you must write; only code in this file will be graded
Makefile a file that tells the make command how to compile the files into a single program
Please note that when we grade your problem, we will use our own copies of main.c, maze.h, and the
Makefile. You may change these files to test your code, but do not expect us to make use of your versions.
Details
The reading of the maze from the text file input is handled for you by code provided in main.c. The maze
is represented as a 2D array (char** data within the maze_t structure), where the first index selects a
row and the second index selects a column (data[y][x]). You may assume that no maze is larger than
the maze in maze3.txt (51 characters x 51 characters).
There are four functions that you must implement for this MP:
int findEntries (maze_t* maze);
The argument to this function is a pointer to a maze structure that has been partially initialized. In particular,
the data field of the structure is the 2D array that represents the maze, and the width and height fields
represent the width and height of the maze, respectively. This function must complete the initialization of
the structure by locating the starting position, the ending position, and all wormholes (if any). The starting
and ending positions must be stored directly into fields of the maze structure. The upper left corner of the
2D array is (0, 0), and the bottom right corner is (width - 1, height - 1). You may assume that no more than
one start or end will appear in the maze. If no start is present in the maze, the fields xStart and yStart
point to should equal -1. Use a similar approach if the maze end is missing. Any wormholes found must
be inserted into a cyclic, doubly-linked list of wormhole_t’s. You must perform the dynamic allocation
for these wormhole structures. If allocation fails, return 0 from this function (the ONLY reason to return 0).
Note that the maze structure contains one wormhole_t that serves as a sentinel for the list, and note that
this sentinel is NOT initialized before you function is called. See maze.h for the structure definition. If
allocation does not fail, return 1 for success.
void printMaze (const maze_t* maze);
Given a pointer to a maze structure, print the maze in a human readable format to the console (stdout).
The maze should be printed in the same format as the mazes in the example files.
int solveMaze (maze_t* maze, uint32_t xPos, uint32_t yPos);
Given a pointer to a maze structure along with the current x and y position, recursively solve the maze,
mark the solution path (if one exists), and mark all visited locations as VISITED (an enumerated constant
meaning ‘+’). Notice that the start and end positions should NOT be overwritten by the path nor as having
been visited. The function must return 1 if the maze has a solution, or 0 if it does not. However, in both
cases, the maze must be marked properly. A path can only use any given wormhole once; even if the path
simply passes by the wormhole (doesn’t jump), the wormhole cannot be used again.
int checkMaze (const maze_t* maze);
Given a pointer to a maze structure, check to see if the solution path is valid. A valid solution is a single
path of PATH characters from start to end with no detours (the path may jump through wormholes, of
course). In other words, the solution cannot branch. If the solution is correct, this function should return
1, otherwise, return 0.
Depth-First-Search Algorithm
You must implement a recursive depth-first search (DFS) algorithm in your code. The term “depth-first”
refers to the fact that your solution should explore as far as it can along one path before going back to
explore alternate routes. You may remember that we talked about a breadth-first search (BFS) early in our
class; in such a search, all routes of a given length are explored before any longer routes are considered.
DFS is what you will obtain naturally by solving this problem recursively: if your solveMaze function
calls itself more than once, the second call cannot execute until the first call returns, meaning that the first
path has been explored as deeply as possible.
The tricky part of this problem is making sure that you handle the start, end, and wormholes correctly with
regard to marking them. Again, they should not be left VISITED nor on the PATH when your solveMaze
has finished.
Specifics
Your program must be written in C in the file maze.c provided for you.
You must implement findEntries, printMaze, solveMaze, and checkMaze correctly.
Your routine's return values and outputs must be correct.
Don't change the function definitions for the functions you have to implement.
Be sure to access the maze as row first then column (data[row][column]).
Your code must be well-commented and include an introductory paragraph.
You may assume that the maze is acyclic and that the maze has no more than three
wormholes.
Grading Rubric
Functionality (100%)
20% - findEntries works correctly
10% - printMaze works correctly
50% - solveMaze works correctly
20% - checkMaze works correctly