NeuralTargetingBot
Neural Networks
Neural Networks are machine learning systems loosely based on brains. Also they are not very popular in roborumble.
Making a Simple Neural Targeting Bot Using Roboneural
- Utilities
Roboneural(There is a link in it's page).
public static class GunUtils {
public static double absoluteBearing(Point2D.Double l1, Point2D.Double l2) {
return Math.atan2(l2.x - l1.x, l2.y - l1.y);
}
public static int limit(int min, int val, int max) {
return Math.max(min, Math.min(val, max));
}
}
- AbsoluteBearing takes the angle to a point from the source.
- Limit limits a number between two numbers.
- Variables
static final int BINS = 51;
static final int MIDDLE_BIN = 25;
static final double FIRE_POWER = 1.95;
int[] splitNum = new int[]{9, 9};
public static MultiLayerPerceptron mlp = new MultiLayerPerceptron(new int[]{18, BINS},
new ActivationFunction[]{new Sigmoid()}, 0.1, 1);
/*
Creating a MultiLayerPerceptron is easy.
First is how many cells for the nth layer.
Second is the activation functions for hidden and output cells.
Third is learning rate
Fourth is batch size
*/
Point2D.Double myLocation = new Point2D.Double();
Point2D.Double enemyLocation = new Point2D.Double();
ArrayList<Wave> gfWaves = new ArrayList<>();
ArrayList<Wave> gfWavesToRemove = new ArrayList<>();
public static ArrayList<double[]> neuralNetworkInput = new ArrayList<>();
public static ArrayList<double[]> neuralNetworkOutput = new ArrayList<>();
/*
For saving past information to train our MLP.
*/
public void run() { //Radar Stuff and Colors.
setBodyColor(Color.ORANGE);
setGunColor(Color.BLUE);
setRadarColor(Color.CYAN);
setScanColor(Color.CYAN);
setAdjustGunForRobotTurn(true);
setAdjustRadarForGunTurn(true);
for (;;) {
turnRadarRightRadians(Double.POSITIVE_INFINITY);
}
}
- Wave Stuff
public class Wave {
double power;
double velocity;
double absoluteBearing;
double distanceTraveled;
int lateralDirection;
double mea;
double binWidth;
Point2D.Double source;
double[] input;
public Wave(Point2D.Double source, double power, double absoluteBearing, int lateralDirection) {
this.source = (Point2D.Double) source.clone();
this.power = power;
this.velocity = 20 - 3 * power;
this.absoluteBearing = absoluteBearing;
mea = 8 / velocity;
binWidth = mea / BINS * 2;
this.lateralDirection = lateralDirection;
}
public int update() {
distanceTraveled += velocity;
if (distanceTraveled > source.distance(enemyLocation)) {
gfWavesToRemove.add(this);//These will be deleted.
int bin = (int) Math.round(((Utils.normalRelativeAngle(GunUtils.absoluteBearing(source, enemyLocation) - absoluteBearing))
/ (lateralDirection * binWidth)) + MIDDLE_BIN);
return GunUtils.limit(0, bin, BINS - 1);//Hit guess factor
}
return -1;//If it didn't hit we will know that because of -1.
}
public double getFiringAngle(int firingBin) {
return absoluteBearing + (lateralDirection * binWidth) * (firingBin - MIDDLE_BIN);//Producing a firing angle from a bin
}
}
- Main code
public void onScannedRobot(ScannedRobotEvent e) {
myLocation.setLocation(getX(), getY());//Setting our location
double absBearing = e.getBearingRadians() + getHeadingRadians();//For radar and targeting
double distance = e.getDistance(); //For learning enemy location
enemyLocation.setLocation(myLocation.x + Math.sin(absBearing) * distance,
myLocation.y + Math.cos(absBearing) * distance);
setTurnRadarRightRadians(Utils.normalRelativeAngle(absBearing - getRadarHeadingRadians()) * 2);//Locking the radar
double enemyVelocity = e.getVelocity();
double enemyLateralVelocity = (enemyVelocity * Math.sin(e.getHeadingRadians() - absBearing));//Some data
double enemyAdvancingVelocity = (enemyVelocity * -Math.cos(e.getHeadingRadians() - absBearing));//Some data
int enemyLateralDirection = enemyLateralVelocity >= 0 ? 1 : -1;
//Don't forget to normalise the data between 0-1. FeatureSplitter works like that.
double[] data = new double[]{Math.abs(enemyLateralVelocity), enemyAdvancingVelocity / 16 + 0.5};//Normal Data
double[] preprocessedData = dsekercioglu.roboneural.format.FeatureSplitter.split(data, splitNum);
//Preprocessing the data to make it more useful for small networks.
Wave w = new Wave(myLocation, FIRE_POWER, absBearing, enemyLateralDirection);//Creating a wave
w.input = preprocessedData;
gfWaves.add(w);
int firingBin = dsekercioglu.roboneural.format.Utils.getBin(mlp.getOutput(preprocessedData));//Getting the bestBin
double firingAngle = w.getFiringAngle(firingBin);
setTurnGunRightRadians(Utils.normalRelativeAngle(firingAngle - getGunHeadingRadians()));
setFire(FIRE_POWER);
train(); //For training the network
updateWaves(); //For updating the waves
}
- Updating the Waves and Training Our MultiLayerPerceptron
public void updateWaves() {
for (Wave w : gfWaves) {
int result = w.update();
if (result != -1) { //Here we use the -1 to understand if the wave hit or didn't.
neuralNetworkInput.add(0, w.input); //We add to the beginning to make training easier.
double[] bins = new double[BINS];
bins[result] = 1;//We set the correct gf. Others are zero initially.
neuralNetworkOutput.add(0, bins); //Adding it.
}
}
gfWaves.removeAll(gfWavesToRemove);//Removing the hit waves.
gfWavesToRemove.clear();//Clearing the list.
}
public void train() {
if (!neuralNetworkInput.isEmpty()) {
for (int i = 0; i < 25; i++) {
int index = (int) (Math.random() * Math.min(200, neuralNetworkInput.size())); //Training the last 200 waves 25 times.
mlp.backPropogate(neuralNetworkInput.get(index), neuralNetworkOutput.get(index));
}
}
}
Notes
- To make it more powerful there is a lot more to do:
- Changing the training policy.
- Increasing the number of data.
- Combining with another network.
- Different activation functions(For example SoftPlus(SmoothMax))
- Changing the output type.
- Making an anti-surfer gun.(It can be really strong) NeuralTargetingBot gets about %59 against Shadow. You can get %72 with a Neural Network.