Marine Biology Simulation

In this project, you will extend implement a software package that simulates simple marine life forms (“fish”).  The program is a GUI application that displays a number of fish in an environment.  Both the behavior of the fish as well as that of the environment they live in can vary independently.  The user can write new fish species and new types of environments and plug them into the program at runtime.

The project is not really about simulating fish, though; instead, you will learn about bigger concepts in computing, such as

The entire program consists of well over 10,000 lines of code.  To get you acquainted with it, the assignment is divided into four parts.  It is highly advisable to attempt the parts in order.

For the first two parts, you will be given most of the program in compiled form contained in a jar file.  You can treat everything inside this jar as “black box”.  It just provides a framework for you to work with.  For now, you do not need to know how the internals of the program function.  You will first be asked to create a new species of fish (KnightFish) and then make a new type of environment (WrappingEnv).  The purpose is to demonstrate that the fish and the environment hierarchies can be extended independently from each other.  These two parts are due for Milestone 1.

In the last two parts, you will actually modify the internals of the system.  This is designed to help you understand how the fish and the environment communicate through the local environment.  To do so, you will be given the remaining portion of the source code once the deadline for Milestone 1 has passed.  Some of the source files contain only stub code.  In the third part, we ask you to re-implement the system to provide the same capabilities as in the demo.  To help you with this task, we have provided unit tests that serve as additional specification.  Finally, we require you to modify the fish to allow for dynamically changing behaviors.  This will entail replacing the inheritance-based design with composition.  All four parts are required for Milestone 2.


Milestone 1

You are given the following:

  1. The source code for the remaining files: RiceMBSmilestone1.jar. To extract the files, use the command
  1. The compiled framework is in this jar file: RiceMBSfw.jar. To compile your source code with this framework, add the following command line parameter to your javac command line

The RiceMSBfw.jar file is an executable jar file that can be run using ths command line:

·        java –jar RiceMBSfw.jar

NOTE: In DrJava, type the following in the “Interactions” pane:

·        java controller.MBSController

  1. The documentation for the entire framework.

As a starting point, please take a look at the provided demo that uses inheritance. To get the correct images for the fish, download these optional images and unzip them in the same directory as the jar file. If you are using DrJava, you will also need to copy the Drjava executable into the same directory and start it from there. You can execute the demo by double-clicking on the jar file or from the command line by typing

Part 1

Implement a new species of fish, the knight fish. This species is described by a class called KnightFish, to be placed in the model.fish package. To make the fish conform to the standards of the simulation package, it needs to extend AFish in the sysModel.fish package.

The knight fish has a very peculiar way to move that you will need to implement in the move() method: It moves very similar to the knight in the game of chess.

 

0

 

1

 

7

     

2

   

X

   

6

     

3

 

5

 

4

 

Figure 1: Destinations

Assume the fish is located where the ‘X’ is in Figure 1. The places labeled ‘0’ through ‘7’ are possible places the fish can go.

When the fish begins to move, it randomly chooses one of these places as destination.


       
 

B

C

 
 

A

   
 

X

   

Figure 2: Route

The knight fish will then turn in the right direction and attempt to move to that place by making moves forward. It will then either turn to its left or its right and make a third step forward, bringing the fish to the place where it wants to go.  In the diagram on the left, the fish (‘X’) will first move to ‘A’, then to ‘B’, and then to ‘C’ (see Figure 2).

There is a difference between the knight in chess and the behavior of the knight fish, however.  In chess, the knight can jump over other pieces. If any of the locations ‘A’ or ‘B’ were blocked, the knight could still go from ‘X’ to ‘C’. The knight fish cannot do this.

       
 

###

C

 
 

A

   
 

X

   

Figure 3: Blocked

If, at any time, the fish attempts to move forward and gets blocked, it just stops there, even though the destination has not been reached yet. In the diagram to the left, the location labeled ‘###’ is blocked. The fish tries to move from ‘X’ to ‘C’, but just stays at ‘A’ since the next step forward gets blocked (see Figure 3).

The fish will also need a constructor with one parameter, the fish’s color. Inside the constructor, you should call the superclass’s constructor and pass the fish color as well as a fish display. You may use any fish display you want.

For examples of how the fish’s movement behavior needs to be implemented and how the constructor looks like, please experiment with the existing fish species such as GenericFish and DarterFish.

Test the fish in different environments. The fish should work in all of them without knowing or checking what environment it lives in. You can load the fish dynamically by selecting “Add” in the drop-down box and specifying the fully qualified class name.

Part 2

Create a new type of environment, WrappingEnv.  This environment is similar to the existing environment type BoundedEnv in that it places fish on a square grid.  It is also of limited size, specified by a width and a height, just like BoundedEnv.

The difference, however, is that this environment allows fish to leave the environment on one edge and reenter it on the opposite edge. For instance, a fish that moves out of the environment on the left side will reenter on the right side.  (Aside: If you think about the topology of this environment, you will realize that it is actually toroidal, i.e. shaped like a donut.  You can go around and around in a big circle, but you can also go through the hole in the middle and come out on the outside again.)

Now consider these questions:

When creating your new environment type, please consider that the framework uses factory methods inside the environment to create instances of locations, directions, and local environments.  If you choose to extend one of these, keep in mind that you also have to write a new factory method.  If you don’t, you have created a new class with different behavior, but the framework will continue to create instances of the old class!

