CS 3230 - Lab 5

RobotPart interface

Specifications

Write an interface called RobotPart and three classes that implement it called Radar, Gun, and Tank.

All of these interfaces / classes will be written inside a Robot class, making them all inner classes.

The RobotPart Interface

Declare an interface called RobotPart. It should have two method stubs: init() and move().

The Radar Class

Write a class called Radar that implements the RobotPart interface. You will need to override both of the interface's methods.

Oscillating the radar: You may be wondering how to wobble the scanner outside of the onScannedRobot method. Here's how you can do it:

double turn = getHeading() - getRadarHeading() + enemy.getBearing();
turn += 30 * radarDirection;
setTurnRadarRight(normalizeBearing(turn));
radarDirection *= -1;
The radarDirection variable can be declared within the Radar class and initialized to 1. (Feel free to experiment with offset values other than 30.)

Additional convenience methods: As we discussed, you must override all the methods in interfaces that you implement, but you can certainly add additional methods if you want. In the test harness below I've added shouldScan() and wasTracking() methods.

The Gun Class

Next, write a class called Gun that also implements the RobotPart interface. As before, you will need to override both of the interface's methods.

The Tank Class

Lastly, write a class called Tank that also implements the RobotPart interface. If you haven't figured it out already, you will need to override both of the interface's methods in this class too.

Test Harness

To test the various parts you wrote, you can start with the following skeleton code:

public class PartsBot extends AdvancedRobot {

	private AdvancedEnemyBot enemy = new AdvancedEnemyBot();
	private Radar radar = new Radar();
	private Gun gun = new Gun();
	private Tank tank = new Tank();

	public void run() {

		RobotPart[] parts = new RobotPart[3];
		parts[0] = radar;
		parts[1] = gun;
		parts[2] = tank;

		// initialize each part
		for (int i = 0; i < parts.length; i++) {
			// behold, the magic of polymorphism
			parts[i].init();
		}

		// iterate through each part, moving them as we go
		for (int i = 0; true; i = (i + 1) % parts.length) {
			// polymorphism galore!
			parts[i].move();
			execute();
		}
	}

	public void onScannedRobot(ScannedRobotEvent e) {
		if (radar.shouldScan(e)) enemy.update(e, this);
	}

	public void onRobotDeath(RobotDeathEvent e) {
		if (radar.wasTracking(e)) enemy.reset();
	}   

	...

	// put normalizeBearing and absoluteBearing methods here

	...

	// declare RobotPart interface and classes that implement it here
	// They will be _inner_ classes.

}

I'll show you a demo that uses this test harness in class.

Note that you can use all the outer class' methods and variables inside the inner classes. Thus, you can make calls to setTurnRight() or setFire() without any qualifiers. You can also use the enemy variable in the inner classes as you normally would inside any of the outter class' methods.

Questions and Answers

Help! It won't compile!

The Lab 3 Q & A answers this.

How do I show you this lab working?

Using the above test harness, you can show me a robot zooming around the screen using all the parts you wrote.

What do you want me to turn in?

The PartsBot.java file with your name, the lab # and the course # at the top of the page in comments.

What's up with all those screwy .class files that were generated?

Glad you asked. This lab will illustrate how the Java compiler generates .class files for inner classes by concatenating the outer class name with the inner class name, putting a dollar sign ($) between them.

Will you pleeease show me the code for the shouldScan() and wasTracking() methods?

Oh, fine. Here:

boolean shouldScan(ScannedRobotEvent e) {
	// track if we have no enemy, the one we found is significantly
	// closer, or we scanned the one we've been tracking.
	return (enemy.none() || e.getDistance() < enemy.getDistance() - 70 ||
			e.getName().equals(enemy.getName()));
}

boolean wasTracking(RobotDeathEvent e) {
	return (e.getName().equals(enemy.getName()));
}