COMP 310
Spring 2019

HW05: Command-dispatching Ballworld with Inter-ball Interactions

Home  Info  Canvas   Java Resources  Eclipse Resources  Piazza

Deprecated Web Page! This content has either been moved to Canvas or has been removed from the course. Please inform the staff right away about any links that led to this page.

Assignment Instructions 

To turn in assignment:  branch your HW04 to a new HW05 project in SVN.   Do NOT name your assignment anything other than "HW05"!   Points WILL be deducted for misnamed projects.

In this assignment, you will get collisions and inter-ball interactions working in your Ballworld system.    The interactions will be in response to some sort of criteria that determines whether or not the interaction will take place, for instance, a ball will only "kill" another ball if it overlaps (collides) with it.    You are free to design whatever kinds of interactions and criteria you choose and are encouraged to seek your own models, designs and implementations for ball-to-ball interaction.  You are NOT required to follow the design presented in class!   Creativity and innovation will be rewarded!

Since this is the last Ballworld-based project, at least for a while, one of the goals here is to neatly "wrap up" this project.  When you are finished, all the documentation should be in order, all the classes and interfaces should be in packages that make logical and architectural sense, etc.   A basic rule-of-thumb criteria would be to make this project ready to hand off to another developer who is not familiar with your work and all that they will get is what is contained in the project (this is a very realistic situation!).

See the demo of the command-dispatching Ballworld with inter-ball interactions

Requirements

  1. All classes should be in packages that correspond to the semantics of the classes.         (5 pts)
  2. Full documentation of all classes and interfaces, including all fields and methods.   Documentation must be generated in a "doc" folder in your project that holds the generated Javadocs.   See the instructions on how to create Javadocs in Eclipse.  (10 pts)
  3. The generic dispatcher must be used.  (5 pts)
  4. Add IUpdateStrategy initialization capability
  5. Add an elastic collision strategy.  Suggestion: Initially, to get collisions working, comment out the delegation to any post-collision behaviors.  Then, after you've gotten collisions working, add in the infrastructure for post collision behaviors. (10 pts)  Note that this is a separate requirement, in addition to requirement #6 below.
  6. Add at least 3 ball-to-ball interactions based on some sort of interaction criteria, where the architecture clearly separates the criteria and the interaction behaviors (e.g. should be dynamically combinable), i.e. not every pairs of balls will interact, with at least one each of the following:  (45 pts total)
    1. Interaction criteria is that the balls must have collided, i.e. are overlapping.
    2. Interaction critera is something other than having collided.
      The interactions that were covered in class and lab, i.e. Infect, Spawn and Kill, do NOT qualify as submissions and will not be counted as one of the 3 required interactions.   This includes pairing these interactions with non-collision-based interaction detections.
  7. All controls on the GUI must have tool tips.    Tool tips can be easily set in the properties of each component in WindowBuilder.   The user should be able to gather enough information  to use your program just from the tool tips. (5 pts)
  8. Discretionary points, including critiques of the designs used. ( 10 pts)
  9. UML diagrams that cover the entire ballworld system are required as usual.   Multiple diagrams that highlight specific portions of the system are HIGHLY RECOMMENDED -- overly large and complex diagrams will be penalized..  The following criteria must be met: 
  10. Creativity will be rewarded!   0-10 pts extra rewarded for creative/innovative solutions, design and capabilities of your program!

Development Advice

It is HIGHLY recommended that you do Steps 1-3 above FIRST and make sure that your code works before proceeding.   This will create a much better organization of your code and will help clarify what your system does to you, making the rest of the assignment much, much easier.   Fill in the missing parts of Steps 2 and 3 as you create the new classes and possibly packages in the remaining steps.

Start EARLY!!   This assignment is due in a week, so ask questions early--do NOT wait until the last minute.   If you encounter problems or if you have not followed the directions carefully in Step 1, it could take a significant amount of time with the staff's help to get your code back to working order, so get this done and out of the way so it won't derail you at the last moment.

 


On Switchers and Initializations....

There are some sticky issues regarding the initialization of the decoree strategy in the SwitcherStrategy.   These issues include, but are not limited to:  

  1.  The initialization of a strategy requires an input parameter of a host Ball, but there is no Ball available for such a parameter when the strategy switching occurs.

  2. The decoree strategy is a single strategy instance that is shared amongst many host Balls, so which Ball should be used for initialization?

  3. If the initialization of the decoree strategy mutates that strategy as per the properties of its host ball, since the strategy is shared by multiple balls, what should the net effect be on the decoree strategy?    

Possible solutions, none of which is 100% satisfactory, include  

Overall, the issue is wrapped up in notions of state in the strategy and the ability to share a stateful object amongst multiple hosts.    This is a non-trivial issue with non-trivial consequences and is certainly worth any the study by any student of OOP/D.  

However, in the interest of minimizing distractions for Comp310 students in completing this assignment, you will NOT be required to perform a re-initialization of the decoree strategy when doing a switch operation on a SwitcherStrategy.      

Do revisit the problem when you are more relaxed as it is a very serious issue that could potentially create serious consequences if ignored in a large system.  

 

Don't Use Static Fields (or Methods)!

