NeuralMinimumRiskBot
Jump to navigation
Jump to search
Contents
Neural Networks
- Neural networks are architectures based loosely on brain and used both in Machine Learning and Data Mining.
- Also they are not very popular in Roborumble.
Making a Neural Minimum Risk Bot Using Roboneural
- Utilities
Roboneural(There is a link in it's page)
public static class MoveUtils {
public static Point2D.Double project(Point2D.Double source, double angle, double distance) {
return new Point2D.Double(source.x + Math.sin(angle) * distance, source.y + Math.cos(angle) * distance);
}
public static double distanceToWall(Point2D.Double location) {
return Math.min(Math.min(location.x, 800 - location.x), Math.min(location.y, 600 - location.y));
//This robot is just for 1on1 but it uses MinimumRisk=)
}
}
Variables
public static MultiLayerPerceptron mlp = new MultiLayerPerceptron(new int[]{6, 5, 5, 1}, new ActivationFunction[]{new Tanh(), new Tanh(), new Tanh()}, 0.01, 1);
//Using Hyperbolic Tangent to have negative results.
//This one does deep learning =).
Point2D.Double myLocation = new Point2D.Double();
Point2D.Double enemyLocation = new Point2D.Double();
public static ArrayList<double[]> notHit = new ArrayList<>();//Correct moves
public static ArrayList<double[]> hit = new ArrayList<>();//Wrong moves
public static ArrayList<double[]> rammed = new ArrayList<>();//Very bad moves
//We have a special list for this so our bot will always be trained against rammers.
double[] bestResultInput = null;//The input of our current move
boolean hitWhenGoing = true;//Did we hit a bullet while going to that point?
/*
If the robot got hit when trying to reach it's goal this will let us to know
on ScannedRobot event.
*/
double enemyEnergy = 100;
int pointNum = 100;//Number of positions we will produce
double myLateralVelocity;
double myAdvancingVelocity;
public void run() { //Radar Stuff and Colors.
setBodyColor(Color.BLACK);
setGunColor(Color.CYAN);
setRadarColor(Color.BLACK);
setScanColor(Color.BLACK);
setAdjustGunForRobotTurn(true);
setAdjustRadarForGunTurn(true);
for (;;) {
turnRadarRightRadians(Double.POSITIVE_INFINITY);
}
}
Other Utilities
public double[] produceData(Point2D.Double target) {//We will use this as an input to our MLP.
double[] data = new double[6];
data[0] = target.distance(enemyLocation) / 1200;//For teaching to stay at a controlled distance.
data[1] = target.distance(myLocation) / 199;//If we go too far there is a lot more chance to get hit by a bullet.
data[2] = Math.min(enemyEnergy, 100) / 100;//Setting the balance of distance
data[3] = Math.min(getEnergy(), 100) / 100;//Setting the balance of distance
data[4] = Math.abs(myLateralVelocity) / 8;//Learning how enemy fires?
data[5] = myAdvancingVelocity / 16 + 0.5;//Learning how enemy fires?
return data;
}
//From the wiki, GoTo page.
/**
* This method is very verbose to explain how things work. Do not
* obfuscate/optimize this sample.
*/
private void goTo(double x, double y) {
/* Transform our coordinates into a vector */
x -= getX();
y -= getY();
/* Calculate the angle to the target position */
double angleToTarget = Math.atan2(x, y);
/* Calculate the turn required get there */
double targetAngle = Utils.normalRelativeAngle(angleToTarget - getHeadingRadians());
/*
* The Java Hypot method is a quick way of getting the length
* of a vector. Which in this case is also the distance between
* our robot and the target location.
*/
double distance = Math.hypot(x, y);
/* This is a simple method of performing set front as back */
double turnAngle = Math.atan(Math.tan(targetAngle));
setTurnRightRadians(turnAngle);
if (targetAngle == turnAngle) {
setAhead(distance);
} else {
setBack(distance);
}
}
Main Code
public void onScannedRobot(ScannedRobotEvent e) {
enemyEnergy = e.getEnergy();//Input to NN
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
myLateralVelocity = getVelocity() * Math.sin(e.getBearingRadians());
myAdvancingVelocity = getVelocity() * -Math.cos(e.getBearingRadians());
ArrayList<Point2D.Double> points = new ArrayList<>();//Points will be kept here
if (getDistanceRemaining() < 18/*If touching the target we will create another set of points*/) {
if (!hitWhenGoing) { //This will be true if we hit a bullet when going to our destination
notHit.add(bestResultInput);//Because we didn't get hit this is a correct move.
}
hitWhenGoing = false;//Because we are changing points this won't be true for the next destination.Possibly
for (int i = 0; i < pointNum; i++) {//C
points.add(MoveUtils.project(myLocation,
Math.random() * Math.PI * 2,
(int) (Math.random() * 100 + 100)));//To not to sit where we are.
/*
If we sit still we will arrive to our destination in 1 tick.
We won't be hit possibly and it will be added to notHit list and corrupt the data.
*/
}
double lowestDanger = Double.POSITIVE_INFINITY;
Point2D.Double best = null;
for (int i = 0; i < points.size(); i++) { //Finding the bestPoint
Point2D.Double p = points.get(i);
if (MoveUtils.distanceToWall(p) > 22) {//We don't want to leave this to MLP.
double[] data = produceData(p);
double currentDanger = mlp.getOutput(data)[0];
if (currentDanger < lowestDanger) {
lowestDanger = currentDanger;
best = (Point2D.Double) p.clone();
bestResultInput = data.clone(); //We will use this later to train the network
}
}
}
goTo(best.x, best.y);//Going to the position
}
train();//Train!
}
Learning
public void onHitByBullet(HitByBulletEvent e) {//Hit learning
hit.add(bestResultInput);
hitWhenGoing = true;
}
public void onHitRobot(HitRobotEvent e) {
if (e.isMyFault()) {//If the enemy rammed us it's not our fault.
rammed.add(bestResultInput);
hitWhenGoing = true;
}
}
public void train() {
for (int i = notHit.size() - 1; i > Math.max(0, notHit.size() - 15); i--) {
System.out.println(Arrays.toString(notHit.get(i)));
mlp.backPropogate(notHit.get(i), new double[]{-1});
}
for (int i = hit.size() - 1; i > Math.max(0, hit.size() - 15); i--) {
/*
We want this training process to have more effect on the result
because the robots learn.
*/
mlp.backPropogate(hit.get(i), new double[]{1});
}
for (int i = rammed.size() - 1; i > Math.max(0, hit.size() - 5); i--) {
//This training process will have even more effect on the result.
mlp.backPropogate(rammed.get(i), new double[]{1});
}
}
- Watch this robot fighting with a sample bot. You will realise that it improves itself slowly.
- I tried it against Crazy. It stays away normally but when Crazy comes too close it tracks it from behind and doesn't get hit for the rest of the round.
How to Improve
- This movement doesn't care about any bullets.
- It can be easily improved by adding bullets.
- Doing Compressed Serialization would help the movement improve all the time in "Melee" because there are more than one robot in melee so the learning would be more general.
- The point shouldn't be chosen if enemy is between our bot and the point.