Difference between revisions of "User:AaronR/HatLeagueRobot"
Jump to navigation
Jump to search
(Version 0.2 is up) |
RednaxelaBot (talk | contribs) m (Using <syntaxhighlight>.) |
||
Line 24: | Line 24: | ||
=== The HatLeagueRobot class === | === The HatLeagueRobot class === | ||
− | < | + | <syntaxhighlight> |
package wiki.hat; | package wiki.hat; | ||
Line 376: | Line 376: | ||
} | } | ||
} | } | ||
− | </ | + | </syntaxhighlight> |
=== Example robot === | === Example robot === | ||
− | < | + | <syntaxhighlight> |
package wiki.hat; | package wiki.hat; | ||
Line 404: | Line 404: | ||
} | } | ||
} | } | ||
− | </ | + | </syntaxhighlight> |
Latest revision as of 09:36, 1 July 2010
Yet another base class for robots participating in the Hat League.
Contents
Version history
- 0.2 The "I didn't even expect it to work this well" release.
- Release: 2008-01-15
- Bugfix: the enemy-scanned event didn't bother to check whether the scanned robot was actually an enemy...
- The API has been changed to pass bullet power instead of bullet speed as the parameter to the partner-bullet-fired and enemy-wave-fired events.
- The internal implementation now properly handles multiple messages that are merged into a single string (separated by "\n"). It will also ignore blank messages.
- Added hlGetRadarTarget() and hlGetBulletTarget() methods that return the values previously supplied through the corresponding hlSetRadarTarget() and hlSetBulletTarget() methods.
- 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.
- Make it sort out duplicate enemy-scanned and enemy-fired-wave events registered by both robots.
- 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.*;
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 power) {
}
/**
* 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 power) {
}
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);
}
private String radarTarget = null;
private String bulletTarget = null;
public final String hlGetRadarTarget() {
return radarTarget;
}
public final void hlSetRadarTarget(String target) {
broadcastHatLeagueMessage(new HatLeagueMessage("MR", target));
radarTarget = target;
}
public final String hlGetBulletTarget() {
return bulletTarget;
}
public final void hlSetBulletTarget(String target) {
broadcastHatLeagueMessage(new HatLeagueMessage("MB", target));
bulletTarget = 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[] decodeHatLeagueMessages(String receivedBroadcast) {
String[] messages = receivedBroadcast.split("\n");
List<HatLeagueMessage> decodedMessages = new ArrayList<HatLeagueMessage>();
for (String message : messages) {
if (!message.equals("")) {
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];
}
decodedMessages.add(new HatLeagueMessage(messageParts[0],
valueParts));
}
}
return decodedMessages.toArray(new HatLeagueMessage[decodedMessages.size()]);
}
// 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();
if (!isTeammate(name)) {
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) {
HatLeagueMessage[] messages = decodeHatLeagueMessages(e.getMessage().toString());
for (HatLeagueMessage message : messages) {
passHatLeagueMessage(message);
}
}
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]),
getBulletPowerFromSpeed(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])),
getBulletPowerFromSpeed(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 double getBulletPowerFromSpeed(double bulletSpeed) {
return (20.0 - bulletSpeed) / 3;
}
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);
}
}