PluggableRobot/Source
Jump to navigation
Jump to search
Below is the source for PluggableRobot. Pillage to your heart's content. PluggableRobot is released under the RoboWiki Limited Public Code License.
Contents
Component.java
/*
* PluggableRobot, by Robert J. Walker
* Home page: http://robowiki.net/cgi-bin/robowiki?PluggableRobot
* This software is made available under the RoboWiki Limited Public Code License (RWLPCL). The full
* text of the license may be found at http://robowiki.net/cgi-bin/robowiki?RWLPCL.
*/
package rjw.pluggablerobot;
/**
* Components encapsulate the main combat behavior of the robot into pluggable modules. Any code
* that actually sets an action for the robot (moving, turning, rotating the turret or radar, etc.)
* should be done in the go() method. Components should NEVER call any blocking methods;
* PluggableRobot will call execute() automatically when all components have had a chance to act.
* @author Robert J. Walker
*/
public interface Component {
/**
* Asks this Component to execute any actions that it wants to take this turn. PluggableRobot
* will call this method once per turn for each registered Component. Don't put any blocking
* calls in here; PluggableRobot will call execute() for you automatically after calling go() on
* each Component.
*/
public abstract void go();
}
EventListener.java
/*
* PluggableRobot, by Robert J. Walker
* Home page: http://robowiki.net/cgi-bin/robowiki?PluggableRobot
* This software is made available under the RoboWiki Limited Public Code License (RWLPCL). The full
* text of the license may be found at http://robowiki.net/cgi-bin/robowiki?RWLPCL.
*/
package rjw.pluggablerobot;
import robocode.*;
/**
* Event listener interfaces. Objects that wish to be notified of events must extend one of these
* subinterfaces.
* @author Robert J. Walker
*/
public interface EventListener {
public interface BulletHitBullet extends EventListener {
/**
* Called by PluggableRobot when a bullet fired by your robot has hit another bullet.
*/
public void notifyBulletHitBullet(BulletHitBulletEvent event);
}
public interface BulletHit extends EventListener {
/**
* Called by PluggableRobot when a bullet fired by your robot has hit another robot.
*/
public void notifyBulletHit(BulletHitEvent event);
}
public interface BulletMissed extends EventListener {
/**
* Called by PluggableRobot when a bullet fired by your robot has hit a wall.
*/
public void notifyBulletMissed(BulletMissedEvent event);
}
public interface Death extends EventListener {
/**
* Called by PluggableRobot when your robot has been destroyed.
*/
public void notifyDeath(DeathEvent event);
}
public interface HitByBullet extends EventListener {
/**
* Called by PluggableRobot when your robot has been hit by an enemy bullet.
*/
public void notifyHitByBullet(HitByBulletEvent event);
}
public interface HitRobot extends EventListener {
/**
* Called by PluggableRobot when your robot has collided with another robot.
*/
public void notifyHitRobot(HitRobotEvent event);
}
public interface HitWall extends EventListener {
/**
* Called by PluggableRobot when your robot has collided with a wall.
*/
public void notifyHitWall(HitWallEvent event);
}
public interface RobotDeath extends EventListener {
/**
* Called by PluggableRobot when an enemy robot has been destroyed.
*/
public void notifyRobotDeath(RobotDeathEvent event);
}
public interface ScannedRobot extends EventListener {
/**
* Called by PluggableRobot when your radar has swept over an enemy robot.
*/
public void notifyScannedRobot(ScannedRobotEvent event);
}
public interface SkippedTurn extends EventListener {
/**
* Called by PluggableRobot when your robot skipped a turn.
*/
public void notifySkippedTurn(SkippedTurnEvent event);
}
public interface Win extends EventListener {
/**
* Called by PluggableRobot when all robots besides yours have been destroyed.
*/
public void notifyWin(WinEvent event);
}
}
Hud.java
/*
* PluggableRobot, by Robert J. Walker
* Home page: http://robowiki.net/cgi-bin/robowiki?PluggableRobot
* This software is made available under the RoboWiki Limited Public Code License (RWLPCL). The full
* text of the license may be found at http://robowiki.net/cgi-bin/robowiki?RWLPCL.
*/
package rjw.pluggablerobot;
import java.awt.Graphics2D;
import java.awt.Paint;
import robocode.Robot;
/**
* Facilitates drawing graphics on the arena by automatically converting between values used in
* calculations to values used for drawing. The graphics context (Graphics2D) is injected into the
* Hud just before it is handed to Painters, then removed afterward.
* @author Robert J. Walker
*/
public class Hud {
/**
* Objects which implement this interface can be passed to PluggableRobot.registerPainter(), and
* will get their paint() methods called when it's time to draw the HUD.
*/
public interface Painter {
/**
* This method will be called by PluggableRobot when it's time for this object to draw.
*/
public void paint(Hud hud, long tick);
}
private Graphics2D _g;
public double _w;
public double _h;
/**
* Creates a new Hud object.
*/
public Hud(Robot bot) {
_w = bot.getBattleFieldWidth();
_h = bot.getBattleFieldHeight();
}
/**
* Draws a point at the given coordinates.
*/
public void drawPoint(double x, double y) {
int x0 = i(x);
int y0 = i(y);
_g.drawLine(x0, y0, x0, y0);
}
/**
* Draws a line between the two indicated points.
*/
public void drawLine(double x1, double y1, double x2, double y2) {
_g.drawLine(i(x1), i(y1), i(x2), i(y2));
}
/**
* Draws a circle with the given center point and radius.
*/
public void drawCircle(double x, double y, double r) {
int d = i(r * 2);
_g.drawOval(i(x - r), i(y - r), d, d);
}
public void drawArc(double x, double y, double r, double start, double extend) {
int d = i(r * 2);
_g.drawArc(i(x - r), i(y - r), d, d, i(Math2.radToDeg(start)), i(Math2.radToDeg(extend)));
}
/**
* Draws a rectangle with the given position and dimensions.
*/
public void drawRect(double x, double y, double w, double h) {
_g.drawRect(i(x), i(y), i(w), i(h));
}
/**
* Draws a filled rectangle with the given position and dimensions.
*/
public void drawFilledRect(double x, double y, double w, double h) {
_g.fillRect(i(x), i(y), i(w), i(h));
}
/**
* Draws a left-aligned String at the given position.
*/
public void drawString(String s, double x, double y) {
_g.drawString(s, i(x), i(y));
}
/**
* Draws a right-aligned String at the given position.
*/
public void drawStringRight(String s, double x, double y) {
_g.drawString(s, i(x) - _g.getFontMetrics().stringWidth(s), i(y));
}
/**
* Sets the Hud's current drawing paint.
*/
public void setPaint(Paint c) {
_g.setPaint(c);
}
/**
* Returns the width of the battlefield. This is useful in situations where you don't have
* access to the robot object.
*/
public double getWidth() {
return _w;
}
/**
* Returns the height of the battlefield. This is useful in situations where you don't have
* access to the robot object.
*/
public double getHeight() {
return _h;
}
/**
* Allows PluggableRobot to inject the graphics context into the Hud.
*/
public void setContext(Graphics2D g) {
_g = g;
}
/**
* Rounds the given double value to the nearest int.
*/
private int i(double val) {
return (int) Math.round(val);
}
}
ListenerDelegate.java
/*
* PluggableRobot, by Robert J. Walker
* Home page: http://robowiki.net/cgi-bin/robowiki?PluggableRobot
* This software is made available under the RoboWiki Limited Public Code License (RWLPCL). The full
* text of the license may be found at http://robowiki.net/cgi-bin/robowiki?RWLPCL.
*/
package rjw.pluggablerobot;
import java.util.*;
import robocode.*;
/**
* Class that manages all the event listeners for a PluggableRobot and delegates events to the
* appropriate EventListeners. Unlike the default Robocode behavior, events are doled out first by
* listener (first registered, first notified), then by the order of the listener interfaces
* declared on the listener implementation. So a class with a declaration like this:
* public class MyClass implements ScannedRobotListener, EventListener.Death
* ...will get notified of the ScannedRobotEvent *before* the DeathEvent!
* @author Robert J. Walker
*/
public class ListenerDelegate {
private ArrayList<EventListener> _listeners = new ArrayList<EventListener>();
private static HashMap<Class<? extends EventListener>, ListenerInvoker> _invokers;
// Build the invoker map, allowing us to look up invokers by listener class
static {
_invokers = new HashMap<Class<? extends EventListener>, ListenerInvoker>();
_invokers.put(EventListener.Death.class,
new ListenerInvoker<EventListener.Death, DeathEvent>() {
protected Class<DeathEvent> eventClass() { return DeathEvent.class; }
protected void invokeListener(EventListener.Death listener, DeathEvent event) {
listener.notifyDeath(event);
}
}
);
_invokers.put(EventListener.Win.class,
new ListenerInvoker<EventListener.Win, WinEvent>() {
protected Class<WinEvent> eventClass() { return WinEvent.class; }
protected void invokeListener(EventListener.Win listener, WinEvent event) {
listener.notifyWin(event);
}
}
);
_invokers.put(EventListener.SkippedTurn.class,
new ListenerInvoker<EventListener.SkippedTurn, SkippedTurnEvent>() {
protected Class<SkippedTurnEvent> eventClass() { return SkippedTurnEvent.class; }
protected void invokeListener(EventListener.SkippedTurn listener, SkippedTurnEvent event) {
listener.notifySkippedTurn(event);
}
}
);
_invokers.put(EventListener.ScannedRobot.class,
new ListenerInvoker<EventListener.ScannedRobot, ScannedRobotEvent>() {
protected Class<ScannedRobotEvent> eventClass() { return ScannedRobotEvent.class; }
protected void invokeListener(EventListener.ScannedRobot listener, ScannedRobotEvent event) {
listener.notifyScannedRobot(event);
}
}
);
_invokers.put(EventListener.HitByBullet.class,
new ListenerInvoker<EventListener.HitByBullet, HitByBulletEvent>() {
protected Class<HitByBulletEvent> eventClass() { return HitByBulletEvent.class; }
protected void invokeListener(EventListener.HitByBullet listener, HitByBulletEvent event) {
listener.notifyHitByBullet(event);
}
}
);
_invokers.put(EventListener.BulletHit.class,
new ListenerInvoker<EventListener.BulletHit, BulletHitEvent>() {
protected Class<BulletHitEvent> eventClass() { return BulletHitEvent.class; }
protected void invokeListener(EventListener.BulletHit listener, BulletHitEvent event) {
listener.notifyBulletHit(event);
}
}
);
_invokers.put(EventListener.BulletHitBullet.class,
new ListenerInvoker<EventListener.BulletHitBullet, BulletHitBulletEvent>() {
protected Class<BulletHitBulletEvent> eventClass() { return BulletHitBulletEvent.class; }
protected void invokeListener(EventListener.BulletHitBullet listener, BulletHitBulletEvent event) {
listener.notifyBulletHitBullet(event);
}
}
);
_invokers.put(EventListener.BulletMissed.class,
new ListenerInvoker<EventListener.BulletMissed, BulletMissedEvent>() {
protected Class<BulletMissedEvent> eventClass() { return BulletMissedEvent.class; }
protected void invokeListener(EventListener.BulletMissed listener, BulletMissedEvent event) {
listener.notifyBulletMissed(event);
}
}
);
_invokers.put(EventListener.HitRobot.class,
new ListenerInvoker<EventListener.HitRobot, HitRobotEvent>() {
protected Class<HitRobotEvent> eventClass() { return HitRobotEvent.class; }
protected void invokeListener(EventListener.HitRobot listener, HitRobotEvent event) {
listener.notifyHitRobot(event);
}
}
);
_invokers.put(EventListener.HitWall.class,
new ListenerInvoker<EventListener.HitWall, HitWallEvent>() {
protected Class<HitWallEvent> eventClass() { return HitWallEvent.class; }
protected void invokeListener(EventListener.HitWall listener, HitWallEvent event) {
listener.notifyHitWall(event);
}
}
);
_invokers.put(EventListener.RobotDeath.class,
new ListenerInvoker<EventListener.RobotDeath, RobotDeathEvent>() {
protected Class<RobotDeathEvent> eventClass() { return RobotDeathEvent.class; }
protected void invokeListener(EventListener.RobotDeath listener, RobotDeathEvent event) {
listener.notifyRobotDeath(event);
}
}
);
}
/**
* Register a new EventListener.
*/
public void register(EventListener listener) {
_listeners.add(listener);
}
/**
* Hand out event notifications to the EventListeners.
*/
public void processEvents(Vector<Event> events) {
// Notify listeners in the order they were registered
for(EventListener listener : _listeners) {
Class[] interfaces = listener.getClass().getInterfaces();
// Iterate the interfaces on each listener that descend from EventListener
for(Class iface : interfaces) {
if(!EventListener.class.isAssignableFrom(iface)) continue;
// Get the invoker and the corresponding event class for this interface
ListenerInvoker invoker = _invokers.get(iface);
Class<? extends Event> eventClass = invoker.eventClass();
// Iterate the events and hand the ones of the proper type to the invoker
for(Event event : events) {
if(!eventClass.isAssignableFrom(event.getClass())) continue;
invoker.invokeListener(listener, event);
}
}
}
}
/**
* An object that knows about a Robocode Event class and how to invoke its corresponding
* EventListener.
* @author Robert J. Walker
*/
private static abstract class ListenerInvoker<K extends EventListener, V extends Event> {
/**
* Returns the Robocode Event class handled by this ListenerInvoker.
*/
protected abstract Class<V> eventClass();
/**
* Invokes the given EventListener, passing in a Robocode Event object.
*/
protected abstract void invokeListener(K listener, V event);
}
}
Math2.java
/*
* PluggableRobot, by Robert J. Walker
* Home page: http://robowiki.net/cgi-bin/robowiki?PluggableRobot
* This software is made available under the RoboWiki Limited Public Code License (RWLPCL). The full
* text of the license may be found at http://robowiki.net/cgi-bin/robowiki?RWLPCL.
*/
package rjw.pluggablerobot;
import java.awt.geom.Point2D;
import java.util.Random;
import robocode.util.Utils;
/**
* Math utility class.
* @author Robert J. Walker
*/
public final class Math2 {
public static final double PI_OVER_2 = Math.PI / 2;
private static final Random random = new Random();
private Math2() {
}
/**
* Returns a random int between the min and max arguments, inclusive.
*/
public static int randomInteger(int min, int max) {
return random.nextInt(max - min + 1) + min;
}
/**
* Returns a random double value between 0.0 (inclusive) and 1.0 (exclusive).
*/
public static double randomDouble() {
return random.nextDouble();
}
/**
* If value is less than min, returns min. If value is greater than max, returns max. Otherwise,
* returns value.
*/
public static double limit(double min, double value, double max) {
return Math.max(min, Math.min(value, max));
}
/**
* Adds the X and Y components of the given Point2D.Double objects and returns a new
* Point2D.Double object with the result.
*/
public static Point2D.Double add(Point2D.Double point1, Point2D.Double point2) {
return new Point2D.Double(point1.x + point2.x, point1.y + point2.y);
}
/**
* Subtracts the X and Y components of the second given Point2D.Double object from those of the
* first and returns a new Point2D.Double object with the result.
*/
public static Point2D.Double subtract(Point2D.Double point1, Point2D.Double point2) {
return new Point2D.Double(point1.x - point2.x, point1.y - point2.y);
}
/**
* Returns the absolute bearing in radians from the given origin point to the given target
* point.
*/
public static double getAbsoluteTargetBearing(Point2D.Double origin, Point2D.Double target) {
return Utils.normalAbsoluteAngle(Math.atan2(target.x - origin.x, target.y - origin.y));
}
/**
* Returns a Point2D.Double object indicating the relative position of an object at the given
* angle and distance from the origin.
*/
public static Point2D.Double getRelativePosition(double angle, double distance) {
double dx = distance * Math.sin(angle);
double dy = distance * Math.cos(angle);
return new Point2D.Double(dx, dy);
}
/**
* Returns a Point2D.Double object indicating the position of an object at the given angle and
* distance from the given origin point.
*/
public static Point2D.Double getAbsolutePosition(Point2D.Double origin, double angle, double distance) {
double x = origin.x + distance * Math.sin(angle);
double y = origin.y + distance * Math.cos(angle);
return new Point2D.Double(x, y);
}
/**
* Converts degrees to radians.
*/
public static double degToRad(double degrees) {
return degrees * Math.PI / 180;
}
/**
* Converts radians to degrees.
*/
public static double radToDeg(double radians) {
return radians * 180 / Math.PI;
}
}
PluggableRobot.java
/*
* PluggableRobot, by Robert J. Walker
* Home page: http://robowiki.net/cgi-bin/robowiki?PluggableRobot
* This software is made available under the RoboWiki Limited Public Code License (RWLPCL). The full
* text of the license may be found at http://robowiki.net/cgi-bin/robowiki?RWLPCL.
*/
package rjw.pluggablerobot;
import java.awt.Graphics2D;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import robocode.*;
/**
* A pluggable listener and strategy architecture for a robot.
* http://robowiki.net/cgi-bin/robowiki?PluggableRobot
* @author Robert J. Walker
*/
public abstract class PluggableRobot extends AdvancedRobot {
private static boolean _battleInitialized = false;
private static Hud _hud;
private ListenerDelegate _listenerDelegate;
private ArrayList<Component> _components;
private ArrayList<Hud.Painter> _painters;
private Point2D.Double _center;
/**
* Sets up the ListenerDelegate and the Component and Painter lists.
*/
protected PluggableRobot() {
_listenerDelegate = new ListenerDelegate();
_components = new ArrayList<Component>();
_painters = new ArrayList<Hud.Painter>();
}
/**
* Set up the robot, then continuously collect events and invoke components.
*/
@Override
public final void run() {
// Initialize battle (at start of first round only)
if(!_battleInitialized) {
_hud = new Hud(this);
initializeBattle();
_battleInitialized = true;
}
// Register custom event test() hook for event manager
addCustomEvent(new Condition("eventManager") {
public boolean test() {
PluggableRobot.this.handleEvents();
return false;
}
});
// Round is starting
initializeRound();
// Main loop
while(true) {
for(Component component : _components) {
component.go();
}
execute();
}
}
/**
* This method will be called at the beginning of a battle. Robots can override this method to
* initialize their properties. This is a good place to initialize static properties or set your
* tank color.
*/
protected void initializeBattle() {
// Default implementation does nothing
}
/**
* This method will be called at the beginning of each round. Robots can override this method to
* initialize their properties. This is a good place to set up non-static properties and
* register listeners, painters and components.
*/
protected void initializeRound() {
// Default implementation does nothing
}
/**
* Called before events get processed each tick. The default implementation does nothing.
*/
public void onBeforeEventsProcessed() {
// Do nothing
}
/**
* Returns a Point2D.Double object representing the center of the battlefield.
*/
public Point2D.Double getCenter() {
if(_center == null) {
_center = new Point2D.Double(getBattleFieldWidth() / 2, getBattleFieldHeight() / 2);
}
return _center;
}
/**
* Registers the given EventListener, which will cause it to receive notifications of the events
* indicated by the listener interfaces it implements.
*/
protected void registerListener(EventListener listener) {
_listenerDelegate.register(listener);
}
/**
* Reigsters the given Component, which will give it the opportunity to act each turn.
*/
protected void registerComponent(Component component) {
_components.add(component);
}
/**
* Reigsters the given Painter, which will give it the opportunity to draw on the HUD each turn.
*/
protected void registerPainter(Hud.Painter painter) {
_painters.add(painter);
}
/**
* Hand out notifications to the Painters.
*/
@Override
public final void onPaint(Graphics2D g) {
_hud.setContext(g); // Inject the graphics context into the Hud
for(Hud.Painter painter : _painters) {
painter.paint(_hud, getTime());
}
_hud.setContext(null); // Clear the injected graphics context
}
/**
* Process all the events in the queue.
*/
private void handleEvents() {
onBeforeEventsProcessed();
_listenerDelegate.processEvents(getAllEvents());
clearAllEvents();
}
// Since we have our own event manager, we want to prevent overrides of the Robocode event
// methods, so we'll make them final.
@Override
public final void onCustomEvent(CustomEvent event) {
}
@Override
public final void onDeath(DeathEvent event) {
}
@Override
public final void onSkippedTurn(SkippedTurnEvent event) {
}
@Override
public final void onBulletHit(BulletHitEvent event) {
}
@Override
public final void onBulletHitBullet(BulletHitBulletEvent event) {
}
@Override
public final void onBulletMissed(BulletMissedEvent event) {
}
@Override
public final void onHitByBullet(HitByBulletEvent event) {
}
@Override
public final void onHitRobot(HitRobotEvent event) {
}
@Override
public final void onHitWall(HitWallEvent event) {
}
@Override
public final void onRobotDeath(RobotDeathEvent event) {
}
@Override
public final void onScannedRobot(ScannedRobotEvent event) {
}
@Override
public final void onWin(WinEvent event) {
}
}