The assignment to use neural network an conjunction with robocode for demonstration purposes.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
robocode-neural-network/src/neural/BattlefieldParameterEvaluat...

276 lines
11 KiB

package neural;
import java.util.Arrays;
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Random;
import javax.imageio.ImageIO;
import org.encog.engine.network.activation.ActivationSigmoid;
import org.encog.ml.data.MLData;
import org.encog.ml.data.basic.BasicMLData;
import org.encog.ml.data.basic.BasicMLDataSet;
//import org.encog.neural.data.basic.BasicNeuralDataSet;
import org.encog.neural.networks.BasicNetwork;
import org.encog.neural.networks.layers.BasicLayer;
import org.encog.neural.networks.training.propagation.resilient.ResilientPropagation;
import robocode.BattleResults;
import robocode.control.*;
import robocode.control.events.*;
import neural.Palette;
public class BattlefieldParameterEvaluator {
// Minimum allowable battlefield size is 400
final static int MINBATTLEFIELDSIZE = 400;
final static int MAXBATTLEFIELDSIZE = 4000;
// Minimum allowable gun cooling rate is 0.1
final static double MINGUNCOOLINGRATE = 0.1;
final static double MAXGUNCOOLINGRATE = 10;
// Visual image dimensions
final static int NUMBATTLEFIELDSIZES = 601;
final static int NUMCOOLINGRATES = 501;
final static int NUMSAMPLES = 1000;
// Number of inputs for the multilayer perceptron (size of the input vectors)
final static int NUM_NN_INPUTS = 2;
// Number of hidden neurons of the neural network
final static int NUM_NN_HIDDEN_UNITS = 50;
// Number of epochs for training
final static int NUM_TRAINING_EPOCHS = 100000;
// The requested error in nn training
final static double NN_TRAINING_ERROR = 0.001;
// Maximum robot score obtained - used for scaling <0,1>
final static int BATTLE_MAX_SCORE = 250;
/* The name of the palette. Must be one of "Spectrum",
* "PaleSpectrum", "Grayscale", "CyclicGrayscale", "CyclicRedCyan",
* "EarthSky", "HotCold", or "Fire". */
final static String PALETTE = "PaleSpectrum";
static int NdxBattle;
static double[] FinalScore1;
static double[] FinalScore2;
public static void main(String[] args) {
double[] BattlefieldSize = new double[NUMSAMPLES];
double[] GunCoolingRate = new double[NUMSAMPLES];
FinalScore1 = new double[NUMSAMPLES];
FinalScore2 = new double[NUMSAMPLES];
Random rng = new Random(15L);
// Disable log messages from Robocode
RobocodeEngine.setLogMessagesEnabled(false);
// Create the RobocodeEngine
// Run from C:/Robocode
RobocodeEngine engine = new RobocodeEngine(new java.io.File("/opt/robocode"));
// Add our own battle listener to the RobocodeEngine
engine.addBattleListener(new BattleObserver());
// Show the Robocode battle view
engine.setVisible(false);
// Setup the battle specification
// Setup battle parameters
int numberOfRounds = 1;
long inactivityTime = 100;
int sentryBorderSize = 50;
boolean hideEnemyNames = false;
// Get the robots and set up their initial states
RobotSpecification[] competingRobots = engine.getLocalRepository("sample.RamFire,sample.TrackFire");
RobotSetup[] robotSetups = new RobotSetup[2];
for (NdxBattle = 0; NdxBattle < NUMSAMPLES; NdxBattle++) {
// Choose the battlefield size and gun cooling rate
BattlefieldSize[NdxBattle] = rangedRand(rng, MINBATTLEFIELDSIZE, MAXBATTLEFIELDSIZE);
GunCoolingRate[NdxBattle] = rangedRand(rng, MINGUNCOOLINGRATE, MAXGUNCOOLINGRATE);
// BattlefieldSize[NdxBattle] = MAXBATTLEFIELDSIZE * (0.1 + 0.9 * rng.nextDouble());
// GunCoolingRate[NdxBattle] = MAXGUNCOOLINGRATE * (0.1 + 0.9 * rng.nextDouble());
// Create the battlefield
BattlefieldSpecification battlefield = new BattlefieldSpecification((int) BattlefieldSize[NdxBattle],
(int) BattlefieldSize[NdxBattle]);
// Set the robot positions
robotSetups[0] = new RobotSetup(BattlefieldSize[NdxBattle] / 2.0, BattlefieldSize[NdxBattle] / 3.0, 0.0);
robotSetups[1] = new RobotSetup(BattlefieldSize[NdxBattle] / 2.0, 2.0 * BattlefieldSize[NdxBattle] / 3.0, 0.0);
// Prepare the battle specification
BattleSpecification battleSpec = new BattleSpecification(battlefield, numberOfRounds, inactivityTime,
GunCoolingRate[NdxBattle], sentryBorderSize, hideEnemyNames, competingRobots, robotSetups);
// Run our specified battle and let it run till it is over
engine.runBattle(battleSpec, true);
}
// Cleanup our RobocodeEngine
engine.close();
System.out.println("Fight ended:");
System.out.println(Arrays.toString(BattlefieldSize));
System.out.println(Arrays.toString(GunCoolingRate));
System.out.println(Arrays.toString(FinalScore1));
System.out.println(Arrays.toString(FinalScore2));
// Create the training dataset for the neural network
double[][] RawInputs = new double[NUMSAMPLES][NUM_NN_INPUTS];
double[][] RawOutputs = new double[NUMSAMPLES][1];
for (int NdxSample = 0; NdxSample < NUMSAMPLES; NdxSample++) {
// IMPORTANT: normalize the inputs and the outputs to
// the interval [0,1]
RawInputs[NdxSample][0] = BattlefieldSize[NdxSample] / MAXBATTLEFIELDSIZE;
RawInputs[NdxSample][1] = GunCoolingRate[NdxSample] / MAXGUNCOOLINGRATE;
RawOutputs[NdxSample][0] = FinalScore1[NdxSample] / BATTLE_MAX_SCORE;
}
BasicMLDataSet MyDataSet = new BasicMLDataSet(RawInputs, RawOutputs);
// Create and train the neural network
BasicNetwork network = new BasicNetwork();
network.addLayer(new BasicLayer(null, true, NUM_NN_INPUTS));
network.addLayer(new BasicLayer(new ActivationSigmoid(), true, NUM_NN_HIDDEN_UNITS));
network.addLayer(new BasicLayer(new ActivationSigmoid(), false, 1));
network.getStructure().finalizeStructure();
network.reset();
System.out.println("Training network...");
final ResilientPropagation train = new ResilientPropagation(network, MyDataSet);
int epoch = 1;
do {
train.iteration();
// System.out.println("Epoch #" + epoch + " Error:" + train.getError());
epoch++;
}
while (train.getError() > NN_TRAINING_ERROR);
System.out.println("The error of " + train.getError() + " was reached in " + epoch + " iterations.");
train.finishTraining();
System.out.println("Training completed.");
System.out.println("Testing network...");
// Generate test samples to build an output image
int[] OutputRGBint = new int[NUMBATTLEFIELDSIZES * NUMCOOLINGRATES];
Color MyColor;
double MyValue = 0;
double[][] MyTestData = new double[NUMBATTLEFIELDSIZES * NUMCOOLINGRATES][NUM_NN_INPUTS];
for (int NdxBattleSize = 0; NdxBattleSize < NUMBATTLEFIELDSIZES; NdxBattleSize++) {
for (int NdxCooling = 0; NdxCooling < NUMCOOLINGRATES; NdxCooling++) {
MyTestData[NdxCooling + NdxBattleSize * NUMCOOLINGRATES][0] = 0.1 + 0.9 * ((double) NdxBattleSize)
/ NUMBATTLEFIELDSIZES;
MyTestData[NdxCooling + NdxBattleSize * NUMCOOLINGRATES][1] = 0.1 + 0.9 * ((double) NdxCooling) / NUMCOOLINGRATES;
}
}
// Palette palette = new Palette();
Palette palette = Palette.makeDefaultPalette(PALETTE);
// Simulate the neural network with the test samples and fill a matrix
for (int NdxBattleSize = 0; NdxBattleSize < NUMBATTLEFIELDSIZES; NdxBattleSize++) {
for (int NdxCooling = 0; NdxCooling < NUMCOOLINGRATES; NdxCooling++) {
// Get the output data using taught neural network
BasicMLData input = new BasicMLData(MyTestData[NdxCooling + NdxBattleSize * NUMCOOLINGRATES]);
final MLData output = network.compute(input.clone());
double MyResult = output.getData()[0];
// 2 * fix introduced to shift the top gradient more down to se whole ColorMap spectrum
// MyValue = ClipColor(MyResult * 2);
MyValue = ClipColor(MyResult);
// MyColor = new Color((float) MyValue, (float) MyValue, (float) MyValue);
MyColor = palette.getColor(MyValue);
OutputRGBint[NdxCooling + NdxBattleSize * NUMCOOLINGRATES] = MyColor.getRGB();
}
}
System.out.println("Testing completed.");
// Plot the training samples
for (int NdxSample = 0; NdxSample < NUMSAMPLES; NdxSample++) {
// MyValue = ClipColor(FinalScore1[NdxSample] / BATTLE_MAX_SCORE);
// 2 * fix introduced to shift the top gradient more down to se whole ColorMap spectrum
// MyValue = ClipColor(2 * FinalScore1[NdxSample] / BATTLE_MAX_SCORE);
MyValue = ClipColor(FinalScore1[NdxSample] / BATTLE_MAX_SCORE);
// MyColor = new Color((float) MyValue, (float) MyValue, (float) MyValue);
MyColor = palette.getColor(MyValue);
int MyPixelIndex = (int) (Math.round(NUMCOOLINGRATES * ((GunCoolingRate[NdxSample] / MAXGUNCOOLINGRATE) - 0.1) / 0.9) + Math
.round(NUMBATTLEFIELDSIZES * ((BattlefieldSize[NdxSample] / MAXBATTLEFIELDSIZE) - 0.1) / 0.9)
* NUMCOOLINGRATES);
if ((MyPixelIndex >= 0) && (MyPixelIndex < NUMCOOLINGRATES * NUMBATTLEFIELDSIZES)) {
OutputRGBint[MyPixelIndex] = MyColor.getRGB();
}
}
BufferedImage img = new BufferedImage(NUMCOOLINGRATES, NUMBATTLEFIELDSIZES, BufferedImage.TYPE_INT_RGB);
img.setRGB(0, 0, NUMCOOLINGRATES, NUMBATTLEFIELDSIZES, OutputRGBint, 0, NUMCOOLINGRATES);
File f = new File("hello_" + PALETTE + ".png");
try {
ImageIO.write(img, "png", f);
}
catch (IOException e) {
e.printStackTrace();
}
System.out.println("Image generated.");
// Make sure that the Java VM is shut down properly
System.exit(0);
}
/*
* Clip a color value (double precision) to lie in the valid range [0,1]
*/
public static double ClipColor(double Value) {
if (Value < 0.0) {
Value = 0.0;
}
if (Value > 1.0) {
Value = 1.0;
}
return Value;
}
//
// Our private battle listener for handling the battle event we are interested in.
//
static class BattleObserver extends BattleAdaptor {
// Called when the battle is completed successfully with battle results
public void onBattleCompleted(BattleCompletedEvent e) {
System.out.println("Battle has completed.");
// Get the indexed battle results
BattleResults[] results = e.getIndexedResults();
// Print out the indexed results with the robot names
System.out.println("Battle results:");
for (BattleResults result : results) {
System.out.println(" " + result.getTeamLeaderName() + ": " + result.getScore());
}
// Store the scores of the robots
BattlefieldParameterEvaluator.FinalScore1[NdxBattle] = results[0].getScore();
BattlefieldParameterEvaluator.FinalScore2[NdxBattle] = results[1].getScore();
}
// Called when the game sends out an information message during the battle
public void onBattleMessage(BattleMessageEvent e) {
// System.out.println("Msg> " + e.getMessage());
}
// Called when the game sends out an error message during the battle
public void onBattleError(BattleErrorEvent e) {
System.out.println("Err> " + e.getError());
}
}
/**
* Returns a pseudo-random number between min and max, inclusive. The difference between min and max can be at most
*
* @param min
* Minimum value
* @param max
* Maximum value. Must be greater than min.
* @return Double between min and max, inclusive.
* @see java.util.Random#nextDouble(int)
*/
private static double rangedRand(Random rng, double min, double max) {
// Make sure the randomizer was initialised
if (rng == null)
throw new RuntimeException("PRNG not initialised prior to call");
// Check for the limit
if (Double.valueOf(max - min).isInfinite())
throw new RuntimeException("Value od max - min is infinite. Change the range.");
// nextInt is normally exclusive of the top value, so add 1 to make it inclusive
double randomNum = min + (max - min) * rng.nextDouble();
// int randomNum = rng.nextDouble((max - min) + 1) + min;
return randomNum;
}
}