CS 305J Assignment 11, Critters, Implementing classes

Programming Assignment 11 This is an individual assignment. You must complete it on your own. You can talk with other members of the class, but you cannot look at another person's code, show your code to another person, or relate the details of how you wrote your program to anyone else.

Placed online: Wednesday, November 13
20 points, ~2% of total grade
Due: no later than 11 pm, Thursday, December 4. You may not use any slip days on assignment 11. If you do not turn in your assignment in the correct format by 11 pm Thursday, December 4, your assignment grade will be a 0.
General Assignment Requirements

Description The purposes of this assignment are:
  1. To practice implementing classes
  2. To practice implementing interfaces
  3. To learn how to work within a much larger program
  4. To have fun creating a competitive critter.

Thanks to Marty Stepp, Stuart Reges, and Steve Gribble for sharing this assignment with me.

Program Overview:

You will complete a set of classes that define the behavior of various animals or critters. You will be provided with several classes that implement a graphical simulation of a two dimensional world with many animals of different types moving around on it. Different kinds of animals move in different ways. As you implement the required classes you are defining those differences.

During each round of the simulation each critters is asked which direction it wants to move. A critter can move one square to the north, east, south, or west or the critter may choose to remain in its current location. The world the critters are moving around in is of finite size, but it is a torus, like a doughnut; if a critter goes off the right edge of the 2d grid they pop up on the left edge and vice versa. Likewise if a critter goes off the south edge of the 2d grid they pop up on the north edge and vice versa. The critter world is divided into cells that have integer coordinates like the 2d arrays we studied in class. The upper left cell has coordinates (0,0). x coordinates increase to the right and y coordinates increase as you go down. The default size of the world is 60 cells across and 50 cells high, although this could be altered.

Like the color histogram program you are not writing the main method, nor are you writing the code that controls the simulation. Your code will not be in control of the overall program execution. Also, you won't write the code that actually creates the various critter objects. Instead you are implementing a series of classes to specification ("to 'spec' ") and the existing code will use the classes you implement. The existing classes are clients of the classes you will be implementing. As we talked about in class this is how most programs are written. They are not written by a single person, rather by a team of people.

You may find yourself wanting to move your critter several spaces at once, but this is not possible. The only way a critter can move is if the simulator asks the critter to move and the critter simply responds with the direction it wants to move. The simulator will then move the critter one space in the appropriate direction. This is a good introduction to the kind of programming that is done with objects and if you move on to the follow class, CS307, you will be doing a lot of programming in this style. (If you want to move several spaces you will have to have your class remember what its next move should be so it can tell the simulator the next time it asks.)

As the simulation runs critters can collide with each other by moving into the same location. Again, the simulator takes care of all of this, not the critters. When two critters enter the same cell they fight to the death in a deadly game of rock-paper-scissors. The winning animal survives and the losing animal is removed from the simulation. (Again, most of this is handled by the simulation, not by the critters.) Critters simply pick a value for rock, paper, or scissors when the simulator asks them. The outcome of the rock paper scissors duels are:

      Critter #2  
    ROCK PAPER SCISSORS
  ROCK random winner #2 wins #1wins
Critter #1 PAPER #1 wins random winner #2 wins
  SCISSORS #2 wins #1 wins random winner

Provided files:

There are multiple support files you will have to download from the assignment web page.

The main method is in the CritterMain class. Run the main method in this class to run a simulation.

Each of the four classes you complete will implement the following provided Critter interface.

public interface Critter {
    // methods to be implemented
    public int fight(String opponent);
    public Color getColor();
    public int getMove(CritterInfo info);
    public String toString();

    // constants for directions
    public static final int NORTH = -2;
    public static final int SOUTH = 4;
    public static final int EAST = 3;
    public static final int WEST = 19;
    public static final int CENTER = 11;

    // constants for rock-paper-scissors game
    public static final int ROCK = 28;
    public static final int PAPER = -10;
    public static final int SCISSORS = 55;
}

Recall, as we discussed in class, that an interface is a plan, a blueprint. You can review chapter 9 of the book for more details. Recall each of your classes will have to include a clause in the class header to indicate they are implementing the Critter interface.

public class Bear implements Critter{ ...

You will have to provide a working version of the 4 methods specified in the Critter interface. The details of these are different for each critter. One critter class has already been completed, the Stone class. Stones are not very active critters. Stones are displayed with the letter S via the toString method, they are the color gray, they always stay at their current location and never try to move, and they play rock - paper - scissors by always picking rock. Here is the Stone class in its entirety. Notice Stone objects don't have any fields (a.k.a. instance variables), because they never do anything different.

import java.awt.Color;

public class Stone implements Critter {
    // the Stone class doesn't need any fields because Stone objects
    // always do the same thing

