There are some immediate issues with this code:
package wiki.nn;
import robocode.*;
import wiki.nn.nrlibj.*;
import java.awt.geom.*;
import java.awt.Color;
import java.util.*;
// OrcaM, A multi-smart killer. By PEZ.
//
// OrcaM is open source under GPL-ish conditions.
// You must share any improvements you do to the code.
// You must include this header with any code based on this code.
// If you pick minor parts of the code you can, if you like, close source it.
// But please give credit to the authors of this code.
//
// Home page of this bot is: http://robowiki.dyndns.org/?OrcaM
// The code should be available there and it is also the place for you to share any
// code improvements.
//
// $Id: OrcaM.java,v 1.1 2003/04/21 19:53:27 peter Exp $
public class OrcaM extends AdvancedRobot {
private final static double MAX_BEARING_DIFF = 45;
private final static double MAX_VELOCITY = 8;
private final static double MAX_BEARING_DELTA = 7;
private final static double MAX_DISTANCE_DELTA = 11;
private final static double MAX_HEADING_DELTA = 6;
private final static int HISTORY_DEPTH = 2;
private final static int HISTORY_ITEMS = 2;
private final static String NNdescr[] = {
"layer=0 tnode=8 nname=NodeLin",
"layer=1 tnode=18 nname=NodeSigm",
"layer=2 tnode=10 nname=NodeSigm",
"layer=3 tnode=1 nname=NodeSigm",
"linktype=all fromlayer=0 tolayer=1",
"linktype=all fromlayer=1 tolayer=2",
"linktype=all fromlayer=2 tolayer=3"
};
private final static int NN_CANDIDATES = 7;
private final static double MIN_NETS_IN_TRAINING = 2;
private final static int MAX_TRAININGS = 1000;
private final static int TRAINING_SESSION_LENGTH = 50;
private final static double NN_CANDIDATE_RATE_DEPTH = 50;
private final static double ALLOWED_HIT_RATE_DEGRADATION = -5.0;
private final static double MIN_ACCEPTED_HITRATE = 7;
private final static double MAX_HIT_RATE = 100;
private static Point2D location = new Point2D.Double();
private static Point2D oldLocation = new Point2D.Double();
private static Point2D enemyLocation = new Point2D.Double();
private static Point2D oldEnemyLocation = new Point2D.Double();
private static Rectangle2D fieldRectangle;
private static double velocity;
private boolean haveEnemy;
private static String enemyName;
private double enemyDistance;
private double enemyDistanceDelta;
private double enemyHeading;
private double enemyHeadingDelta;
private double enemyEnergy;
private double enemyVelocity;
private double absoluteBearing;
private double enemyBearingDelta;
private double bulletPower;
private long roundNum;
private boolean roundOver;
private int waitBeforeRam;
private static long time;
private static long wins;
private static long shots;
private static long skippedTurns;
private double timeDelta;
private static double maxTimeDelta;
private static double maxDistance;
private static double rollingBearingDelta;
private static double rollingDistanceDelta;
private static int nNetsInTraining;
private static NNCandidate[] nnCandidate = new NNCandidate[NN_CANDIDATES];
private static LinkedList nnHistoryList = new LinkedList();
private static float[] nnHistoryArray = new float[HISTORY_DEPTH * HISTORY_ITEMS + 4];
private double nnError;
public void run() {
if (fieldRectangle == null) {
initBattle();
}
roundOver = false;
setAdjustGunForRobotTurn(true);
setAdjustRadarForGunTurn(true);
while (true) {
if (Math.random() < 0.05) {
velocity = Math.min(8, Math.random() * 24);
}
setMaxVelocity(Math.abs(getTurnRemaining()) > 45 ? 0.1 : velocity);
selectNNetsForTraining();
if (!haveEnemy) {
setTurnRadarLeft(22.5);
}
haveEnemy = false;
if (enemyEnergy > 0) {
Bullet bullet = setFireBullet(bulletPower);
if (bullet != null) {
shots++;
addCustomEvent(new CheckUpdateFactors(bullet));
}
}
execute();
}
}
public void onScannedRobot(ScannedRobotEvent e) {
double radarTurn;
enemyName = e.getName();
oldLocation.setLocation(location);
location.setLocation(getX(), getY());
oldEnemyLocation.setLocation(enemyLocation);
absoluteBearing = getHeading() + e.getBearing();
enemyEnergy = e.getEnergy();
enemyVelocity = e.getVelocity();
enemyDistance = e.getDistance();
toLocation(absoluteBearing, enemyDistance, location, enemyLocation);
setBulletPower();
timeDelta = getTime() - time;
if (timeDelta > 0) {
if (timeDelta > maxTimeDelta) {
maxTimeDelta = timeDelta;
}
enemyBearingDelta = normalRelativeAngle(absoluteBearing(oldLocation, enemyLocation) -
absoluteBearing(oldLocation, oldEnemyLocation)) / timeDelta;
enemyDistanceDelta = (oldLocation.distance(oldEnemyLocation) - oldLocation.distance(enemyLocation)) / timeDelta;
enemyHeadingDelta = (enemyHeading - e.getHeading()) / timeDelta;
time = getTime();
if (enemyBearingDelta <= MAX_BEARING_DELTA) {
record();
}
}
enemyHeading= e.getHeading();
haveEnemy = true;
radarTurn = normalRelativeAngle(getHeading() + e.getBearing() - getRadarHeading()) * 2;
setTurnRadarRight(radarTurn);
if (getOthers() > 0 && getGunHeat() / getGunCoolingRate() < 2) {
aim();
}
else {
setTurnGunRight(normalRelativeAngle(absoluteBearing - getGunHeading()));
}
considerRamming();
move();
}
public void onWin(WinEvent e) {
wins++;
if (!roundOver) {
printStats();
}
roundOver = true;
}
public void onDeath(DeathEvent e) {
if (!roundOver) {
printStats();
}
roundOver = true;
}
public void onSkippedTurn(SkippedTurnEvent e) {
skippedTurns++;
}
private void initBattle() {
roundNum = getRoundNum();
fieldRectangle = new Rectangle2D.Double(0, 0 , getBattleFieldWidth(), getBattleFieldHeight());
setColors(Color.black, Color.black, Color.white);
maxDistance = (new Point2D.Double(20,20)).distance(
new Point2D.Double(fieldRectangle.getWidth() - 20, fieldRectangle.getHeight() - 20));
for (int i = 0; i < NN_CANDIDATES; i++) {
nnCandidate[i] = new NNCandidate(i);
}
}
private void aim() {
double guessedDistance = location.distance(enemyLocation);
Arrays.sort(nnCandidate);
nnCandidate[0].predict(nnHistoryArray);
double guessedHeading = absoluteBearing(location, enemyLocation) + nnCandidate[0].getPrediction();
Point2D impactLocation = new Point2D.Double();
toLocation(guessedHeading, guessedDistance, location, impactLocation);
translateInsideField(impactLocation, 1);
guessedHeading = absoluteBearing(location, impactLocation);
setTurnGunRight(normalRelativeAngle(guessedHeading - getGunHeading()));
}
private void considerRamming() {
if (enemyEnergy == 0 && getOthers() == 1) {
if (waitBeforeRam == 0) {
goTo(enemyLocation);
}
else {
waitBeforeRam--;
}
}
else {
waitBeforeRam = 100;
}
}
private void move() {
if (Math.abs(getDistanceRemaining()) < Math.random() * 50) {
Point2D dLocation = new Point2D.Double();
double relativeAngle = -36 + 72 * Math.random();
double distanceExtra = 3;
double angle = absoluteBearing + 180 + relativeAngle;
if (isCornered() || enemyDistance > 500) {
distanceExtra = -1;
}
if (enemyEnergy == 0 && getOthers() == 1) {
distanceExtra = -10;
}
distanceExtra *= Math.abs(relativeAngle);
toLocation(angle, enemyDistance + distanceExtra, enemyLocation, dLocation);
if (!fieldRectangle.contains(dLocation)) {
angle = absoluteBearing + 180 - relativeAngle;
toLocation(angle, enemyDistance + distanceExtra, enemyLocation, dLocation);
}
translateInsideField(dLocation, 35);
goTo(dLocation);
}
}
private boolean isCornered() {
double m = 100;
double mnX = m;
double mnY = m;
double mxX = fieldRectangle.getWidth() - m;
double mxY = fieldRectangle.getHeight() - m;
double x = location.getX();
double y = location.getY();
return ((x < mnX && (y < mnY || y > mxY)) || (x > mxX && (y < mnY || y > mxY)));
}
private void setBulletPower() {
double power = 3;
power = Math.min(4 * 7 * nnCandidate[0].getHitRate() / MAX_HIT_RATE, power);
power = Math.min(enemyEnergy / 4, power);
power = Math.min(getEnergy() / 3, power);
bulletPower = power;
}
private void goTo(Point2D point) {
double distance = location.distance(point);
double angle = normalRelativeAngle(absoluteBearing(location, point) - getHeading());
if (Math.abs(angle) > 90) {
distance *= -1;
if (angle > 0) {
angle -= 180;
}
else {
angle += 180;
}
}
setTurnRight(angle);
setAhead(distance);
}
private void translateInsideField(Point2D point, double margin) {
point.setLocation(Math.max(margin, Math.min(fieldRectangle.getWidth() - margin, point.getX())),
Math.max(margin, Math.min(fieldRectangle.getHeight() - margin, point.getY())));
}
private static void toLocation(double angle, double length, Point2D sourceLocation, Point2D targetLocation) {
targetLocation.setLocation(sourceLocation.getX() + Math.sin(Math.toRadians(angle)) * length,
sourceLocation.getY() + Math.cos(Math.toRadians(angle)) * length);
}
private static double absoluteBearing(Point2D source, Point2D target) {
return Math.toDegrees(Math.atan2(target.getX() - source.getX(), target.getY() - source.getY()));
}
private static double normalRelativeAngle(double angle) {
double relativeAngle = angle % 360;
if (relativeAngle <= -180 )
return 180 + (relativeAngle % 180);
else if ( relativeAngle > 180 )
return -180 + (relativeAngle % 180);
else
return relativeAngle;
}
//Paul Evans' excellent function for keeping rolling averages
private static double rollingAvg(double value, double newEntry, double n, double weighting ) {
return (value * n + newEntry * weighting) / (n + weighting);
}
private static float nnNormalizedValue(double value, double max) {
return (float)((value + max) / (2 * max));
}
private void record() {
rollingBearingDelta = rollingAvg(rollingBearingDelta, enemyBearingDelta, 15, 1);
rollingDistanceDelta = rollingAvg(rollingDistanceDelta, enemyDistanceDelta, 15, 1);
nnHistoryList.addLast(new Double(nnNormalizedValue(enemyBearingDelta, MAX_BEARING_DELTA)));
nnHistoryList.addLast(new Double(nnNormalizedValue(enemyDistanceDelta, MAX_DISTANCE_DELTA)));
if (nnHistoryList.size() > HISTORY_DEPTH * HISTORY_ITEMS) {
for (int i = 0; i < HISTORY_ITEMS; i++) {
nnHistoryList.removeFirst();
}
int i;
for (i = 0; i < HISTORY_DEPTH * HISTORY_ITEMS; i++) {
nnHistoryArray[i] = ((Double)(nnHistoryList.get(i))).floatValue();
}
nnHistoryArray[i++] = (float)(enemyDistance / maxDistance);
nnHistoryArray[i++] = (float)(bulletPower / 3);
nnHistoryArray[i++] = nnNormalizedValue(rollingBearingDelta, MAX_BEARING_DELTA);
nnHistoryArray[i++] = nnNormalizedValue(rollingDistanceDelta, MAX_DISTANCE_DELTA);
}
}
private void selectNNetsForTraining() {
int numSelected = 0;
int numInTraining = 0;
for (int i = 0; i < NN_CANDIDATES; i++) {
if (nnCandidate[i].isInTraining()) {
numInTraining++;
if (nnCandidate[i].getTrainingsThisSession() > TRAINING_SESSION_LENGTH) {
double trainingResults = nnCandidate[i].validateTraining();
if (trainingResults > 0) {
nnCandidate[i].setInTraining(true);
nnCandidate[i].initiateTraining();
}
else {
nnCandidate[i].setInTraining(false);
}
}
if (nnCandidate[i].getTrainings() > MAX_TRAININGS) {
nnCandidate[i].setInTraining(false);
}
}
}
if (numInTraining < MIN_NETS_IN_TRAINING) {
int net = (int)Math.floor((Math.random() * NN_CANDIDATES));
if (!(nnCandidate[net].getTrainings() > MAX_TRAININGS)) {
nnCandidate[net].setInTraining(true);
nnCandidate[net].initiateTraining();
}
}
}
private void printStats() {
System.out.println("Wins: " + wins);
for (int i = 0; i < NN_CANDIDATES; i++) {
System.out.println("Net #: " + nnCandidate[i].getId() +
", trainings: " + nnCandidate[i].getTrainings() +
", hit rate: " + nnCandidate[i].getHitRate() +
", error: " + nnCandidate[i].getError());
}
}
class CheckUpdateFactors extends Condition {
private long time;
private double bulletVelocity;
private double bulletPower;
private double bearingDelta;
private Point2D oldRLocation = new Point2D.Double();
private Point2D oldELocation = new Point2D.Double();
private double oldBearing;
private float[] history = new float[HISTORY_DEPTH * HISTORY_ITEMS + 4];
private double[] prediction = new double[NN_CANDIDATES];
public CheckUpdateFactors(Bullet bullet) {
this.time = getTime();
this.bulletVelocity = bullet.getVelocity();
this.bulletPower = bullet.getPower();
this.bearingDelta = enemyBearingDelta;
this.oldRLocation.setLocation(location);
this.oldELocation.setLocation(enemyLocation);
this.oldBearing = absoluteBearing(oldRLocation, oldELocation);
System.arraycopy(nnHistoryArray, 0, history, 0, nnHistoryArray.length);
for (int i = 0; i < NN_CANDIDATES; i++) {
this.prediction[i] = nnCandidate[i].getPrediction();
}
}
public boolean test() {
if (getOthers() == 0) {
removeCustomEvent(this);
return false;
}
double bulletDistance = bulletVelocity * (getTime() - time);
if (bulletDistance > oldRLocation.distance(enemyLocation) - 10) {
double impactBearing = absoluteBearing(oldRLocation, enemyLocation);
double bearingDiff = normalRelativeAngle(impactBearing - oldBearing);
for (int i = 0; i < NN_CANDIDATES; i++) {
if (Math.abs(prediction[i] - bearingDiff) < Math.toDegrees(Math.atan(20 / bulletDistance))) {
nnCandidate[i].updateHitRate(MAX_HIT_RATE, bulletPower);
}
else {
nnCandidate[i].updateHitRate(0, bulletPower);
}
}
if (nnHistoryList.size() == HISTORY_DEPTH * HISTORY_ITEMS) {
float nnCorrectAnswer[] = { nnNormalizedValue(bearingDiff, MAX_BEARING_DIFF) };
for (int i = 0; i < NN_CANDIDATES; i++) {
if (nnCandidate[i].isInTraining()) {
nnError = nnCandidate[i].train(history, nnCorrectAnswer);
}
}
}
removeCustomEvent(this);
}
return false;
}
}
class NNCandidate implements Comparable {
private int id;
private wiki.nn.nrlibj.NNet nnet;
private wiki.nn.nrlibj.NNet nnetBackup;;
private double nnError;
private double prediction;
private long trainings;
private long trainingsBackup;
private int trainingsThisSession;
private double hitRate;
private double hitRateBackup;
private double bestHitRate;
private boolean inTraining;
public NNCandidate(int id) {
this.id = id;
wiki.nn.nrlibj.NrPop.setSeed();
nnet = new wiki.nn.nrlibj.NNet(NNdescr);
}
public NNCandidate(int id, wiki.nn.nrlibj.NNet nnet) {
this.id = id;
this.nnet = nnet;
}
public int compareTo(Object o) {
NNCandidate nnC = (NNCandidate) o;
if (this.getHitRate() > nnC.getHitRate()) {
return -1;
}
if (this.getHitRate() < nnC.getHitRate()) {
return +1;
}
return 0;
}
public boolean equals(Object object) {
if (object instanceof NNCandidate) {
return (((NNCandidate)object).getHitRate() == this.getHitRate());
}
return false;
}
wiki.nn.nrlibj.NNet getNNet() {
return this.nnet;
}
double getError() {
return nnError;
}
double train(float[] input, float[] answer) {
nnError = nnet.ebplearnNNet(input, answer);
trainings++;
trainingsThisSession++;
return nnError;
}
long getTrainings() {
return this.trainings;
}
void predict(float[] input) {
float[] nnAnswer = new float[1];
nnet.frwNNet(input, nnAnswer);
prediction = (0 - MAX_BEARING_DIFF) + MAX_BEARING_DIFF * 2 * nnAnswer[0];
}
double getPrediction() {
return this.prediction;
}
void updateHitRate(double hitValue, double weight) {
this.hitRate = rollingAvg(this.hitRate, hitValue, Math.min(shots, NN_CANDIDATE_RATE_DEPTH), weight);
}
double getHitRate() {
return this.hitRate;
}
boolean isInTraining() {
return this.inTraining;
}
void setInTraining(boolean inTraining) {
this.inTraining = inTraining;
}
void initiateTraining() {
nnetBackup = nnet.cloneNNet();
hitRateBackup = hitRate;
trainingsBackup = trainings;
trainingsThisSession = 0;
}
int getTrainingsThisSession() {
return this.trainingsThisSession;
}
double validateTraining() {
double hitRateDelta = hitRate - hitRateBackup;
if (hitRate > bestHitRate) {
bestHitRate = hitRate;
}
if (hitRateDelta < ALLOWED_HIT_RATE_DEGRADATION || bestHitRate < MIN_ACCEPTED_HITRATE) {
nnet = nnetBackup;
hitRate = hitRateBackup;
trainings = trainingsBackup;
}
return hitRateDelta;
}
int getId() {
return this.id;
}
}
}