Back to 111 Main Page

Mobius strip

Assignment 12

Task

Combine everything you've learned so far to write a very simple maze game. (The maze is simple, not the program! Compare to Rogue and NetHack.)

Overview

Write a turn-based maze game. The maze is a simple 12x8 rectangle with a single exit. (So it's really just a big room, not a maze.) The player is represented by a single character on the screen. The player starts at a random place somewhere in the maze-room, and the exit is at some random location on the right/east side of the maze-room.

Each turn, print the current map of the maze-room and ask the user which direction they want to move.

The game ends when the player reaches the exit. Print some congratulatory message and end the program.

Requirements

Drawing the map. The map must be the requested size, but which characters you use for the player, exit, and floor are up to you (as long as each is different). Here is what the maze might look like on the screen using '*' for the player, '=' for the exit, and '.' for the room floor.

............
............
............
......*.....
............
............
...........=
............
Enter next move (N/E/S/W):

On the other hand, you might use 'P' for the player, 'E' for the exit, and ' ' for the floor. (' ' works for the floor only if you do the borders extra credit, below.)

--------------
|            |
|            |
|            |
|      P     |
|            |
|            |
|           E
|            |
--------------
Which way do you want to move [(u)p, (d)own, (l)eft, or (r)ight]?

Input characters. You may choose from one of 3 direction input systems:

  • n, s, e, w (compass directions)
  • u, d, l, r (up/down, left/right)
  • w, a, s, d (keyboard controls)
Your program is required to accept only one of these systems, using lowercase letters. Clearly indicate in your program's output how the user should enter a move. You may support additional input options, if you want: more than one system, uppercase characters, typed words, numbers, etc. (Note that it's easy to accept diverse input if you just uppercase or lowercase the input and then take the first character.)

Constants. In your program, use final variables to hold the following details:

  • The width of the maze
  • The height of the maze
  • The characters used to print the player, floor, exit, and any other features of the maze-room.

You should be able to change only the values assigned to these variables in order to change the size, shape, or look of your maze. (Of course, your program should still work correctly after making such changes.)

If you want to use methods, you can declare your constants inside your class but outside of any method, like this:

  //constants used in drawing the maze
  public static final int MAZE_WIDTH = 12;
  public static final int MAZE_HEIGHT = 8;
  //...etc...

If you do this, these variables will be accessible from any method.

Instructions to the User. Be sure to explain any necessary rules, important characters, or input requirements in your user interface.

Player Placement and Movement. Place the player and exit randomly at the start of the game. (The exit should be somewhere on the right/east wall of the maze though.) Be careful not to initially place the player on the exit square. Also, do not let the player move beyond the bounds of the maze.

Error-handling. If the player enters something other than one of the valid movement choices, print an appropriate error message and ask the user to try again.

Coding Standards. As with all assignments since A10, you must follow Java Coding Standards while writing the code for this program.

Sample output

Here is some sample output to give you a better idea of how a sample game might look from start to finish:

