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.
276 lines
11 KiB
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;
|
|
}
|
|
}
|
|
|