    public int fight(String opponent) {
        // good ol' rock... nothing beats that!
        return ROCK;
    }

    public Color getColor() {
        // gray
        return Color.GRAY;
    }

    public int getMove(CritterInfo info) {
        // does not move
        return CENTER;
    }

    public String toString() {
        // displays stone as S
        return "S";
    }
}

Notice the Critter interface defines five constants for the various directions and three more constants for the three choices in the rock - paper - scissors game. You can refer to these constant directly in your code (NORTH, SOUTH, ROCK, etc.) because you are implementing the interface. Alternatively you could refer to them via the interface name. (Critter.NORTH, Critter.PAPER, etc.)

Your code should not depend on the specific values assigned to these constants, although you may assume they will always be of type int. In other words a simulation may be run where Critter.NORTH is not equal to -2. A critter can stay in its current location by returning CENTER from its getMove method.

Critters to implement:

Here is where you actually get to write code! You will complete four critter classes. Each class must have only one constructor and that constructor must accept exactly the parameter(s) described below. For random moves each possible choice must be equally likely. You may either use an object of type Random  or the Math.random() method to obtain pseudorandom numbers.

Bear:

constructor public Bear()
fight behavior always scissors
color brown. To do this you will have to create a new Color object using a Color constructor. A decent brown is (red = 128, green = 128, blue = 64). For example, Color c = new Color(128, 128, 64);
movement behavior alternates between north and west in a zig-zag pattern. (first north, then west, then north, then west, ...)
toString B

Lion:

constructor public Lion(int steps)
fight behavior always paper
color yellow
movement behavior moves the given number of steps in a random direction (north, east, south, or west) then chooses a new random direction and repeats. Here is one of those times you will want to move many steps, but you can only move one. You will have to track how many steps you have taken in the current direction.
toString L

The Lion constructor accepts a parameter representing the distance or number of steps a particular Lion will walk in a straight line before choosing a new, random direction. For example, a Lion constructed with a parameter value of 8 will uses its first 8 moves to walk in a single random direction. Then after the 8th move the Lion will choose a new random direction (which could be the same as the original one, and repeat the process. Recall the whole purpose of fields in classes and objects is to remember things!

Tiger:

constructor public Tiger(Color c)
fight behavior alternate between scissors and paper. (first scissors, then paper, then scissors, then paper ... )
color the color passed to the constructor
movement behavior first 5 steps south, then 5 steps west, then 5 steps north, then 5 steps east. (a clockwise square pattern, one step at a time), then repeats
toString T

The Tiger constructor accepts a parameter representing the color in which that given Tiger should be drawn. Different Tigers could be different colors. This color should be returned each time the getColor method is called on a given Tiger. For example, a Tiger object constructed with a parameter value of Color.RED will return that color from its getColor method and will therefore appear red on the screen.

Wolf:

constructor public Wolf()
fight behavior you decide
color you decide
movement behavior you decide
toString you decide, but it must be a single character

You get to decide the behavior of the objects of type Wolf and thus how to implement the Wolf class. Your constructor in the Wolf class must accept no parameters as shown above.

More on the Wolf class:

Part of your grade on this assignment will be based on implementing creative and non-trivial behavior in your Wolf class. Here are some hints and ideas.

Each time a critter is asked to move its getMove method is called by the simulation. Look at the header of the getMove method from the Critter interface.

public int getMove(CritterInfo info);

The getMove method is passed an object of type CritterInfo that provides useful information about the area of the world the critter is in. None of the other critters (Stone, Bear, Lion, Tiger) use this information in any way, but your Wolf class can. You may wish to use the information in the CritterInfo object to guide a Wolf objects behavior. For example. you can find out the wolf's current x and y coordinates by calling the getX and getY methods, while the getWidth and getHeight methods return the size of the simulation world. You can find out what is around the wolf by calling the getNeighbor method and passing one of the direction constants as a parameter. The getNeighbor method returns the display character (as a String object) for whatever is in that location. A period, ".", indicates an empty cell. Here are the methods you may call on the CritterInfo object:

public interface CritterInfo {
    // Returns the height of the world.
    public int getHeight();

    // Takes a direction as a parameter (one of the constants NORTH,
    // SOUTH, EAST, WEST or CENTER from the Critter interface). It
    // returns the display character for the critter that is one unit away
    // in that direction (or "." if the square is empty).
    // If multiple critters occupy this space, returns a randomly chosen
    // one of them.
    public String getNeighbor(int direction);

    // Returns the width of the world.
    public int getWidth();

    // Returns a critter's current x-coordinate in the world.
    public int getX();

    // Returns a critter's current y-coordinate in the world.
    public int getY();
}

Also notice the fight method provides a String that is the display character for the other opponent in the fight. Again, none of the other critter classes use this information in any way, but your Wolf class can.. For example if the opponent equals "B" it is likely you are fighting a Bear (or some other, crafty wolf...)

Your Wolf can return any String of length 1 from its toString method. and any color you like from its getColor method. Critters are asked what display color and display String to use on each round of the simulation, so you can have a Wolf that displays itself differently over time. Keep in mind that the toString text is also passed to other animals when they fight your Wolf. You may wish to develop a strategy to fool other animals (not shown here or other wolves) in the simulation.

Implementation Guidelines:

Download all the required files and add them to DrJava folder. The provided GUI and simulation can run even if you haven't completed all of the required critter classes. To do this, edit the file CritterMain.java and comment out lines that refer to critter types that you have not completed. For example, commenting out the following line would prevent the simulation from trying to place any Tiger objects.

     model.add(NUM_START, Tiger.class);

I recommend commenting out all the critters in the main method of CritterMain except Stone and running the program to make sure you have downloaded all the file and have set them up correctly. Then implement the Critter classes one at a time, testing after each one is complete. I recommend going from Bear to Lion to Tiger to Wolf. A critter class will not compile without having implementations of all the methods from the Critter interface. It is a good idea to test each method after you write it before going on to the next method. You can do this by creating "stub" versions of the methods you are not done with. The stub method returns a place holder value until you replace it with the correct statements. For example, your could create a stub of  fight for the Tiger that always returns Scissors while working on the Tiger's getMove behavior. When the getMove behavior is done and tested go back to the fight method and implement it correctly for Tigers.

For each critter you implement it will be impossible to implement correctly if you do not have the necessary fields to track the state of the object. Before trying to write the code for each class figure out what fields will be necessary for that critter to achieve the desired behavior. Do this before you start typing code. (Don't fiddle! Think first!)

It is sometimes hard to tell from the simulation if a critter is behaving correctly, particular the fight behavior. You can test this by using println statements. For example in the Tiger class you could have a println showing what will be returned. You may want to alter the CritterMain class to add a single Tiger and look at its fight behavior via the println statements. Does it alternate between scissors and paper correctly?

Style Guidelines and grading:

Some of the points for this assignment will be awarded on the basis of how much energy and creativity you put into creating an interesting and effective Wolf class. Style points will also depend on the basis to simply and clearly implement each critter's required behavior.

Turn in your files named Bear.java, Lion.java, Tiger.java, and Wolf.java using the turnin program.

Files
File Responsibility
CritterMain.java. The class with the main method for the GUI and simulation. Provided by me. You can alter as you develop your classes, but the original version will be used to test your programs.
CritterModel.java, CritterGuijava, CritterPanel.java. Classes to run the simulation Provided by me. Do not change.
Critter.java. The interface for the Critter classes. Provided by me. Do not change.
CritterInfo.java. An interface for information about a critter's surroundings. You can call methods from this interface in your Wolf class's getMove method to try and improve your Wolf;s chances for survival. Provided by me. Do not change.
Stone.java. A simple critter. Provided by me. Do not change.
Bear.java, Lion.java, Tiger.java, Wolf.java. Critter classes you implement as described above. Provided by you.
A11.zip. All the required files in one zip file for easier downloading if you are familiar with the zip archive format. Provided by me.
Checklist Did you remember to:
  • review the general assignment requirements?
  • work on the assignment individually?
  • ensure your program creates implements the correct behavior for Bear, Lion, and Tiger?
  • Create a creative and effective Wolf class?
  • ensure you wrote the program using good programming style?
  • ensure your program does not suffer a compile error or runtime error?
  • turn in your Java source code in files named Bear.java, Lion.java, Tiger.java, and Wolf.java to the proper account in the Microlab via the turnin program before 11 pm, Thursday, December 4? You may not use any slip days on assignment 11. If you do not turn in your assignment in the correct format by 11 pm Thursday, December 4, your assignment grade will be a 0.

Back to the CS 305j homepage.