User:AaronR/HatLeagueRobot
< User:AaronR
Jump to navigation
Jump to search
Revision as of 02:15, 15 January 2008 by AaronR (talk | contribs) (Publishing some source code for the Hat League)
Yet another base class for robots participating in the Hat League.
Contents
Version history
- 0.1 The "This should save some time" release.
- Release: 2008-01-14
- A largely untested and probably buggy robot framework.
What's next
- Debugging, probably.
- Better enemy wave detection.
Source code
Usage rules
- If a method begins with "
hl", use it instead of the normal Robocode method. - See rule 1.
The HatLeagueRobot class
package wiki.hat;
import static java.lang.Math.*;
import static robocode.Rules.*;
import java.awt.geom.Point2D;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import robocode.*;
public abstract class HatLeagueRobot extends TeamRobot {
// OVERRIDE THESE IN SUBCLASSES, NOT THE NORMAL ROBOCODE METHODS! //
/**
* Don't:
*
* public void hlRun() {
* // ...
*
* do {
* // ...
* execute();
* } while (true);
* }
*
* Do:
*
* public void hlRun() {
* // ...
* }
*
* public void hlOnTickEnd() {
* // ...
* }
*/
public void hlRun() {
}
public void hlOnTickBegin() {
}
public void hlOnTickEnd() {
}
public void hlOnCustomEvent(CustomEvent e) {
}
public void hlOnPartnerDataReceived(long time, Point2D.Double location,
double heading, double velocity, double energy) {
}
/**
* Note that this method is called both when this robot scans an enemy and
* when the partner scans one.
*/
public void hlOnEnemyDataReceived(long time, Point2D.Double location,
double heading, double velocity, double energy, String name) {
}
public void hlOnPartnerBulletOriginReceived(long time,
Point2D.Double location, double heading, double velocity) {
}
/**
* Note that this method is called both when this robot scans an enemy that
* fired a wave and when the partner scans one.
*/
public void hlOnEnemyWaveOriginReceived(long time, Point2D.Double location,
double velocity) {
}
public void hlOnPartnerRadarTargetReceived(String target) {
}
public void hlOnPartnerBulletTargetReceived(String target) {
}
public void hlOnSuggestedRadarTargetReceived(String target) {
}
public void hlOnSuggestedBulletTargetReceived(String target) {
}
public void hlOnCustomMessageReceived(String message) {
}
// SPECIAL HAT LEAGUE ACTION METHODS. //
private static class HatLeagueMessage {
private String name;
private String[] values;
public HatLeagueMessage(String name, String... values) {
this.name = name;
this.values = values;
}
public String getName() {
return name;
}
public String[] getValues() {
return values;
}
}
/**
* Use this everywhere you would normally use setFire().
*/
public final Bullet hlSetFireBullet(double bulletPower) {
// Copied from robocode.peer.RobotPeer.java. =)
if (getGunHeat() > 0 || getEnergy() == 0) {
return null;
}
double realBulletPower = min(getEnergy(), min(max(bulletPower,
Rules.MIN_BULLET_POWER), Rules.MAX_BULLET_POWER));
broadcastHatLeagueMessage(new HatLeagueMessage("BO",
Long.toString(getTime()), Double.toString(getX()),
Double.toString(getY()),
Double.toString(getGunHeadingRadians()),
Double.toString(getBulletSpeed(realBulletPower))));
return setFireBullet(realBulletPower);
}
public final void hlSetRadarTarget(String target) {
broadcastHatLeagueMessage(new HatLeagueMessage("MR", target));
}
public final void hlSetBulletTarget(String target) {
broadcastHatLeagueMessage(new HatLeagueMessage("MB", target));
}
public final void hlSuggestRadarTarget(String target) {
broadcastHatLeagueMessage(new HatLeagueMessage("TR", target));
}
public final void hlSuggestBulletTarget(String target) {
broadcastHatLeagueMessage(new HatLeagueMessage("TB", target));
}
public final void hlBroadcastCustomMessage(String message) {
broadcastHatLeagueMessage(new HatLeagueMessage("NA", message));
}
private void broadcastHatLeagueMessage(HatLeagueMessage message) {
StringBuilder buffer = new StringBuilder();
buffer.append(message.getName());
for (String value : message.getValues()) {
buffer.append(",");
buffer.append(value);
}
try {
broadcastMessage(buffer.toString());
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
private HatLeagueMessage decodeHatLeagueMessage(String message) {
String[] messageParts = message.split(",");
// Dang it! Why did they have to wait until Java 1.6 to introduce
// Arrays.copyOfRange()?
String[] valueParts = new String[messageParts.length - 1];
for (int i = 1; i < messageParts.length; i++) {
valueParts[i - 1] = messageParts[i];
}
return new HatLeagueMessage(messageParts[0], valueParts);
}
// CLASS INTERNALS START HERE. //
private static class TickCondition extends Condition {
public TickCondition(String name, int priority) {
super(name, priority);
}
public boolean test() {
return true;
}
}
private static final String TICK_BEGIN_NAME = "onTickBegin";
private static final String TICK_END_NAME = "onTickStart";
private Map<String, Double> enemyEnergies = new HashMap<String, Double>();
@Override
public final void run() {
addCustomEvent(new TickCondition(TICK_BEGIN_NAME, 99));
addCustomEvent(new TickCondition(TICK_END_NAME, 1));
hlRun();
}
@Override
public final void onCustomEvent(CustomEvent e) {
String name = e.getCondition().getName();
if (name.equals(TICK_BEGIN_NAME)) {
broadcastHatLeagueMessage(new HatLeagueMessage("PD",
Long.toString(getTime()), Double.toString(getX()),
Double.toString(getY()),
Double.toString(getHeadingRadians()),
Double.toString(getVelocity()),
Double.toString(getEnergy())));
hlOnTickBegin();
} else if (name.equals(TICK_END_NAME)) {
hlOnTickEnd();
} else {
hlOnCustomEvent(e);
}
}
@Override
public final void onScannedRobot(ScannedRobotEvent e) {
String name = e.getName();
long time = getTime();
double distance = e.getDistance();
Point2D.Double location = project(new Point2D.Double(getX(), getY()),
e.getBearingRadians(), distance);
double heading = e.getHeadingRadians();
double velocity = e.getVelocity();
double energy = e.getEnergy();
HatLeagueMessage scannedMessage = new HatLeagueMessage("ES",
Long.toString(time), Double.toString(location.getX()),
Double.toString(location.getY()), Double.toString(heading),
Double.toString(velocity), Double.toString(energy), name);
passHatLeagueMessage(scannedMessage);
broadcastHatLeagueMessage(scannedMessage);
if (enemyEnergies.containsKey(name)) {
double lastEnergy = enemyEnergies.get(name);
double difference = lastEnergy - energy;
if (difference > 0.09 && difference < 3.01) {
HatLeagueMessage waveMessage = new HatLeagueMessage("EW",
Long.toString(time), Double.toString(location.getX()),
Double.toString(location.getY()),
Double.toString(getBulletSpeed(difference)));
passHatLeagueMessage(waveMessage);
broadcastHatLeagueMessage(waveMessage);
}
}
enemyEnergies.put(name, energy);
}
@Override
public final void onMessageReceived(MessageEvent e) {
passHatLeagueMessage(decodeHatLeagueMessage(e.getMessage().toString()));
}
private void passHatLeagueMessage(HatLeagueMessage message) {
String messageType = message.getName();
String[] messageValues = message.getValues();
if (messageType.equals("PD")) {
hlOnPartnerDataReceived(Long.parseLong(messageValues[0]),
new Point2D.Double(Double.parseDouble(messageValues[1]),
Double.parseDouble(messageValues[2])),
Double.parseDouble(messageValues[3]),
Double.parseDouble(messageValues[4]),
Double.parseDouble(messageValues[5]));
} else if (messageType.equals("ES")) {
hlOnEnemyDataReceived(Long.parseLong(messageValues[0]),
new Point2D.Double(Double.parseDouble(messageValues[1]),
Double.parseDouble(messageValues[2])),
Double.parseDouble(messageValues[3]),
Double.parseDouble(messageValues[4]),
Double.parseDouble(messageValues[5]), messageValues[6]);
} else if (messageType.equals("BO")) {
hlOnPartnerBulletOriginReceived(Long.parseLong(messageValues[0]),
new Point2D.Double(Double.parseDouble(messageValues[1]),
Double.parseDouble(messageValues[2])),
Double.parseDouble(messageValues[3]),
Double.parseDouble(messageValues[4]));
} else if (messageType.equals("EW")) {
hlOnEnemyWaveOriginReceived(Long.parseLong(messageValues[0]),
new Point2D.Double(Double.parseDouble(messageValues[1]),
Double.parseDouble(messageValues[2])),
Double.parseDouble(messageValues[3]));
} else if (messageType.equals("MR")) {
hlOnPartnerRadarTargetReceived(messageValues[0]);
} else if (messageType.equals("MB")) {
hlOnPartnerBulletTargetReceived(messageValues[0]);
} else if (messageType.equals("TR")) {
hlOnSuggestedRadarTargetReceived(messageValues[0]);
} else if (messageType.equals("TB")) {
hlOnSuggestedBulletTargetReceived(messageValues[0]);
} else if (messageType.equals("NA")) {
// This is so that we correctly parse custom messages containing
// commas.
StringBuilder joinedMessage = new StringBuilder();
for (int i = 0; i < messageValues.length; i++) {
joinedMessage.append(messageValues[i]);
if (i < messageValues.length - 1) {
joinedMessage.append(",");
}
}
hlOnCustomMessageReceived(joinedMessage.toString());
} else {
throw new RuntimeException("Unrecognized message type: "
+ messageType);
}
}
private static Point2D.Double project(Point2D.Double sourceLocation,
double angle, double distance) {
return new Point2D.Double(
sourceLocation.x + Math.sin(angle) * distance, sourceLocation.y
+ Math.cos(angle) * distance);
}
}
Example robot
package wiki.hat;
import java.awt.Color;
import java.awt.geom.*;
public class HatLeagueTestRobot extends HatLeagueRobot {
@Override
public void hlRun() {
setColors(Color.RED, Color.ORANGE, Color.RED);
setTurnRadarRightRadians(Double.POSITIVE_INFINITY);
}
@Override
public void hlOnPartnerBulletOriginReceived(long time,
Point2D.Double location, double heading, double velocity) {
out.println(time + " - partner fired bullet: location " + location
+ ", heading " + heading + ", velocity " + velocity);
}
@Override
public void hlOnTickEnd() {
hlSetFireBullet(0.5);
}
}