Computer Science 60
Principles of Computer Science
Spring 2007

Assignment 7: Spampede!
Due Tuesday, March 11 by 11:59 PM

This assignment asks you to extend the capabilities of your maze solver from HW6 (though you may use our solution code if you prefer). In addition, you will incorporate your Maze and maze-solver into a Java applet-based game that is similar to "Nibbles." Since it's spam-seeking, we'll call it Spampede. Please start this assignment early. It's fun - but also challenging!

What is the final product?

There are three parts to building your intelligent spam-seeking spampede... .



Submitting

Because there are so many files that may be involved in this assignment, you should zip the entire folder (which you might still have named hw7files) into hw7files.zip and then submit that zipped folder.



Part 1:     improving Maze.java [25 points]

This project introduces and practices a number of different techniques that are common to software engineering, that is the design and implementation of large software projects. Certainly this assignment can only provide a hint at a very rich -- and important -- field.

The first part is to improve the Maze class in which you wrote breadth-first search for assignment 6. In particular, you may start with our Maze.java file (in the hw7files.zip folder) or use your own. Either way, you should start by making sure you add at least four public accessor methods to the MazeCell class within Maze:

These methods will be important for getting and setting values in other classes that you build in parts 2 and 3 of the assignment.

You should have a new zero-input contstructor for Maze (this is already in the solution file, or you can copy it from here:

protected Maze()
{
  int HEIGHT = mazeStrings.length;
  int WIDTH = mazeStrings[0].length();
  this.maze = new MazeCell[HEIGHT][WIDTH];
  for (int r=0 ; r<HEIGHT ; ++r) {
    for (int c=0 ; c<WIDTH ; ++c) {
      maze[r][c] = new MazeCell(r,c,mazeStrings[r].charAt(c));
    }
  }
}
This constructor loads a maze in from the static data member named mazeStrings, which is simply an array of strings contained in Maze.java. The nice thing about this is that you can edit your Maze directly in the file! Also, applets are not permitted to read files for security purposes, so this will be the maze you use in your applet. Feel free to customize it!

What is protected?

The access level protected indicates that derived classes may use a method (or data member), but not simply any class at all. It is between the access of public (any class may use it) and private (only the defining class may use it). Since part 2 asks you to write a class named SpamMaze that derives from Maze and SpamMaze will use this zero-argument constructor, protected is an appropriate access level.

A more flexible breadth-first-search

The final method to write in Maze.java is

protected MazeCell multiBFS(MazeCell start, char destination) ...
which will implement breadth-first search from start to ANY cell containing the character in destination, which will typically be a 'D', representing spam. Because it is breadth-first search, the method should find the closest destination to the start MazeCell. This is slightly different than the original BFS you wrote for hw6, and represents a reasonable example of the "lowest-level" of software reuse: copy-and-paste!

What should multiBFS do?

This method should have the following behavior:

Testing your code

Be sure to test your code thoroughly before heading to part 2 of this assignment... there is a test in main for this purpose, and you should try editing the mazeStrings in order to make sure it works in a variety of conditions!





Part 2:     writing SpamMaze.java [50 points]

The overview

In this part of the assignment you will create a derived class named SpamMaze that handles the model for the applet, which is part 3. A derived class is simply an extension of the data and capabilities (methods) available in the base class. Thus, by starting the code as in the provided SpamMaze.java file:

import java.lang.Math;
import java.util.LinkedList;

class SpamMaze extends Maze
{
  // your code goes here...
}
you should keep in mind that any object of type SpamMaze IS also an object of type Maze. This is identical to the relationship of every object with Java's Object type. Object is the base class of all Java classes.

The data

Because a SpamMaze object represents the model for the Spampede applet, it needs to keep track of (1) the maze, (2), the centipede, and (3) the spam in the environment. Remember that (1) is already taken care of because your SpamMaze is a derived class of Maze. To keep track of (2) and (3), you should use lists of MazeCells. In particular, you will declare two data members:

  // The data members representing the spam and the centipede
  private LinkedList<MazeCell> spamCells;
  private LinkedList<MazeCell> pedeCells;
Each of these is of type LinkedList<MazeCell>, which is the Java-library version of a double-ended queue implemented via a linked list. You will thus have access to the methods listed at http://java.sun.com/j2se/1.5.0/docs/api/java/util/LinkedList.html. Notice especially the methods addFirst, addLast, removeFirst, removeLast, getFirst, getLast, and get(int n). Each get method is similar to peek in that it returns a value, but does not change the list. You can ask the size of a list with size(), which returns an int.

The methods

You should, in essence, implement all of the functionality, but not the graphics front end, for the Spampede game inside SpamMaze. Here is one possible suggestion for a decomposition into methods:

Notes on the behavior of the centipede



Testing!!

As with Maze, be sure to test your SpamMaze thoroughly in main before worrying about the graphical front-end of the applet in part 3. Below is my main method, which you should feel free to adapt to your implementation. Remember that you do not need to write toString -- the version that's already in Maze will work perfectly well!


  public static void main(String[] args)
  {
    SpamMaze SM = new SpamMaze();

    System.out.println("SM is\n" + SM);
    MazeCell nextSpot = SM.multiBFS(SM.pedeCells.getFirst(), SPAM);
    System.out.println("nextSpot is\n" + nextSpot);
    System.out.println("SM is\n" + SM);

    SM.advancePede(EAST);
    System.out.println("SM is\n" + SM);
    System.out.println("pedeCells is " + SM.pedeCells);

    SM.advancePede(EAST);
    System.out.println("SM is\n" + SM);
    System.out.println("pedeCells is " + SM.pedeCells);

    SM.advancePede(EAST);
    System.out.println("SM is\n" + SM);
    System.out.println("pedeCells is " + SM.pedeCells);

    SM.advancePede(SOUTH);
    System.out.println("SM is\n" + SM);
    System.out.println("pedeCells is " + SM.pedeCells);

    SM.advancePede(SOUTH);
    System.out.println("SM is\n" + SM);
    System.out.println("pedeCells is " + SM.pedeCells);
  }



Part 3:     writing Spampede.java [50 points]

The overview

The Spampede applet gives a user control over a spam-seeking centipede. Key presses from the keyboard change the direction of the centipede's movement in order to intersect snacks (spam) that appear at random places on the screen. For each snack consumed, the centipede grows by one segment (a segment is simply one MazeCell). Variations are welcome (see Ex. Cr.)!

As a result, in this part of the assignment you will be modifying another derived class, this one named Spampede, which is a derived class from Java's JApplet. This means that your Spampede is itself an applet that will run in a Java-enabled browser from anywhere.

Setting up

The "starter" applet Spampede.java and its html file Spampede.html are provided for you in hw7files from the top-level assignments page.

Finally, we have also provided the following files which you may wish to use (but they are totally optional):

Getting the applet compiling, running, recompiling, and rerunning

Make sure that you can compile the provided "starter" applet with javac *.java. Then, you should choose "Open...File" in a browser window and select the file Spampede.html from the folder in which you just compiled. The applet should start.

Getting debugging information from the Java console

In order to see output from print statements (or any errors), you should open the Java console. On the PC, this can be done by right-clicking the little Java icon from the lower right of your screen and choosing "Open Console." On the Mac, you need to go a bit further... . Go to "Applications - Utilities - Java - J2SE 5.0 (or your version) - Java Preferences," and then go to the "Advanced" tab, the "Java Console" options, and select "Show Console." You may need to restart your browser or at least reload the page after this sequence of commands.

Making sure you get the NEW applet after making changes

You can make sure you get the NEW applet to which you've made changes (do remember to recomplile, too!) by typing an 'x' in the Java Console window. It's also a good idea to clear the window so that you know which output is from the latest run of your applet. Then, when you hit the "Reload" button in the browser, the new applet should be loaded and run.

Writing the applet

Once the above steps work for you, you're ready to write Spampede by the modifying Spampede.java file with the following things in mind.
  • Create, in init, a SpamMaze and make sure it is in a suitable starting configuration. There is already a data member named this.themaze to hold the created object.

  • Draw the contents of the SpamMaze within the drawEnvironment method already provided. This will require writing a nest loop to create the 2d array of 10x10 pixel squares that represent the maze. This drawEnvironment method will be called every so often by the cycle method to show the latest state of the maze. You should use different colors of your choice representing walls, empty space, the head of the centipede and the body of the centipede. You will want to use the fillRect command to accomplish this.

  • Update the spam within the SpamMaze named world. Within updateSpam you can add (and/or remove) spam every so often (though every cycle is probably too fast!). You can also add spam as needed (e.g., when one is eaten). But, you should make sure to have spam on the board at all times!

  • Keep track of the centipede (i.e., the "spampede"). The updatePede method is provided as a placeholder for where you would do this. You might want a data member that keeps track of the centipede's current direction so that advancePede can be called appropriately. In this case, key presses would simply change the internally-stored direction (I used a char.) Keep in mind that no MazeCells are moving as the centipede crawls through the maze! Rather, it's the data member named pedeCells of type LinkedList (within SpamMaze) that's wending its way through the 2d array of MazeCellss.

  • Handle key presses. You will see a method that prints out certain characters when track of the centipede (i.e., the "spampede"). When the user presses the following keys, the centipede should change direction as indicated:
    • r : reverse, switching its head's position to its tail
    • i : turn north
    • j : turn west
    • l : turn east
    • k : turn south
    • a : go into autonomous, spam-seeking mode ("AI")
    If the centipede is already heading in the direction that the user chooses, nothing changes. If the user changes the centipede's direction so that it is moving back on itself (from South to North, say, or West to East), you may reverse direction, ignore the command, or "terminate" the centipede.

  • Note on "reverse" The reverse key (r) does not necessarily send the centipede in the compass direction opposite to which it was just heading. Instead, it switches the current tail to become the head and the current head to become the tail. It then should determine which direction the centipede's head segment and second segment are heading and set the current heading appropriately. You might want a public method inside SpamMaze that does this.

As you write your code, please compile and rerun the applet often to make sure you're on the right path. Use the Java Console to help with debugging and error-detection. Basically, this means many iterations of the compilation, copying, and testing steps above.

I want more!

If you haven't had enough of the Spampede.java file at the end of this assignment, there are a couple of specific items and an open-ended invitation to improve on the applet for optional bonus credit. (Up to 25 points in total.)

If you add optional features, please document them in ALL UPPERCASE in a comment at the top of your Spampede.java file so that the grutors will see this.

  • Speed up: You might want to have the rate at which the centipede is moving to increase as the game progresses.

  • Scoring: You might want to have a system of scoring with a running total displayed as a label or text field or simply drawn to the applet panel.

  • Lives: Rather than resetting or stopping the game after a single Spampede crash, keep a text field (or label) with the number of lives remaining and decrement it after each crash. When there are no lives left, stop the game (though you might want to consider a "reset" button.)

  • Levels: Rather than maintaining a single, static maze, you may want to have the centipede advance to different mazes after consuming enough spam.

  • Wrapping: Allow the centipede to wrap around the game board -- either in an unlimited fashion or through small tunnels in the walls. Or you might consider a "hyperspace" square, that "sends" cells to another spot on the board.

  • General improvements: Feel free to add additional features you think would enhance the Spampede applet: different kinds of spam, sounds, images, other graphical widgets like pull-down menus or text boxes, etc.