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
Canvas.java
<nowiki>
/*
* PluggableRobot, by Robert J. Walker
* Home page: http://robowiki.net/w/index.php?title=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/w/index.php?title=RWLPCL
*/
package rjw.pluggablerobot;
import java.awt.*;
import java.awt.geom.Point2D;
import robocode.AdvancedRobot;
/**
* A convenience wrapper around Graphics2D which provides the following
* features:
*
* - Accepts doubles for many arguments which are ints in Graphics2D
* - getCenter(), getHeight() and getWidth()
* - drawCircle(), fillCircle()
*
* @author Robert J. Walker
*/
public class Canvas {
private Graphics2D _g;
private double _width;
private double _height;
private Point2D.Double _center;
Canvas(AdvancedRobot bot) {
_g = bot.getGraphics();
_width = bot.getBattleFieldWidth();
_height = bot.getBattleFieldHeight();
_center = new Point2D.Double(_width / 2, _height / 2);
}
/**
* @see java awt.Graphics2D.clearRect(int, int, int, int)
*/
public void clearRect(double x, double y, double width, double height) {
_g.clearRect(i(x), i(y), i(width), i(height));
}
/**
* @see java awt.Graphics2D.clip(java.awt.Shape)
*/
public void clip(Shape shape) {
_g.clip(shape);
}
/**
* @see java awt.Graphics2D.clipRect(int, int, int, int)
*/
public void clipRect(double x, double y, double width, double height) {
_g.clipRect(i(x), i(y), i(width), i(height));
}
/**
* @see java awt.Graphics2D.copyArea(int, int, int, int, int, int)
*/
public void copyArea(double x, double y, double width, double height,
double dx, double dy) {
_g.copyArea(i(x), i(y), i(width), i(height), i(dx), i(dy));
}
/**
* @see java awt.Graphics2D.draw(java.awt.Shape)
*/
public void draw(Shape shape) {
_g.draw(shape);
}
/**
* @see java awt.Graphics2D.drawArc(int, int, int, int, int, int)
*/
public void drawArc(double x, double y, double width, double height,
double startAngle, double arcAngle) {
_g.drawArc(i(x), i(y), i(width), i(height), i(startAngle), i(arcAngle));
}
/**
* Convenience method for drawing a circle, given the center coordinates 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);
}
/**
* @see java awt.Graphics2D.drawLine(int, int, int, int)
*/
public void drawLine(double x1, double y1, double x2, double y2) {
_g.drawLine(i(x1), i(y1), i(x2), i(y2));
}
/**
* @see java awt.Graphics2D.drawOval(int, int, int, int)
*/
public void drawOval(double x, double y, double width, double height) {
_g.drawOval(i(x), i(y), i(width), i(height));
}
/**
* @see java awt.Graphics2D.drawRect(int, int, int, int)
*/
public void drawRect(double x, double y, double width, double height) {
_g.drawRect(i(x), i(y), i(width), i(height));
}
/**
* @see java awt.Graphics2D.drawRoundRect(int, int, int, int, int, int)
*/
public void drawRoundRect(double x, double y, double width, double height,
double arcWidth, double arcHeight) {
_g.drawRoundRect(i(x), i(y), i(width), i(height), i(arcWidth),
i(arcHeight));
}
/**
* @see java awt.Graphics2D.drawString(String, float, float)
*/
public void drawString(String str, double x, double y) {
_g.drawString(str, (float) x, (float) y);
}
/**
* @see java awt.Graphics2D.fill(java.awt.Shape)
*/
public void fill(Shape shape) {
_g.fill(shape);
}
/**
* @see java awt.Graphics2D.fillArc(int, int, int, int, int, int)
*/
public void fillArc(double x, double y, double width, double height,
double startAngle, double arcAngle) {
_g.fillArc(i(x), i(y), i(width), i(height), i(startAngle), i(arcAngle));
}
/**
* Convenience method for filling a circle, given the center coordinates and
* radius.
*/
public void fillCircle(double x, double y, double r) {
int d = i(r * 2);
_g.fillOval(i(x - r), i(y - r), d, d);
}
/**
* @see java awt.Graphics2D.fillOval(int, int, int, int)
*/
public void fillOval(double x, double y, double width, double height) {
_g.fillOval(i(x), i(y), i(width), i(height));
}
/**
* @see java awt.Graphics2D.fillRect(int, int, int, int)
*/
public void fillRect(double x, double y, double width, double height) {
_g.fillRect(i(x), i(y), i(width), i(height));
}
/**
* @see java awt.Graphics2D.fillRoundRect(int, int, int, int, int, int)
*/
public void fillRoundRect(double x, double y, double width, double height,
double arcWidth, double arcHeight) {
_g.fillRoundRect(i(x), i(y), i(width), i(height), i(arcWidth),
i(arcHeight));
}
/**
* @see java awt.Graphics2D.getBackground()
*/
public Color getBackground() {
return _g.getBackground();
}
/**
* Returns a Point2D located at the center of the canvas.
*/
public Point2D.Double getCenter() {
return _center;
}
/**
* @see java awt.Graphics2D.getClip()
*/
public Shape getClip() {
return _g.getClip();
}
/**
* @see java awt.Graphics2D.getClipBounds()
*/
public Rectangle getClipBounds() {
return _g.getClipBounds();
}
/**
* @see java awt.Graphics2D.getClipBounds(java.awt.Rectangle)
*/
public Rectangle getClipBounds(Rectangle r) {
return _g.getClipBounds(r);
}
/**
* @see java awt.Graphics2D.getColor()
*/
public Color getColor() {
return _g.getColor();
}
/**
* @see java awt.Graphics2D.getDeviceConfiguration()
*/
public GraphicsConfiguration getDeviceConfiguration() {
return _g.getDeviceConfiguration();
}
/**
* Returns a reference to the actual Graphics2D object wrapped by the
* Canvas.
*/
public Graphics2D getGraphics() {
return _g;
}
/**
* Returns the canvas's height.
*/
public double getHeight() {
return _height;
}
/**
* @see java awt.Graphics2D.getPaint()
*/
public Paint getPaint() {
return _g.getPaint();
}
/**
* @see java awt.Graphics2D.getStroke()
*/
public Stroke getStroke() {
return _g.getStroke();
}
/**
* Returns the canvas's width.
*/
public double getWidth() {
return _width;
}
/**
* @see java awt.Graphics2D.hit(java.awt.Rectangle, java.awt.Shape, boolean)
*/
public boolean hit(Rectangle rect, Shape s, boolean onStroke) {
return _g.hit(rect, s, onStroke);
}
/**
* @see java awt.Graphics2D.hitClip(int, int, int, int)
*/
public boolean hitClip(double x, double y, double width, double height) {
return _g.hitClip(i(x), i(y), i(width), i(height));
}
/**
* @see java awt.Graphics2D.setBackground(java.awt.Color)
*/
public void setBackground(Color color) {
_g.setBackground(color);
}
/**
* @see java awt.Graphics2D.setClip(int, int, int, int)
*/
public void setClip(double x, double y, double width, double height) {
_g.setClip(i(x), i(y), i(width), i(height));
}
/**
* @see java awt.Graphics2D.setClip(java.awt.Shape)
*/
public void setClip(Shape clip) {
_g.setClip(clip);
}
/**
* @see java awt.Graphics2D.setColor(java.awt.Color)
*/
public void setColor(Color c) {
_g.setColor(c);
}
/**
* @see java awt.Graphics2D.setPaint(java.awt.Paint)
*/
public void setPaint(Paint paint) {
_g.setPaint(paint);
}
/**
* @see java awt.Graphics2D.setStroke(java.awt.Stroke)
*/
public void setStroke(Stroke stroke) {
_g.setStroke(stroke);
}
/**
* Rounds a double to the nearest integer and returns it as an int.
*/
private static int i(double d) {
return (int) Math.round(d);
}
}
</nowiki>
Component.java
<nowiki>
/*
* PluggableRobot, by Robert J. Walker
* Home page: http://robowiki.net/w/index.php?title=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/w/index.php?title=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();
}
</nowiki>
EventListener.java
<nowiki>
/*
* PluggableRobot, by Robert J. Walker
* Home page: http://robowiki.net/w/index.php?title=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/w/index.php?title=RWLPCL
*/
package rjw.pluggablerobot;
import robocode.*;
/**
* Event listener interfaces. Objects that wish to be notified of events must
* extend one or more of these subinterfaces and register themselves with
* PluggableRobot at the start of the round via the registerListener() method.
* @author Robert J. Walker
*/
public interface EventListener {
public interface BattleEnded extends EventListener {
/**
* Called by the ListenerDelegate when the battle ends.
*/
public void notifyBattleEnded(BattleEndedEvent event);
}
public interface BulletHitBullet extends EventListener {
/**
* Called by the ListenerDelegate when a bullet fired by your robot has
* hit another bullet.
*/
public void notifyBulletHitBullet(BulletHitBulletEvent event);
}
public interface BulletHit extends EventListener {
/**
* Called by the ListenerDelegate when a bullet fired by your robot has
* hit another robot.
*/
public void notifyBulletHit(BulletHitEvent event);
}
public interface BulletMissed extends EventListener {
/**
* Called by the ListenerDelegate when a bullet fired by your robot has
* hit a wall.
*/
public void notifyBulletMissed(BulletMissedEvent event);
}
public interface Death extends EventListener {
/**
* Called by the ListenerDelegate when your robot has been destroyed.
*/
public void notifyDeath(DeathEvent event);
}
public interface HitByBullet extends EventListener {
/**
* Called by the ListenerDelegate when your robot has been hit by an
* enemy bullet.
*/
public void notifyHitByBullet(HitByBulletEvent event);
}
public interface HitRobot extends EventListener {
/**
* Called by the ListenerDelegate when your robot has collided with
* another robot.
*/
public void notifyHitRobot(HitRobotEvent event);
}
public interface HitWall extends EventListener {
/**
* Called by the ListenerDelegate when your robot has collided with a
* wall.
*/
public void notifyHitWall(HitWallEvent event);
}
public interface RobotDeath extends EventListener {
/**
* Called by the ListenerDelegate when an enemy robot has been
* destroyed.
*/
public void notifyRobotDeath(RobotDeathEvent event);
}
public interface ScannedRobot extends EventListener {
/**
* Called by the ListenerDelegate when your radar has swept over an
* enemy robot.
*/
public void notifyScannedRobot(ScannedRobotEvent event);
}
public interface SkippedTurn extends EventListener {
/**
* Called by the ListenerDelegate when your robot has skipped a turn.
*/
public void notifySkippedTurn(SkippedTurnEvent event);
}
public interface Status extends EventListener {
/**
* Called by the ListenerDelegate every turn with a robot status update.
*/
public void notifyStatus(StatusEvent event);
}
public interface Win extends EventListener {
/**
* Called by the ListenerDelegate when all robots besides yours have
* been destroyed.
*/
public void notifyWin(WinEvent event);
}
// Internal event listeners
/**
* An EventListener used only by the Hud to inform it of KeyPressedEvents
* so that it handle requests to toggle layers.
*/
interface _KeyPressed extends EventListener {
/**
* Notifies the Hud that a key was pressed.
*/
public void notifyKeyPressed(KeyPressedEvent event);
}
/**
* An EventListener used only by the ListenerDelegate to inform it of
* PaintEvents. The ListenerDelegate registers with itself as being
* interested in this event. This is the connection point for
* PluggableRobot's debug graphics harness.
*/
interface _Paint extends EventListener {
/**
* Notifies the ListenerDelegate that a PaintEvent has been received.
*/
public void notifyPaint(PaintEvent event);
}
}
</nowiki>
Hud.java
<nowiki>
/*
* PluggableRobot, by Robert J. Walker
* Home page: http://robowiki.net/w/index.php?title=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/w/index.php?title=RWLPCL
*/
package rjw.pluggablerobot;
import java.util.ArrayList;
import rjw.pluggablerobot.EventListener._KeyPressed;
import robocode.AdvancedRobot;
import robocode.KeyPressedEvent;
/**
* The Hud is responsible for drawing debug graphics. The Hud has multiple
* layers, each of which can be enabled or disabled independently through a key
* binding. Any object which is interested in contributing to the Hud must
* register itself with PluggableRobot, declaring which layer it wishes to paint
* on. Layers are painted in the order in which they were declared, and
* individual painters are invoked in the order that they were registered for
* that layer.
*
* Concept based on previous work by Nfwu and David Alves:
* http://robowiki.net/w/index.php?title=User:Nfwu/Painter
*
* @author Robert J. Walker
*/
public class Hud implements _KeyPressed {
private Canvas _canvas;
private ArrayList<Layer> _layers = new ArrayList<Layer>();
public Hud(AdvancedRobot bot) {
_canvas = new Canvas(bot);
}
/**
* Constructs a new Layer with the given name and bound to the indicated
* key. The enabled argument determines whether or not the layer should
* be on or off by default.
*/
public void createLayer(int key, String name, boolean enabled) {
Layer layer = new Layer(key, name, enabled);
_layers.add(layer);
}
/**
* Registers a painter with the layer bound to the given key.
*/
public void registerPainter(int key, Painter painter) {
for (Layer layer : _layers) {
if (layer.getKey() == key) {
layer.addPainter(painter);
return;
}
}
throw new IllegalArgumentException("No layer bound to that key!");
}
/**
* Notifes the Hud that a key was pressed, and toggles the corresponding
* layer, if it exists.
*/
@Override
public void notifyKeyPressed(KeyPressedEvent event) {
Layer layer = getLayer(event.getSourceEvent().getKeyCode());
if (layer != null) {
layer.toggle();
}
}
/**
* Called by PluggableRobot when it's time to paint the Hud.
*/
void paint(long tick) {
for (Layer layer : _layers) {
layer.paint(_canvas, tick);
}
}
/**
* Returns the layer bound to the given key.
*/
private Layer getLayer(int key) {
for (Layer layer : _layers) {
if (layer.getKey() == key) {
return layer;
}
}
return null;
}
/**
* Objects which implement the Painter interface and are registered
* PluggableRobot will get their paint() methods called when it is time for
* them to paint. Note that any one object that implements Painter may only
* paint on one layer of the Hud.
*/
public interface Painter {
/**
* Notifies the Painter that it's time to paint, and provides it with a
* Canvas object to paint with.
*/
public void paint(Canvas canvas, long tick);
}
/**
* A single Hud layer, responsible for painting itself by calling the
* Painters that which to paint on it.
*/
private static class Layer {
private int _key;
private String _name;
private boolean _enabled;
private ArrayList<Painter> _painters = new ArrayList<Painter>();
/**
* Constructs a new Layer with the given name and bound to the indicated
* key. The enabled argument determines whether or not the layer should
* be on or off by default.
*/
Layer(int key, String name, boolean enabled) {
_key = key;
_name = name;
_enabled = enabled;
}
/**
* Returns the key to which this Layer is bound.
*/
int getKey() {
return _key;
}
/**
* Returns this Layer's name.
*/
String getName() {
return _name;
}
/**
* Adds a new Painter to this Layer.
*/
void addPainter(Painter painter) {
_painters.add(painter);
}
/**
* Returns whether or not this Layer is enabled.
*/
boolean isEnabled() {
return _enabled;
}
/**
* Toggles this Layer between being enabled and disabled.
*/
void toggle() {
_enabled = !_enabled;
}
/**
* Notifies the Painter that it's time to paint, and provides it with a
* Canvas object to paint with.
*/
void paint(Canvas canvas, long tick) {
if (!_enabled) {
return;
}
for (Painter painter : _painters) {
painter.paint(canvas, tick);
}
}
}
}
</nowiki>
ListenerDelegate.java
<nowiki>
/*
* PluggableRobot, by Robert J. Walker
* Home page: http://robowiki.net/w/index.php?title=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/w/index.php?title=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. This allows each component to get notified of events
* in any order it likes, regardless of event priorities or the order used by
* other components.
*
* PaintEvents are handled differently; they are captured and held until all
* EventListeners have been notified and Components have acted, so that as much
* information as possible is available for debug painting.
*
* @author Robert J. Walker
*/
public class ListenerDelegate implements EventListener._Paint {
private static HashMap<Class, Invoker> _invokers;
// Build the invoker map, so we can look up invokers by listener class
static {
_invokers = new HashMap<Class, Invoker>();
// interal paint event listener
_invokers.put(_Paint.class, new Invoker() {
protected boolean consumesEvent(Event event) {
return event instanceof PaintEvent;
}
protected void invoke(EventListener listener, Event event) {
((_Paint) listener).notifyPaint((PaintEvent) event);
}
});
// interal key pressed event listener
_invokers.put(_KeyPressed.class, new Invoker() {
protected boolean consumesEvent(Event event) {
return event instanceof KeyPressedEvent;
}
protected void invoke(EventListener listener, Event event) {
((_KeyPressed) listener).notifyKeyPressed(
(KeyPressedEvent) event
);
}
});
// battle ended
_invokers.put(EventListener.BattleEnded.class, new Invoker() {
protected boolean consumesEvent(Event event) {
return event instanceof BattleEndedEvent;
}
protected void invoke(EventListener listener, Event event) {
((EventListener.BattleEnded) listener).notifyBattleEnded(
(BattleEndedEvent) event
);
}
});
// bullet hit
_invokers.put(EventListener.BulletHit.class, new Invoker() {
protected boolean consumesEvent(Event event) {
return event instanceof BulletHitEvent;
}
protected void invoke(EventListener listener, Event event) {
((EventListener.BulletHit) listener).notifyBulletHit(
(BulletHitEvent) event
);
}
});
// bullet hit bullet
_invokers.put(EventListener.BulletHitBullet.class, new Invoker() {
protected boolean consumesEvent(Event event) {
return event instanceof BulletHitBulletEvent;
}
protected void invoke(EventListener listener, Event event) {
((EventListener.BulletHitBullet) listener)
.notifyBulletHitBullet((BulletHitBulletEvent) event);
}
});
// bullet missed
_invokers.put(EventListener.BulletMissed.class, new Invoker() {
protected boolean consumesEvent(Event event) {
return event instanceof BulletMissedEvent;
}
protected void invoke(EventListener listener, Event event) {
((EventListener.BulletMissed) listener).notifyBulletMissed(
(BulletMissedEvent) event
);
}
});
// death
_invokers.put(EventListener.Death.class, new Invoker() {
protected boolean consumesEvent(Event event) {
return event instanceof DeathEvent;
}
protected void invoke(EventListener listener, Event event) {
((EventListener.Death) listener).notifyDeath(
(DeathEvent) event
);
}
});
// hit by bullet
_invokers.put(EventListener.HitByBullet.class, new Invoker() {
protected boolean consumesEvent(Event event) {
return event instanceof HitByBulletEvent;
}
protected void invoke(EventListener listener, Event event) {
((EventListener.HitByBullet) listener).notifyHitByBullet(
(HitByBulletEvent) event
);
}
});
// hit robot
_invokers.put(EventListener.HitRobot.class, new Invoker() {
protected boolean consumesEvent(Event event) {
return event instanceof HitRobotEvent;
}
protected void invoke(EventListener listener, Event event) {
((EventListener.HitRobot) listener).notifyHitRobot(
(HitRobotEvent) event
);
}
});
// hit wall
_invokers.put(EventListener.HitWall.class, new Invoker() {
protected boolean consumesEvent(Event event) {
return event instanceof HitWallEvent;
}
protected void invoke(EventListener listener, Event event) {
((EventListener.HitWall) listener).notifyHitWall(
(HitWallEvent) event
);
}
});
// robot death
_invokers.put(EventListener.RobotDeath.class, new Invoker() {
protected boolean consumesEvent(Event event) {
return event instanceof RobotDeathEvent;
}
protected void invoke(EventListener listener, Event event) {
((EventListener.RobotDeath) listener).notifyRobotDeath(
(RobotDeathEvent) event
);
}
});
// scanned robot
_invokers.put(EventListener.ScannedRobot.class, new Invoker() {
protected boolean consumesEvent(Event event) {
return event instanceof ScannedRobotEvent;
}
protected void invoke(EventListener listener, Event event) {
((EventListener.ScannedRobot) listener).notifyScannedRobot(
(ScannedRobotEvent) event
);
}
});
// skipped turn
_invokers.put(EventListener.SkippedTurn.class, new Invoker() {
protected boolean consumesEvent(Event event) {
return event instanceof SkippedTurnEvent;
}
protected void invoke(EventListener listener, Event event) {
((EventListener.SkippedTurn) listener).notifySkippedTurn(
(SkippedTurnEvent) event
);
}
});
// status
_invokers.put(EventListener.Status.class, new Invoker() {
protected boolean consumesEvent(Event event) {
return event instanceof StatusEvent;
}
protected void invoke(EventListener listener, Event event) {
((EventListener.Status) listener).notifyStatus(
(StatusEvent) event
);
}
});
// win
_invokers.put(EventListener.Win.class, new Invoker() {
protected boolean consumesEvent(Event event) {
return event instanceof WinEvent;
}
protected void invoke(EventListener listener, Event event) {
((EventListener.Win) listener).notifyWin((WinEvent) event);
}
});
}
private ArrayList<EventListener> _listeners =
new ArrayList<EventListener>();
private PaintEvent _lastPaintEvent = null;
public ListenerDelegate() {
register(this); // register itself for the PaintEvent
}
/**
* Register a new EventListener.
*/
public void register(EventListener listener) {
_listeners.add(listener);
}
/**
* Hand out event notifications to the EventListeners.
*/
public void processEvents(List<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
for (Class iface : interfaces) {
// Skip if interface does not descend from EventListener
if (!EventListener.class.isAssignableFrom(iface)) {
continue;
}
// Get the invoker for this interface
Invoker invoker = _invokers.get(iface);
// Find the events this invoker consumes
for (Event event : events) {
// Skip if listener isn't interested in this kind of event
if (!invoker.consumesEvent(event)) {
continue;
}
// Notify the listener
invoker.invoke(listener, event);
}
}
}
}
/**
* Called by a special internal EventListener to handle PaintEvents.
*/
@Override
public void notifyPaint(PaintEvent event) {
_lastPaintEvent = event;
}
/**
* Returns the most recently received PaintEvent, or null if no PaintEvent
* has been received.
*/
public PaintEvent getLastPaintEvent() {
return _lastPaintEvent;
}
/**
* An object that knows about a Robocode Event class and how to invoke its
* corresponding EventListener.
*/
private static abstract class Invoker {
protected abstract boolean consumesEvent(Event event);
/**
* Invokes the given EventListener, passing in a Robocode Event object.
*/
protected abstract void invoke(EventListener listener, Event event);
}
}
</nowiki>
Math2.java
<nowiki>
/*
* PluggableRobot, by Robert J. Walker
* Home page: http://robowiki.net/w/index.php?title=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/w/index.php?title=RWLPCL
*/
package rjw.pluggablerobot;
import java.awt.geom.Point2D;
import java.util.Random;
import robocode.util.Utils;
/**
* Math utility class. Note that trig functions are reversed in order to provide
* correct results for the Robocode coordinate system.
*
* @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;
}
/**
* 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 (in radians) 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 (in radians) 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 Math.toRadians(degrees);
}
/**
* Converts radians to degrees.
*/
public static double radToDeg(double radians) {
return Math.toDegrees(radians);
}
}
</nowiki>
PluggableRobot.java
<nowiki>
/*
* PluggableRobot, by Robert J. Walker
* Home page: http://robowiki.net/w/index.php?title=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/w/index.php?title=RWLPCL
*/
package rjw.pluggablerobot;
import java.awt.Graphics2D;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseWheelEvent;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import rjw.pluggablerobot.Hud.Painter;
import robocode.*;
/**
* An abstract robot class that provides a pluggable architecture, sophisticated
* event management and advanced debug graphics handling.
*
* @author Robert Walker
*/
public abstract class PluggableRobot extends AdvancedRobot {
private static boolean _battleInitialized = false;
private static Point2D.Double _center;
private ListenerDelegate _listenerDelegate;
private ArrayList<Component> _components = new ArrayList<Component>();
private Hud _hud;
public PluggableRobot() {
_listenerDelegate = new ListenerDelegate();
}
/**
* PluggableRobot's main execution loop. Rather that implementing run() in
* your own robot, you will register listeners, components and painters in
* the initRound() method, and those objects will handle your robot's combat
* logic. This allows you to more easily separate concerns into separate
* objects, and replace parts to change robot behavior.
*/
@Override
public final void run() {
// Initialize battle (at start of first round only)
if (!_battleInitialized) {
_center = new Point2D.Double(getWidth() / 2, getHeight() / 2);
initBattle();
_battleInitialized = true;
}
// Mechanism for capturing all events and handing them to the
// ListenerDelegate.
addCustomEvent(new Condition("eventManager") {
public boolean test() {
PluggableRobot.this.handleEvents();
return false;
}
});
// Initialize the Hud
_hud = new Hud(this);
registerListener(_hud);
// Allow robot to initialize its parts
initRound();
// Main loop
while (true) {
// Let each component act
for (Component component : _components) {
component.go();
}
// Handle painting
PaintEvent pe = _listenerDelegate.getLastPaintEvent();
if (pe != null && pe.getTime() == getTime()) {
_hud.paint(getTime());
}
execute();
}
}
/**
* Returns a Point2D object located at the exact center of the battlefield.
*/
public Point2D.Double getCenter() {
return _center;
}
/**
* Called by PluggableRobot at the start of a battle. Your implementation of
* this method should perform whatever operations you wish to handle at the
* start of a battle, such as setting tank colors and initializing memory
* objects that will persist between rounds.
*/
protected abstract void initBattle();
/**
* Called by PluggableRobot at the start of each round. Your implementation
* of this method should create Hud layers, register your robot's
* EventListeners, Components and Painters, and perform any other operations
* you wish to handle at the start of a round.
*/
protected abstract void initRound();
/**
* Registers an EventListener. Registration lasts until the end of the round
* and enables the listener to receive event notifications.
*/
protected final void registerListener(EventListener listener) {
_listenerDelegate.register(listener);
}
/**
* Registers a Component. Registration lasts until the end of the round and
* enables the Component to be notified when it is time to act.
*/
protected void registerComponent(Component component) {
_components.add(component);
}
/**
* Constructs a new Hud layer with the given name and bound to the indicated
* key. The enabled argument determines whether or not the layer should
* be on or off by default.
*/
protected void createLayer(int key, String name, boolean enabled) {
_hud.createLayer(key, name, enabled);
}
/**
* Registers a Painter and binds it to the layer corresponding to the given
* key. Registration lasts until the end of the round and enables the
* Painter to draw on a Hud layer when it's time to paint.
*/
protected void registerPainter(int key, Painter painter) {
_hud.registerPainter(key, painter);
}
/**
* Called by a custom event registered by PluggableRobot. This method hands
* the event list to the ListenerDelegate, which will in turn notify the
* EventListeners in the desired order.
*/
private void handleEvents() {
_listenerDelegate.processEvents(getAllEvents());
clearAllEvents();
}
/*
* Since we've got our own event handling mechanism, we don't want to use
* the existing one, so make these methods final.
*/
@Override
public final void onBattleEnded(BattleEndedEvent 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 onCustomEvent(CustomEvent event) {
}
@Override
public final void onDeath(DeathEvent 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 onKeyPressed(KeyEvent e) {
}
@Override
public final void onKeyReleased(KeyEvent e) {
}
@Override
public final void onKeyTyped(KeyEvent e) {
}
@Override
public final void onMouseClicked(MouseEvent e) {
}
@Override
public final void onMouseDragged(MouseEvent e) {
}
@Override
public final void onMouseEntered(MouseEvent e) {
}
@Override
public final void onMouseExited(MouseEvent e) {
}
@Override
public final void onMouseMoved(MouseEvent e) {
}
@Override
public final void onMousePressed(MouseEvent e) {
}
@Override
public final void onMouseReleased(MouseEvent e) {
}
@Override
public final void onMouseWheelMoved(MouseWheelEvent e) {
}
@Override
public final void onPaint(Graphics2D g) {
}
@Override
public final void onRobotDeath(RobotDeathEvent event) {
}
@Override
public final void onScannedRobot(ScannedRobotEvent event) {
}
@Override
public final void onSkippedTurn(SkippedTurnEvent event) {
}
@Override
public final void onStatus(StatusEvent e) {
}
@Override
public final void onWin(WinEvent event) {
}
}
</nowiki>