Computer Science 60
Principles of Computer Science
Spring 2009

Assignment 7: Spampede!
Due Friday, March 13 by 5 PM

Please read the following carefully. There is a lot here!

  1. First, note that this assignment is due at an unusual time: Friday, March 13 at 5 PM. The assignment is also worth 130 points rather than the usual 100. The following week is spring break and there is no assignment over the break. No extensions are permitted on this assignment (e.g. no "Euros").

  2. Next, a friendly reminder that the midterm exam will be in class on Wednesday, March 11 (for Section 1) and Thursday, March 12 (for Section 2). The exam will cover material up to, and including, the lecture before the exam. You may bring an 8.5 by 11 sheet of paper with writing on both sides (your own writing please). Write down anything on that sheet that you like. The purpose of this sheet is to minimize memorization so that you can concentrate on concepts instead. You will submit the sheet with your exam but will get it back.

  3. This week it's time to change programming partners. If you are pair programming, you should program with someone with someone with whom you have not previously sumbitted together. You and your new partner may work together for the remainder of the semester if you wish. Pair programming is permitted on all three parts of this week's assignment.

  4. You will be submitting several files for this assignment. Please submit every file that you used for your assignment. We will look for Maze.java (Part 1), SpamMaze.java (Part 2), and Spampede.java (Part 3). If you define any other files as part of your project, please submit those too.

  5. This week, we ask that you also submit a file that is typically submitted in any large software project: A text file called README. We have left a basic README file in the homework directory for this week: /cs/cs60/hwfiles/a7/. You should edit this file and submit it. The README file constitute part of your score on this assignment.

This assignment has three parts, which ultimately build to the Spampede game! In Part 1, you will extend the capabilities of your maze solver from HW6 (though you may use our solution code for that assignment if you prefer). In Part 2, you will use the results of Part 1 to build some of the primary functionality of the Spampede game. In Part 3, you will use Part 2 in a graphical applet that you (and your friends) can play on the web!


What is the final product?


Part 1:     Improving Maze.java [20 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 either your own Maze.java file from last week or you may use our solution to that problem in /cs/cs60/hwfiles/a7. Either way, the internal data in the MazeCell (row, col, contents, etc.) MUST be private and you should start by making sure you add at least four public accessor ("getter and setter") 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()
{
        ROWS = mazeStrings.length;
        COLUMNS = mazeStrings[0].length();
        this.maze = new MazeCell[ROWS][COLUMNS];
        for (int r=0 ; r< ROWS ; r++) 
        {
            for (int c=0 ; c< COLUMNS ; 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! Notice that we are assuming that the Maze class has data members named ROWS and COLUMNS that keep track of the dimensions of the array.

What is protected?

When data or methods are given the access level protected, it means that derived classes may use that data or method. However, unrelated classes may not use that data or method. Thus, protected is in-between the access level of public, which any class may use, and private, where only the defining class may use the data or method. Because part 2 of this assignment asks you to write a class named SpamMaze that will be a class derived from Maze and because 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. Note that this is slightly different from the BFS that you wrote on hw6. Now, you will need to make sure to stop the BFS process when it first reaches a destination of the type that you are looking for!

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. At a minimum, you should implement the following methods. You may choose to add more methods - either private helper methods (to help these public methods) - or other public methods for your game to use.

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 a 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:     Putting it all together: Spampede.java [60 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 the extra credit section below)!

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 /cs/cs60/hwfiles/a7 from the top-level assignments page.
There are some other files you'll need, too, such as ImagePanel.java. Be sure to grab it with

   cp /cs/cs60/hwfiles/a7/ImagePanel.java .
     
into your working directory.

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. There are two ways to test your applet. (Appletviewer) You can run appletviewer Spampede.html from the directory containing your code, or (browser) you could use a new tab in an open browser and choose "Open ... File" from the menu. Choose the local copy of Spampede.html from the folder in which you just compiled. The applet should start in either case.

Getting debugging information from the Java console

If you're using appletviewer, the print statements in your code will appear in the terminal window from which you started the viewer.

If you're using a browser, 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 may need to go a bit further. Some browsers have a menu option that simply states "Java Console." Other require you to activate the console first: 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.

If you run into troubles with these low-level details, please seek help -- they're not worth spending much time over. But it is important to be able to debug your code through print statements... .

Making sure you get the NEW applet after making changes

If you're using a browser, 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. The appletviewer should always reload the most recent version.

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.
  • Be sure to create, in init and/or in reset, 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. This may already be done for you in the code, if you are using the zero-argument constructor for SpamMaze.

  • Draw the contents of the SpamMaze within the drawEnvironment method already provided. This will require writing a nested 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 themaze. Within updateSpam you can add (and/or remove) spam every so often -- though doing so every cycle will probably be too fast!. You can also add spam as needed (e.g., when one is eaten). But, you should make sure to have at least one 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 -- the provided code has a data member private char dir that you might use for this. In this case, key presses would simply change this internally-stored dir.

    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 that's snaking its way through the 2d array of MazeCellss by changing the cells to which it refers.

  • 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.

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

Going on the Web!

Once your applet is done, it's time to let your friends and family waste hours of precious free time playing Spampede! In the /cs/cs60/hwfiles/a7 directory is the shell script called copyFiles that we discussed in class. In a nutshell, this file contains a sequence of Unix commands to copy the necessary files from the directory where you developed your program into your web space on knuth.

To use copyFiles, first give yourself "execute permission" by typing chmod u+x copyFiles. Now you, (the "u" stands for "user" - that's you) have permission to execute this script. Then, type

copyFiles
at the unix prompt. If this does not work, type
./copyFiles

When you run copyFiles should expect to see a message like:

chmod: cannot access `/home/apaul/public_html/*.java': No such file or directory
This is just indicating that there were no java files in your web directory. This is a good thing! We just have a line in the copyFiles script to make sure that if you did copy a java file into your web directory for any reason, it will have its read permissions shut off.

Now, open a web browser and use the url www.cs.hmc.edu/~yourUserName/Spampede.html. Your game should now be running from that web page. If the game display is messed up for any reason, try another browser. Some browsers (rarely) are not configured correctely and cause applets to be drawn "funny". Please do not put any java code on your website. Our script does not do this (it only puts the compiled .clas files and other ancillary stuff) and you should not either to avoid having your code exposed to the world.

Of course, if you make changes to your code in your working directory, you will need to compile it again and copy the files again to your website.

A Reminder On What to Submit

Please be sure to submit all of the .java files required for all three parts of this assignment. In addition, please submit your README file described at the very top of this web page.

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 explain them carefully in the README file.


  • Enemy Pedes!: Allow there to be one or more "enemy" pedes that use the multiBFS and/or other heuristics to play against your pede. (This is worth extra bonus points since it is a bit more challenging.)

  • 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.

Testing - with a note for Vista users...

Perhaps the simplest way to compile, run, and test this program is to use the command-line compiler and then the appletviewer program to test things. Windows Vista makes it hard to include the javac, java and appletviewer applications in your path -- but it is possible:
This URL: http://banagale.com/changing-your-system-path-in-windows-vista.htm offers step-by-step instructions for adding a new path to Vista's list of locations where it will search for executables. The path you will want to add to the end of the list is going to be a small variant on ;"C:\Program Files\Java\jdk1.6.0_06\bin" The semicolon is Windows's separator for items in a list of paths. The quotes may be optional - (they're optional in XP, at the very least).