In general, the only places you should ever be using a static field are:
  - Singleton objects
  - serialVersionUID values
  - Null Objects, including invariant error and similar objects

The only static method should be main().

A Common Scenario: Using static arrays of strategies

Here is a scenario that pops up in student code where a composite strategy is being defined:

public class MyCompositePaintStrategy extends MultiPaintStrategy {
 
    private statics APaintStrategy[] myPStrats = {new EllipsePaintStrategy(), new RectanglePaintStrategy()};
    
    public  MyCompositePaintStrategy() {
       super(new AffineTransform(), myPStrats);
    }
 
// etc …
}

where there is a composite strategy defined along these lines:

public class MultiPaintStrategy  extends APaintStrategy {
 
    public APaintStrategy[] pStrats;
 
    public MultiPaintStrategy(AffineTransform at, APaintStrategy[] pStrats) {
         super(at); 
         this.pStrats = pStrats;
    }
 
// etc …
}

 

There are two fixes to the above code, one fast and the other better.   Both involve getting rid of the static field in MyComposite:

Quick fix:   dynamically allocate the array without using a field or variable.

public class MyCompositePaintStrategy extends MultiPaintStrategy {
 
    public  MyCompositePaintStrategy() {
       super(new AffineTransform(), new APaintStrategy[]{new EllipsePaintStrategy(), new RectanglePaintStrategy()});
    }
 
…etc
}

 

Better fix:   Change MultiPaintStrategy to take a vararg

public class MultiPaintStrategy  extends APaintStrategy {
 
    public APaintStrategy[] _pStrats;
 
    public MultiPaintStrategy(AffineTransform at, APaintStrategy… pStrats) {
         super(at); 
         _pStrats = pStrats;
    }
 
// etc …
}

Notice that that the only change is to replace a “[]” with “” in the MultiPaintStrategy constructor's signature.  Nothing else changes because the type of pStrats was and still is APaintStrategy[].    See the discussion on vararg parameters at the bottom of Lec12.

The effect of this is to simplify MyCompositePaintStrategy considerably:

public class MyCompositePaintStrategy extends MultiPaintStrategy {
 
    public  MyCompositePaintStrategy() {
       super(new AffineTransform(), new EllipsePaintStrategy(), new RectanglePaintStrategy());
    }
 
//etc… 
}

 

Another Common Scenario: Using static arrays of choices

Sometimes students use a static field to hold the options for classes that randomly choose an image or the like, for example like such:

public class MyRandomImagePaintStrategy extends ImagePaintStrategy {

	private static String[] imageFiles = {"images/humbird_animate.gif","images/sheep_animate.gif"}; // array of file names.

	public BirdSheepImagePaintStrategy() {
		super(imageFiles [Randomizer.Singleton.randomInt(0, 2)], 0.5);
	}
}

One solution is to use Java's "ternary conditional operator" or simply, the "?" operator:

public class MyRandomImagePaintStrategy extends ImagePaintStrategy {

	public MyRandomImagePaintStrategy() {
		super( ((Math.random() < 0.5)?"images/humbird_animate.gif" : "images/sheep_animate.gif") , 0.5);
	}
}

For the more general case, where more than 2 choices are desired, use a dynamically created array as was done above and pick a random element from it:

public class MyRandomImagePaintStrategy extends ImagePaintStrategy {

	public MyRandomImagePaintStrategy() {
		super( (new String[]{"images/humbird_animate.gif", "images/sheep_animate.gif", "images/Mario_animate.gif", "images/Sonic_animate.gif"})[Randomizer.Singleton.randomInt(0, 4)], 0.5);
	}
}

An even better solution is to recognize the process of randomly choosing a filename has nothing to do with paint strategies and thus define a new method of IRandomizer and Randomizer to randomly pick an element from a vararg input list:

public interface IRandomizer {
	// other methods elided
	
	/**
	 * Return one of the vararg input parameters with equal probability.
	 * The input parameters must all be of the same type and the return type 
	 * will match that type.
	 * @param  The type of the input parameters and thus the return type
	 * @param choices vararg list of choices 
	 * @return One of the input parameters
	 */
	public abstract <T> T randomChoiceList(@SuppressWarnings("unchecked") T... choices );   // Suppress the warning about a generic vararg
}

where Randomizer implements the method as such:

public class Randomizer implements IRandomizer {

	// other methods elided
	
	/**
	 * Return one of the vararg input parameters with equal probability.
	 * The input parameters must all be of the same type and the return type 
	 * will match that type.
	 * @param  The type of the input parameters and thus the return type
	 * @param choices vararg list of choices 
	 * @return One of the input parameters
	 */
	@Override
	public  T randomChoiceList(@SuppressWarnings("unchecked") T... choices) {    // Suppress the warning about a generic vararg
		return choices[randomInt(0, choices.length-1)];
	}
}

The constructor for the MyRandomPaintStrategy paint strategy is now very clear and clean:

public class MyRandomPaintStrategy extends ImagePaintStrategy {

	public MyRandomImagePaintStrategy() {
		super( Randomizer.Singleton.randomChoiceList("images/humbird_animate.gif", "images/sheep_animate.gif", "images/Mario_animate.gif", "images/Sonic_animate.gif"), 0.5);
	}
}

 

 


© 2019 by Stephen Wong