The new environment class must also provide two constructors, just like BoundedEnv (see documentation).  Both need to call the matching superclass constructors.

The last step to turn this into a working environment is to create an environment factory method makeEnvFactory() that returns an object extending AEnvFactory (in the sysModel.env package).  This class serves both as abstract factory and as options panel for your new type of environment.  The options panel gets displayed in the “Create new environment” dialog box beneath the drop-down box.  Once the user presses the “Create” button, the factory is used to make a new environment.

You can use the stub code below to get started:



/**
 * Get the environment factory.
 * @return environment factory
 */
public AEnvFactory makeEnvFactory() {
  return new AEnvFactory() {
    // TODO: Add Swing GUI components for options
    // static initializer block – works like a constructor
    {
        // AEnvFactory extends JPanel, so you can treat
        // “this” just like a JPanel
        // TODO: set layout manager
        // TODO: add GUI components
    }
    public AGlobalEnv create() {
      // TODO: make a new WrappingEnv using the values
      //       in the GUI components
      //       The command factory for the first parameter
      //       is in _cmdFactory, the security adapter for
      //       the second parameter in _securityAdapter
    };
    public String toString() {
      // TODO: return fully qualified class name, i.e.
      //       the class name with all the packages
    }
  };
}

Test the environment with the existing fish.  All of them should still work without knowing of the new environment you just wrote.  The project is flexible and extensible! You can add the environment at runtime by selecting “Add” in the “Create Environment” dialog’s drop-down box and specifying the fully qualified path name of the environment class.

Milestone 1 Checklist

The following is required for Milestone 1:

Submit your project using the turning script.  The assignment name is mbs1.


Milestone 2

You are given the following:

  1. The source code for the entire project: RiceMBSmilestone2.jar. Students who have been given an extension on milestone 1 may not look at milestone 2 until after they have turned in milestone 2. To extract the files, use the command

This jar file will also include sample implementations for KnightFish and WrappingEnv from Milestone 1.

NOTE: The jar file will not be released until the deadline for Milestone 1 has passed.

  1. The documentation for the entire framework.

As a starting point, please take a look at the provided demo that uses composition. To get the correct images for the fish, download these optional images and unzip them in the same directory as the jar file. If you are using DrJava, you will also need to copy the Drjava executable into the same directory and start it from there. You can execute the demo by double-clicking on the jar file or from the command line by typing

Part 3

For Milestone 2, you are given the entire framework as source code.  Some critical portions of the code that let the fish and the environment communicate have been removed, though, and only stub code is present for them.  You are asked to fill in the necessary code to make the simulation work just as in the demo.

To help you with this task, you are given a set of JUnit test cases.  These test cases serve as specification and help you find out where you need to add code and to a certain degree also what you will have to add.  You can run these test cases after you have made changes to verify your progress and eventually make sure the simulation has all the required capabilities.

Once all unit tests pass, the simulation should run exactly as before.

Part 4

Now that you have gained a basic understanding of how the current implementation of the simulation works, we ask you to improve it.

Currently, the behavior of a fish is determined at the time the fish is added to the simulation and then remains fixed. In fact, it cannot be changed in the middle of a fish’s lifetime, since varying movement behavior is accomplished using inheritance. In this scheme, a fish cannot simply “change class”.

Just like in previous projects, dynamic reclassification can be accomplished by using composition. In this particular case, the Strategy design pattern is applicable. The fish has a movement strategy, and when the fish’s move method is called, it merely delegates to that strategy. By providing getter and setter methods, you can change the strategy a fish uses and make it behave differently at runtime.

Your task in part 4 is to change the fish to use the Strategy design pattern for movement. This involves refactoring both the abstract AFish class and the concrete Fish subclasses, as well as creating a new class hierarchy for movement strategies.

Additionally, you should demonstrate the newly gained flexibility in the simulation: When the user right-clicks on a fish, the strategy of that fish should be changed to the strategy of the fish selected in the fish drop-down box. If, for example, you have “CircleFish” selected in the drop-down box, and you right-click on a fish with the “rock” behavior, that fish should start swimming in a circle now.

HINT: You are only given an interface called IFishFactory, so you can make a new fish with the behavior selected in the drop-down box.  Using getters and setters, how can you make the existing fish behave like it should?

NOTE: You will find that once you change the AFish class to use the strategy, you don’t really need the hierarchy of AFish subclasses anymore.  It is easier to keep them there nonetheless; otherwise, a few changes in the view and the factory system are required. The subclasses, however, are now reduced to simple specialization that merely bundle a fish display and a movement strategy together under a common name. The CircleFish class, for example, may look just like this:




/**
 * A fish that swims around in a circle.
 *
 * @author Mathias Ricken
 */
public class CircleFish extends Fish {
    /**
     * Create a new circle fish.
     *
     * @param fishColor color of the fish
     */
    public CircleFish(Color fishColor) {
        super(fishColor,
              CircleFishDisplay.Singleton,
              CircleBehavior.Singleton);
    }
}

 

Milestone 2 Checklist

The following is required for Milestone 2:

Submit your project using the turning script. The assignment name is mbs2.