import java.awt.Graphics2D; |
import java.util.ArrayList; |
import java.util.Random; |
import robocode.*; |
import robocode.util.Utils; |
* A pluggable listener and strategy architecture for a robot. * http://robowiki.net/cgi-bin/robowiki?PluggableRobot |
* Math utility class. |
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; |
public final class Math2 { public static final double PI_OVER_2 = Math.PI / 2; |
/** * 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 } |
private static final Random random = new Random(); |
/** * 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 |
private Math2() { |
* Returns a Point2D.Double object representing the center of the battlefield. |
* Returns a random int between the min and max arguments, inclusive. |
public Point2D.Double getCenter() { if(_center == null) { _center = new Point2D.Double(getBattleFieldWidth?() / 2, getBattleFieldHeight?() / 2); } |
public static int randomInteger(int min, int max) { return random.nextInt(max - min + 1) + min; } |
return _center; } |
/** * 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)); } |
/** * 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); |
/** * 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); |
/** * Reigsters the given Component, which will give it the opportunity to act each turn. */ protected void registerComponent(Component component) { _components.add(component); |
/** * 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); |
* Reigsters the given Painter, which will give it the opportunity to draw on the HUD each turn. |
* Returns the absolute bearing in radians from the given origin point to the given target * point. |
protected void registerPainter(Hud.Painter painter) { _painters.add(painter); |
public static double getAbsoluteTargetBearing?(Point2D.Double origin, Point2D.Double target) { return Utils.normalAbsoluteAngle?(Math.atan2(target.x - origin.x, target.y - origin.y)); |
* Hand out notifications to the Painters. |
* Returns a Point2D.Double object indicating the relative position of an object at the given * angle and distance from the origin. |
@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 |
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); |
* Process all the events in the queue. |
* Returns a Point2D.Double object indicating the position of an object at the given angle and * distance from the given origin point. |
private void handleEvents() { onBeforeEventsProcessed?(); _listenerDelegate.processEvents(getAllEvents?()); clearAllEvents?(); |
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); |
// Since we have our own event manager, we want to prevent overrides of the Robocode event // methods, so we'll make them final. |
/** * Converts degrees to radians. */ public static double degToRad?(double degrees) { return degrees * Math.PI / 180; } |
@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) { } |
/** * Converts radians to degrees. */ public static double radToDeg?(double radians) { return radians * 180 / Math.PI; } |
</nowiki></pre> |
</nowiki></pre> |
/* * 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; } }