Description
In this lab and the next, you are going to write a program that explores a
maze. This provides an example of arrays being used to do interesting things,
introduces an interesting area of artificial intelligence (robotic navigation),
and may give you some ideas about game programming if you are interested
in that kind of thing.
Keep in mind that lab twelve is a continuation of this program, so don’t
lose it. It would probably be a good idea to read the lab 12 assignment too, so
that you know what’s coming.
Today you will be getting the display to look good, and making sure you
can move a little robot about inside the maze. In the second session, you will
work on automation, making the robot/man/woman/whatever move around on
his/her/its own, and making it more of a game. From now on, I’ll just refer to
the moving thing as “the robot”.
The first task for your program will be to read a picture of a maze from a file, and
store a suitable representation of it in memory. The file containing the picture will be
called “maze.txt”, and it will contain a text representation of a rectangular maze, with
the character ‘#’ used to represent a wall, and ‘.’ will be used to represent open space.
This is an example of one possible maze file:
######..#..#####…#####…….
…#……….#…..##.#……#
..##.###.###.####.#..#.#.#.##.#
#..##..#.##…#.#.##…#…#..#
##..##.#….#…..###.##.###.##
#.#.#….#..#.###..#..#..#.#…
#.#..#.########.#####….#.##..
..#……..##A…..#####…##..
….##.###..##.#.###…###.#..#
..#.#…………….#…#.#B.#
..###############……########
It would be a little easier to look at if we used spaces instead of dots, but remember that
C++ likes to ignore spaces when reading input, and we don’t want to introduce unnecessary
complications. To save typing, you can download that maze file from:
http://rabbit.eng.miami.edu/class/een118/labs/maze.txt
Notice that there isn’t a solid wall of #s around the maze. This means that you will have
to be careful to prevent your robot from falling off the edge of the world. It is not permitted
to get around obstructions by going outside the maze.
Notice also that there is a single ‘A’ and a single ‘B’ in the maze. Every valid maze will
have one ‘A’ and one ‘B’ in it. The ‘B’ represents the treasure, and the ‘A’ marks the starting
point. The object is to get your robot from its starting point to the treasure staying within the
maze and without using any squares marked ‘#’.
Diagonal moves are not allowed, and no maze will have more than 100 rows or 100
columns.
1. Read the Maze
Build a program that creates an appropriate array to store the maze, opens the file, reads
the maze into the array, then closes the file and proves to you that it read the maze correctly
by printing it again in a slightly different format.
How should you print the maze after reading it? Remember that the reason for doing
this is to be absolutely certain that you really have read the maze correctly, we don’t want
there to be any risk that you’ll accidentally print out the contents of the file and trick
yourself. Wait until you have read the entire file and closed it, then reprint the maze from
your array, using different symbols. Perhaps ‘@’ for walls and real spaces for the spaces. It
will be easy to see that the maze is the right shape, but it will obviously not be just a copy.
2. Detect A and B
Modify your program so that it notices where the ‘A’ and ‘B’ are, and stores the
coordinates (row and column) in suitable variables.
3. Draw it Properly
Instead of drawing the maze with stars and spaces, open a graphics window and draw it
properly. I would suggest first drawing a grid of the right size, then filling in the wall parts
with a solid colour. Make sure each square occupies enough pixels to be seen clearly. Then
mark the position of the ‘A’ and ‘B’ in some way that stands out. Perhaps a different coloured
blob:
4. Make the Robot Move
The library contains a function called wait_for_key_typed(); it waits until the
user types a key on the keyboard, then returns as its result the ASCII code for that key. Use it
to make the robot move around under your direct control.
Remember that C++ does not expect you to have memorised all the ASCII codes. If
you put a single character inside single quotes, C++ sees it as the ASCII code for that
character. So, if you choose to use the letters l, r, u, and d to stand for left, right, up,
and down, you might have something like this in your program.
while (true)
{ char c = wait_for_key_typed();
if (c == ‘l’)
{ /* make the robot move one square to the left */ }
else if (c == ‘r’)
{ /* make the robot move one square to the right */ }
else if (c == ‘u’)
{ /* make the robot move one square up */ }
else if (c == ‘d’)
{ /* make the robot move one square down */ } }
Note that this function does not behave like “cin >>”. It does not wait until enter has
been pressed at the end of the line, and it only takes keystrokes that were aimed at the
graphics window. If the black text window is selected, keys typed go to cin, and
wait_for_key_typed() doesn’t get to see them. The graphics window must be selected.
You might like to take advantage of the fact that all the non-ASCII keys have also been
assigned numeric codes. In particular, the arrow keys have negative numbers assigned to
them as follows:
down arrow -88
right arrow -89
up arrow -90
left arrow -91
It might also be a good idea to have an x (exit) or q (quit) command for when you get
fed up with playing.
Do not worry about walking through walls or falling off the edge of the world yet. Just
update the robot’s position after each move. The player will have to be careful to navigate
properly.
Try it out, make sure you can navigate the robot to his target. I hope you remembered to
update the picture after each movement, so that you see the robot in its new position.
5. Prevent Walking Through Walls
Make the exploration more realistic by refusing to obey impossible commands. If a
movement would result in the robot walking through (or into) a wall, or off the edge of the
world, then that movement command must not be obeyed.
6. A Foolish Robot
Your robot does not move except under your direct command. Add another command
letter, perhaps ‘A’, that puts him in Automatic mode. When in automatic mode, the robot
should repeatedly select a random neighbouring empty square, and move into it, until he
happens upon the treasure.
One way to achieve this would be simply to stop calling wait_for_key_typed()
once the robot is in automatic mode, but then you would never be able to get him out of
automatic mode. Fortunately, the wait_for_key_typed() has a little bit of extra
functionality. It can take one optional parameter, a floating point number telling it how long
(in seconds) to wait for the user to type a key.
This statement
char c = wait_for_key_typed(O.O);
will not wait at all. If the user has already pressed a key, then everything is fine, and c is set to
that key’s ASCII code as usual. Otherwise, c is just set to zero instantly.
Add another letter command, perhaps ‘M’ for Manual, that turns off automatic mode, and
puts the robot back obediently under your command. You will probably find that 0.0 seconds
isn’t the ideal maximum wait for keyboard input.
7. Enemies
A maze is very easy to solve without any opposition. You now need an enemy. First edit
the maze text file, and replace one of the ‘#’s or ‘.’s with an ‘E’. This is to indicate your
enemy’s starting position.
Now make your program take note of the position of the ‘E’, just like it did for the ‘A’
and ‘B’. On the display, choose another colour to represent the enemy, and make sure he
appears correctly.
Every time your robot makes a move, your enemy should also make a move. Just like
the robot in automatic mode, make the enemy move into a random neighbouring non-wall
square. That won’t make for a very impressive enemy, but you’ll improve it later.
And naturally, a useful enemy has to do something inimical. If the enemy ever walks
into your robot, you lose. Game over.