Move your character (*) to the exit (#).
You may move North, South, East, or West.

............
...........#
............
........*...
............
............
............
............
Enter next move (N/E/S/W): n

............
...........#
........*...
............
............
............
............
............
Enter next move (N/E/S/W): E

............
...........#
.........*..
............
............
............
............
............
Enter next move (N/E/S/W): down
Sorry, but "down" is not a valid direction choice.  Try again.
Enter next move (N/E/S/W): quit
Sorry, but "quit" is not a valid direction choice.  Try again.
Enter next move (N/E/S/W): e

............
...........#
..........*.
............
............
............
............
............
Enter next move (N/E/S/W): e

............
...........#
...........*
............
............
............
............
............
Enter next move (N/E/S/W): e
You can't leave the maze except through the exit!

............
...........#
...........*
............
............
............
............
............
Enter next move (N/E/S/W): n

You've made it out of the maze!

Hints

As long as you satisfy the above requirements for the program (also see Grading, below, to double-check), you can go about solving this problem however you want. However, if you're stuck, here are the steps I'd suggest.

However you choose to go about it, remember to program one step at a time! You should be compiling, running, and testing your program after every few lines you write to make sure everything you've written so far is correct. Often, when writing loops, to helps to write code from the inside out, rather than top to bottom.

  1. Define constant variables for the maze details: width, height, floor, player, exit.
  2. Define a variable for the location of the exit. Since this will always be on the right wall of the maze-room, you really only need the row/y-coordinate. Consider something like this:
    mazeExitY = (int) (Math.random() * MAZE_HEIGHT);
    
    If MAZE_HEIGHT is currently 10, this will set mazeExitY to some random number between 0 and 9.
  3. Define two variables that will hold the player's location. You need an X (column) and Y (row) position of where the player is on the board. These will initially be assigned a random position.

    How you determine the coordinates of your maze-room is up to you. It's generally traditional in graphics to treat the upper-left corner as (0,0). This would make the lower-right corner of the room (MAZE_WIDTH - 1, MAZE_HEIGHT - 1). (The rest of these suggestions assume this system.) However, you could make the lower-left corner your origin, and/or you might want to start indexing at (1,1).

    Remember to try printing out your variables a few times before continuing to make sure you're getting random numbers in the complete range.

  4. Print the maze-room. This is probably the trickiest part of this assignment.
    • First, use a loop to print (one character at a time) a line of FLOOR characters that is MAZE_WIDTH long. This corresponds to a single row on the board/maze-room. (You might want to name the loop counter x for this loop.)
    • Now build a second loop around this first one in order to print each row MAZE_HEIGHT times. (You might want to name the loop counter y for this loop.) At this point, you should be able to print a 2D board/maze-room.
    • Now you can add conditionals within the inner loop to determine what to print based on the current (x,y) position that is being printed. For example, if the current (x, y) matches that of the player's location, print the character that represents the player.
  5. Get the next move from the player.
  6. Update the player's position accordingly. For example, if the player is moving north/up, playerY--; would update their position. However, before moving the character, make sure this doesn't move them off the board/out of the maze.
  7. Move loop. Now you're finally ready to build a loop that keeps asking the player to move until they reach the exit location.

It is recommended you use methods to break up the program into more manageable chunks, but it is not required.

Extra Credit

Once you meet the basic requirements for this maze game, you may add some additional features. Here are a few suggestions:

  • Draw a border around the maze-room. (MAZE_WIDTH and MAZE_HEIGHT should still specify the dimensions of the space within the border.) (0.5 point)
  • Randomly place the exit on any wall of the maze-room, rather than only on the east wall. (0.5 point)
  • Move the exit each time the player moves. This should be in some predictable manner. For instance, the exit might move up the east wall one space each turn until it reaches the top wall, and then it begins to move down the wall again. (1 points)
  • Add a monster to the room that moves each turn towards the player. Of course, the game ends gruesomely if the monster makes it to the player before the player makes it to the exit. (This might be a better game if you provide two exits to choose from, or a wormhole/teleport option, etc.)(1 points)

You may come up with additional ideas of your own. If you include any extra features, be sure to mention them in your initial class documentation.

Only a total +3 points of EC will be awarded, and only if the required features of the game work.

What to Submit

Upload your UsernameA12.java file to Tamarin.

Grading

Out of 10 points:

1 - Compiles + Coding Standards
Your program compiles successfully (no errors). Your code follows Java coding standards.
1 - Constants
Maze details are defined and used through constants such that changing only the value initially assigned to these constants changes the program accordingly.
1 - Random placement
The player and exit are both randomly placed (though not at the same place). The exit is always along a wall.
2 - Prints room
Prints the room, displaying the current location of the player and of the exit.
2.5 - Player movement
The player can move their character around the maze-room board using one of the three input schemes outlines above.
1.5 - Constrained to board
The player cannot move their character off the board.
1 - User Interface
The UI includes sufficient instructions on how to play the game; errors such as incorrect input are detected and clearly reported.
+3 (max) - Extra Credit
For clearly documented extra features. Only 3 points maximum, and only if all basic requirements have been met.

For those of you that submitted A12 before the original due date, you may resubmit once without the normal -0.2 penalty.

FAQs

Where is the demo code from lab?
Here: MoreLoopExamples.java

As with A11's LoopExamples, this file contains the solutions to the problems we did in lab as well as some additional problems. Again, I recommend you read the top of the file and try writing the solutions to all the problems before reading through my solutions. As a learning tool, 80% of the value of these exercises come from when you actually try to write the code yourself. If you at least read through and really understand how all these solutions work, that'll give you the other 20%.

How did that double for loop go?
Assuming you defined the necessary constants for MAZE_WIDTH, MAZE_HEIGHT, and FLOOR, this will print out a 2D grid that represents the room:
for (int y = 0; y < MAZE_HEIGHT; y++) {
  for (int x = 0; x < MAZE_WIDTH; x++) {
    System.out.print(FLOOR);
  }
  System.out.println();
}
This just prints the FLOOR for every character. So you will need to add some conditionals (if/else-if/else statements) to determine which character to print out at each square. The loop counters x and y tell you what location you are currently printing. You will need to check to see if that (x, y) location is the same as the player's location (playerX, playerY). If so, print PLAYER. If it's the location of the exit, print EXIT instead. Otherwise, just print FLOOR.
I still don't understand how to print the player and the exit in the maze.
As explained in the previous answer, you need to use some conditionals to determine which single character to print at each location in the room. Here is the basic structure, though you will need to replaces the /* comments */ with the appropriate code:
for (int y = 0; y < MAZE_HEIGHT; y++) {
  for (int x = 0; x < MAZE_WIDTH; x++) {
    if (/* x and y  == playerX and playerY */) {
      /* print the player */
    }else if (/* x and y  == exitX and exitY */) {
      /* print the exit */
    }else {
      System.out.print(FLOOR);
    }
  }
  System.out.println();
}
Note how only one character will be printed each time through the loop(s)--either the player, the exit, or the floor.
Do I have to repeat that map-printing code again after I move the player?
No, you only need the code that prints the map in one place. You will use a loop to return to the map printing code after you have moved the player. In other words, your code should have this basic structure:
while (player has not reached the exit) {

  /*
   * Print the map (using two nested for loops, as shown above
   */

  /*
   * Ask user to move.
   * (Make sure they enter a valid move.
   *  Don't move the player off the map.)
   * Update playerX/playerY to new player location.
   */
}

/*
 * (Loop ended because player finally reached the exit.)
 * Print congratulatory message.
 */
You might move some of this code out of the while loop and into a couple methods, but it's not required. You will still need this basic loop structure somewhere.


~ztomasze Index : TA Details: ICS111: A12
http://www2.hawaii.edu/~ztomasze
Last Edited: 25 Feb 2008
©2008 by Z. Tomaszewski.