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; } } }