1
0
mirror of https://github.com/fazo96/AIrium.git synced 2025-01-10 09:34:20 +01:00

moved from single precision floating point to double precision

This commit is contained in:
Enrico Fasoli 2016-03-01 15:50:48 +01:00
parent 7650ff44eb
commit dd76b3acc3
16 changed files with 231 additions and 231 deletions

View File

@ -148,7 +148,7 @@ public class Game extends ApplicationAdapter {
Creature c = world.getSelectedCreature(); Creature c = world.getSelectedCreature();
renderer.setColor(1, 1, 1, 1); renderer.setColor(1, 1, 1, 1);
// Draw selection rectangle // Draw selection rectangle
renderer.rect(c.getX() - c.getSize(), c.getY() - c.getSize(), c.getSize() * 2, c.getSize() * 2); renderer.rect((float) (c.getX() - c.getSize()), (float) (c.getY() - c.getSize()), (float) (c.getSize() * 2), (float) (c.getSize() * 2));
// Draw brain // Draw brain
overlayRenderer.begin(); overlayRenderer.begin();
c.getBrain().render(overlayRenderer); c.getBrain().render(overlayRenderer);

View File

@ -17,9 +17,9 @@ import java.util.Random;
public class Serializer { public class Serializer {
private static final String[] sillabe = {"ba", "de", "ka", "mo", "shi", "du", "ro", "te", "mi", "lo", "pa"}; private static final String[] sillabe = {"ba", "de", "ka", "mo", "shi", "du", "ro", "te", "mi", "lo", "pa"};
private static Map<String, Float> defaults; private static Map<String, Double> defaults;
public static String nameBrain(float[][][] brainMap) { public static String nameBrain(double[][][] brainMap) {
// Compute a unique representation of the brainmap // Compute a unique representation of the brainmap
long a = 0; long a = 0;
for (int i = 0; i < brainMap.length; i++) { for (int i = 0; i < brainMap.length; i++) {
@ -64,19 +64,19 @@ public class Serializer {
return a; return a;
} }
public static String serializeSettings(Map<String, Float> options) { public static String serializeSettings(Map<String, Double> options) {
String a = "# Settings file for use with AIrium.\n" String a = "# Settings file for use with AIrium.\n"
+ "# More information at http://github.com/fazo96/AIrium\n"; + "# More information at http://github.com/fazo96/AIrium\n";
for (Object o : options.entrySet().toArray()) { for (Object o : options.entrySet().toArray()) {
Map.Entry<String, Float> e = (Map.Entry<String, Float>) o; Map.Entry<String, Double> e = (Map.Entry<String, Double>) o;
a += e.getKey() + " = " + e.getValue() + "\n"; a += e.getKey() + " = " + e.getValue() + "\n";
} }
return a; return a;
} }
public static Map<String, Float> readSettings(String fileContent) { public static Map<String, Double> readSettings(String fileContent) {
int line = 0; int line = 0;
Map<String, Float> m = new HashMap<String, Float>(); Map<String, Double> m = new HashMap<String, Double>();
for (String s : fileContent.split("\n")) { for (String s : fileContent.split("\n")) {
line++; line++;
if (s.startsWith("#")) { if (s.startsWith("#")) {
@ -88,8 +88,8 @@ public class Serializer {
if (ss.length != 2) { if (ss.length != 2) {
throw new Exception("Invalid string at line " + line); throw new Exception("Invalid string at line " + line);
} }
Log.log(Log.DEBUG, "Loading setting \"" + ss[0].trim() + "\" with value \"" + Float.parseFloat(ss[1].trim()) + "\""); Log.log(Log.DEBUG, "Loading setting \"" + ss[0].trim() + "\" with value \"" + Double.parseDouble(ss[1].trim()) + "\"");
m.put(ss[0].trim(), Float.parseFloat(ss[1].trim())); m.put(ss[0].trim(), Double.parseDouble(ss[1].trim()));
} catch (Exception e) { } catch (Exception e) {
Log.log(Log.ERROR, e.getMessage()); Log.log(Log.ERROR, e.getMessage());
} }
@ -97,7 +97,7 @@ public class Serializer {
return m; return m;
} }
public static String serializeBrain(float brainMap[][][]) { public static String serializeBrain(double brainMap[][][]) {
String s = "# Neural Map for use with AIrium.\n" String s = "# Neural Map for use with AIrium.\n"
+ "# More information at http://github.com/fazo96/AIrium\n" + "# More information at http://github.com/fazo96/AIrium\n"
+ "Layers: " + (brainMap.length + 1); + "Layers: " + (brainMap.length + 1);
@ -116,8 +116,8 @@ public class Serializer {
return s; return s;
} }
public static float[][][] loadBrain(String s) { public static double[][][] loadBrain(String s) {
float brainMap[][][] = null; double brainMap[][][] = null;
Log.log(Log.INFO, "Loading brain from String with " + s.split("\n").length + " lines"); Log.log(Log.INFO, "Loading brain from String with " + s.split("\n").length + " lines");
for (String l : s.split("\n")) { for (String l : s.split("\n")) {
l = l.trim(); l = l.trim();
@ -126,25 +126,25 @@ public class Serializer {
} else if (l.startsWith("Layers: ")) { } else if (l.startsWith("Layers: ")) {
// Set Layer number // Set Layer number
int layers = Integer.parseInt(l.split(" ")[1]) - 1; int layers = Integer.parseInt(l.split(" ")[1]) - 1;
brainMap = new float[layers][][]; brainMap = new double[layers][][];
Log.log(Log.INFO, "Loaded NLayers: " + layers); Log.log(Log.INFO, "Loaded NLayers: " + layers);
} else if (l.startsWith("Input Neurons")) { } else if (l.startsWith("Input Neurons")) {
int in = Integer.parseInt(l.split(" ")[2]); int in = Integer.parseInt(l.split(" ")[2]);
brainMap[0] = new float[in][0]; brainMap[0] = new double[in][0];
Log.log(Log.INFO, "Loaded NInputNeurons: " + in); Log.log(Log.INFO, "Loaded NInputNeurons: " + in);
} else if (l.startsWith("Layer ")) { } else if (l.startsWith("Layer ")) {
// Set neuron number for given layer // Set neuron number for given layer
String ll[] = l.split(" "); String ll[] = l.split(" ");
int layer = Integer.parseInt(ll[1]) - 2; int layer = Integer.parseInt(ll[1]) - 2;
int n = Integer.parseInt(ll[3]); int n = Integer.parseInt(ll[3]);
brainMap[layer] = new float[n][];//[layer>0?brainMap[layer-1].length:0]; brainMap[layer] = new double[n][];//[layer>0?brainMap[layer-1].length:0];
} else if (l.startsWith("Weights ")) { } else if (l.startsWith("Weights ")) {
// Set weights // Set weights
String ll[] = l.split(" "); String ll[] = l.split(" ");
int layer = Integer.parseInt(ll[3]) - 2; int layer = Integer.parseInt(ll[3]) - 2;
int neuron = Integer.parseInt(ll[5]) - 1; int neuron = Integer.parseInt(ll[5]) - 1;
int nWeights = ll.length - 7; int nWeights = ll.length - 7;
brainMap[layer][neuron] = new float[nWeights]; brainMap[layer][neuron] = new double[nWeights];
if (layer == 0) { if (layer == 0) {
Log.log(Log.DEBUG, "This weightmap is for brains with " + (nWeights) + " input neurons."); Log.log(Log.DEBUG, "This weightmap is for brains with " + (nWeights) + " input neurons.");
} else if (nWeights != brainMap[layer - 1].length) { } else if (nWeights != brainMap[layer - 1].length) {
@ -154,7 +154,7 @@ public class Serializer {
+ " weights are supplied to this neuron"); + " weights are supplied to this neuron");
} }
for (int i = 7; i < ll.length; i++) { for (int i = 7; i < ll.length; i++) {
brainMap[layer][neuron][i - 7] = Float.parseFloat(ll[i]); brainMap[layer][neuron][i - 7] = Double.parseDouble(ll[i]);
Log.log(Log.DEBUG, "Loading L" + layer + "N" + neuron + "W" + (i - 7) + " = " + brainMap[layer][neuron][i - 7]); Log.log(Log.DEBUG, "Loading L" + layer + "N" + neuron + "W" + (i - 7) + " = " + brainMap[layer][neuron][i - 7]);
} }
Log.log(Log.DEBUG, "Loaded " + (nWeights) + " Weights for Layer " + layer + " Neuron " + neuron); Log.log(Log.DEBUG, "Loaded " + (nWeights) + " Weights for Layer " + layer + " Neuron " + neuron);
@ -164,7 +164,7 @@ public class Serializer {
return brainMap; return brainMap;
} }
public static Map<String, Float> getDefaultSettings() { public static Map<String, Double> getDefaultSettings() {
if (defaults == null) { if (defaults == null) {
String s = "corpse_decay_rate = 0.0\n" String s = "corpse_decay_rate = 0.0\n"
+ "mutationFactor = 1.0\n" + "mutationFactor = 1.0\n"

View File

@ -9,7 +9,7 @@ import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
*/ */
public abstract class Element { public abstract class Element {
private float x, y, size; private double x, y, size;
/** /**
* Create an element at given position with given radius. Elements have a * Create an element at given position with given radius. Elements have a
@ -19,7 +19,7 @@ public abstract class Element {
* @param y the y position * @param y the y position
* @param size the element body radius * @param size the element body radius
*/ */
public Element(float x, float y, float size) { public Element(double x, double y, double size) {
this.x = x; this.x = x;
this.y = y; this.y = y;
this.size = size; this.size = size;
@ -35,8 +35,8 @@ public abstract class Element {
* @return the distance from the element. It's 0 if they are just touching, * @return the distance from the element. It's 0 if they are just touching,
* negative if they are colliding and positive if they are not * negative if they are colliding and positive if they are not
*/ */
public float distanceFrom(Element e) { public double distanceFrom(Element e) {
return (float) Math.sqrt(Math.pow(e.x - x, 2) + Math.pow(e.y - y, 2)) - getSize() - e.getSize(); return Math.sqrt(Math.pow(e.x - x, 2) + Math.pow(e.y - y, 2)) - getSize() - e.getSize();
} }
/** /**
@ -58,8 +58,8 @@ public abstract class Element {
* @param radius the radius of the circular object * @param radius the radius of the circular object
* @return true if the object overlaps this one * @return true if the object overlaps this one
*/ */
public boolean overlaps(float x, float y, float radius) { public boolean overlaps(double x, double y, double radius) {
return (float) Math.sqrt(Math.pow(x - this.x, 2) + Math.pow(y - this.y, 2)) < getSize() + radius; return Math.sqrt(Math.pow(x - this.x, 2) + Math.pow(y - this.y, 2)) < getSize() + radius;
} }
/** /**
@ -69,7 +69,7 @@ public abstract class Element {
* @param y the y position of the point to check * @param y the y position of the point to check
* @return true if the point is part of this object's area * @return true if the point is part of this object's area
*/ */
public boolean overlaps(float x, float y) { public boolean overlaps(double x, double y) {
return overlaps(x, y, 1); return overlaps(x, y, 1);
} }
@ -79,7 +79,7 @@ public abstract class Element {
* @param deltaX x translation * @param deltaX x translation
* @param deltaY y translation * @param deltaY y translation
*/ */
public void move(float deltaX, float deltaY) { public void move(double deltaX, double deltaY) {
x += deltaX; x += deltaX;
y += deltaY; y += deltaY;
} }
@ -96,27 +96,27 @@ public abstract class Element {
*/ */
public abstract void render(ShapeRenderer s); public abstract void render(ShapeRenderer s);
public float getX() { public double getX() {
return x; return x;
} }
public float getY() { public double getY() {
return y; return y;
} }
public float getSize() { public double getSize() {
return size; return size;
} }
public void setX(float x) { public void setX(double x) {
this.x = x; this.x = x;
} }
public void setY(float y) { public void setY(double y) {
this.y = y; this.y = y;
} }
public void setSize(float size) { public void setSize(double size) {
this.size = size; this.size = size;
} }

View File

@ -9,10 +9,10 @@ import com.mygdx.game.Game;
*/ */
public class Vegetable extends Element { public class Vegetable extends Element {
public static float default_radius = 5; public static double default_radius = 5;
private float decayRate = 0; private double decayRate = 0;
public Vegetable(float x, float y) { public Vegetable(double x, double y) {
super(x, y, default_radius); super(x, y, default_radius);
} }
@ -27,14 +27,14 @@ public class Vegetable extends Element {
@Override @Override
public void render(ShapeRenderer s) { public void render(ShapeRenderer s) {
s.setColor(1, 1, 1, 1); s.setColor(1, 1, 1, 1);
s.circle(getX(), getY(), getSize()); s.circle((float) getX(), (float) getY(), (float) getSize());
} }
public float getDecayRate() { public double getDecayRate() {
return decayRate; return decayRate;
} }
public void setDecayRate(float decayRate) { public void setDecayRate(double decayRate) {
this.decayRate = decayRate; this.decayRate = decayRate;
} }
} }

View File

@ -30,11 +30,11 @@ import logic.neural.Brain;
public class World implements Runnable { public class World implements Runnable {
private int width, height, nPlants, creatPerGen; private int width, height, nPlants, creatPerGen;
private float nMutatedBrains = 0.2f, nMutatedNeurons = 0.5f, nMutatedConnections = 0.5f, mutationFactor = 1f; private double nMutatedBrains = 0.2f, nMutatedNeurons = 0.5f, nMutatedConnections = 0.5f, mutationFactor = 1f;
private int generation = 1; private int generation = 1;
private boolean multithreading, cmdLaunchNewGen = false, cmdRestart = false; private boolean multithreading, cmdLaunchNewGen = false, cmdRestart = false;
private int fpsLimit, fps = 0; private int fpsLimit, fps = 0;
private Map<String, Float> options; private Map<String, Double> options;
private long ticksSinceGenStart = 0, maximumTicksPerGen = 0; private long ticksSinceGenStart = 0, maximumTicksPerGen = 0;
private Creature selected; private Creature selected;
private Queue<Integer> events = new LinkedList<>(); private Queue<Integer> events = new LinkedList<>();
@ -52,9 +52,9 @@ public class World implements Runnable {
* @param options customization options. Can be null. See the * @param options customization options. Can be null. See the
* "reloadOptions" function for possible options * "reloadOptions" function for possible options
*/ */
public World(Map<String, Float> options) { public World(Map<String, Double> options) {
if (options == null) { if (options == null) {
this.options = new HashMap<String, Float>(); this.options = new HashMap<String, Double>();
} else { } else {
this.options = options; this.options = options;
} }
@ -224,7 +224,7 @@ public class World implements Runnable {
} }
Creature[] top = new Creature[topSize]; Creature[] top = new Creature[topSize];
// Calculate avg fitness and prepare best agent list // Calculate avg fitness and prepare best agent list
float avgFitness = 0; double avgFitness = 0;
for (int i = 0; i < graveyard.size(); i++) { for (int i = 0; i < graveyard.size(); i++) {
Creature c = graveyard.get(i); Creature c = graveyard.get(i);
if (i < topSize) { if (i < topSize) {
@ -243,7 +243,7 @@ public class World implements Runnable {
while (sec == first && topSize > 1) { while (sec == first && topSize > 1) {
sec = (int) Math.floor(Math.random() * topSize); sec = (int) Math.floor(Math.random() * topSize);
} }
float[][][] n = null; double[][][] n = null;
try { try {
n = top[first].getBrain().breed(top[sec].getBrain().getMap()); n = top[first].getBrain().breed(top[sec].getBrain().getMap());
} catch (Exception ex) { } catch (Exception ex) {
@ -274,15 +274,15 @@ public class World implements Runnable {
*/ */
public void reloadOptions() { public void reloadOptions() {
for (Object o : Serializer.getDefaultSettings().entrySet().toArray()) { for (Object o : Serializer.getDefaultSettings().entrySet().toArray()) {
Map.Entry<String, Float> e = (Map.Entry<String, Float>) o; Map.Entry<String, Double> e = (Map.Entry<String, Double>) o;
options.putIfAbsent(e.getKey(), e.getValue()); options.putIfAbsent(e.getKey(), e.getValue());
} }
width = Math.round(options.get("world_width")); width = (int) Math.round(options.get("world_width"));
height = Math.round(options.get("world_height")); height = (int) Math.round(options.get("world_height"));
fpsLimit = Math.round(options.get("fps_limit")); fpsLimit = (int) Math.round(options.get("fps_limit"));
maximumTicksPerGen = Math.round(options.get("max_ticks")); maximumTicksPerGen = Math.round(options.get("max_ticks"));
creatPerGen = Math.round(options.get("number_of_creatures")); creatPerGen = (int) Math.round(options.get("number_of_creatures"));
nPlants = Math.round(options.get("number_of_plants")); nPlants = (int) Math.round(options.get("number_of_plants"));
multithreading = options.get("enable_multithreading") > 0; multithreading = options.get("enable_multithreading") > 0;
Creature.corpseDecayRate = options.get("corpse_decay_rate"); Creature.corpseDecayRate = options.get("corpse_decay_rate");
Creature.leaveCorpses = options.get("enable_corpses") > 0; Creature.leaveCorpses = options.get("enable_corpses") > 0;
@ -297,8 +297,8 @@ public class World implements Runnable {
Creature.hpForEatingPlants = options.get("creature_hp_for_eating_plants"); Creature.hpForEatingPlants = options.get("creature_hp_for_eating_plants");
Creature.pointsForAttacking = options.get("creature_points_for_attacking"); Creature.pointsForAttacking = options.get("creature_points_for_attacking");
Creature.pointsForEatingPlants = options.get("creature_points_for_eating_plants"); Creature.pointsForEatingPlants = options.get("creature_points_for_eating_plants");
Creature.brain_hidden_layers = Math.round(options.get("brain_hidden_layers")); Creature.brain_hidden_layers = (int) Math.round(options.get("brain_hidden_layers"));
Creature.brain_hidden_neurons = Math.round(options.get("brain_hidden_neurons")); Creature.brain_hidden_neurons = (int) Math.round(options.get("brain_hidden_neurons"));
Brain.bias = options.get("brain_bias"); Brain.bias = options.get("brain_bias");
nMutatedBrains = options.get("nMutatedBrains"); nMutatedBrains = options.get("nMutatedBrains");
nMutatedNeurons = options.get("nMutatedNeurons"); nMutatedNeurons = options.get("nMutatedNeurons");
@ -314,9 +314,9 @@ public class World implements Runnable {
* null, a random mind will be created * null, a random mind will be created
* @return the spawned element * @return the spawned element
*/ */
private Element spawn(boolean isCreature, float[][][] brainMap) { private Element spawn(boolean isCreature, double[][][] brainMap) {
int x, y; int x, y;
float r; double r;
boolean overlaps; boolean overlaps;
if (isCreature) { if (isCreature) {
r = Torso.default_radius; r = Torso.default_radius;
@ -394,7 +394,7 @@ public class World implements Runnable {
events.add(eventCode); events.add(eventCode);
} }
public Queue<Integer> getEventQueue(){ public Queue<Integer> getEventQueue() {
return events; return events;
} }
@ -406,7 +406,7 @@ public class World implements Runnable {
return (Creature) spawn(true, null); return (Creature) spawn(true, null);
} }
public Creature spawnCreature(float[][][] b) { public Creature spawnCreature(double[][][] b) {
return (Creature) spawn(true, b); return (Creature) spawn(true, b);
} }
@ -446,7 +446,7 @@ public class World implements Runnable {
return plants; return plants;
} }
public float getFpsLimit() { public double getFpsLimit() {
return fpsLimit; return fpsLimit;
} }
@ -454,11 +454,11 @@ public class World implements Runnable {
this.fpsLimit = fpsLimit; this.fpsLimit = fpsLimit;
} }
public float getFps() { public double getFps() {
return fps; return fps;
} }
public Map<String, Float> getOptions() { public Map<String, Double> getOptions() {
return options; return options;
} }
@ -478,7 +478,7 @@ public class World implements Runnable {
this.multithreading = multithreading; this.multithreading = multithreading;
} }
public void replaceOptions(Map<String, Float> options) { public void replaceOptions(Map<String, Double> options) {
this.options = options; this.options = options;
reloadOptions(); reloadOptions();
} }

View File

@ -14,18 +14,18 @@ import logic.Element;
*/ */
public class Beak extends BodyPart { public class Beak extends BodyPart {
private float length; private double length;
private boolean attacking = false; private boolean attacking = false;
public static float max_length = Torso.default_radius / 4, min_length = max_length / 4; public static double max_length = Torso.default_radius / 4, min_length = max_length / 4;
public Beak(float angle, Creature creature) { public Beak(double angle, Creature creature) {
super(3, 1, angle, 1, creature); super(3, 1, angle, 1, creature);
length = min_length; length = min_length;
} }
@Override @Override
public float[] act() { public double[] act() {
float r[] = new float[]{ double r[] = new double[]{
length / max_length, // current beak length length / max_length, // current beak length
length > max_length / 2 ? 1f : 0f, // wether the beak is doing damage length > max_length / 2 ? 1f : 0f, // wether the beak is doing damage
attacking ? 1f : 0f attacking ? 1f : 0f
@ -35,7 +35,7 @@ public class Beak extends BodyPart {
} }
@Override @Override
public void interactWithElement(Element e, float distance, float relAngle) { public void interactWithElement(Element e, double distance, double relAngle) {
if (e instanceof Creature && distance < length && length > max_length / 2 && Math.abs(relAngle) < 0.3f) { if (e instanceof Creature && distance < length && length > max_length / 2 && Math.abs(relAngle) < 0.3f) {
// Can attack // Can attack
creature.praise(Creature.pointsForAttacking); creature.praise(Creature.pointsForAttacking);
@ -46,10 +46,10 @@ public class Beak extends BodyPart {
} }
@Override @Override
protected void draw(ShapeRenderer s, float relX, float relY) { protected void draw(ShapeRenderer s, double relX, double relY) {
s.set(ShapeRenderer.ShapeType.Line); s.set(ShapeRenderer.ShapeType.Line);
// Draw Beak // Draw Beak
s.setColor(getLength() / Beak.max_length, 1 - getLength() / Beak.max_length, 0, 1); s.setColor((float) (getLength() / Beak.max_length), (float) (1 - getLength() / Beak.max_length), 0, 1);
s.line((float) (relX + creature.getX()), (float) (relY + creature.getY()), (float) (relX * (1.5f + getLength() / Beak.max_length) + creature.getX()), (float) (relY * (1.5f + getLength() / Beak.max_length) + creature.getY())); s.line((float) (relX + creature.getX()), (float) (relY + creature.getY()), (float) (relX * (1.5f + getLength() / Beak.max_length) + creature.getX()), (float) (relY * (1.5f + getLength() / Beak.max_length) + creature.getY()));
if (attacking) { if (attacking) {
s.circle((float) (relX * (1.5f + getLength() / Beak.max_length) + creature.getX()), (float) (relY * (1.5f + getLength() / Beak.max_length) + creature.getY()), 0.3f); s.circle((float) (relX * (1.5f + getLength() / Beak.max_length) + creature.getX()), (float) (relY * (1.5f + getLength() / Beak.max_length) + creature.getY()), 0.3f);
@ -57,7 +57,7 @@ public class Beak extends BodyPart {
} }
@Override @Override
public void readFromBrain(float[] outputs) { public void readFromBrain(double[] outputs) {
length = outputs[0] * max_length; length = outputs[0] * max_length;
if (length > max_length) { if (length > max_length) {
length = max_length; length = max_length;
@ -66,7 +66,7 @@ public class Beak extends BodyPart {
} }
} }
public float getLength() { public double getLength() {
return length; return length;
} }

View File

@ -12,8 +12,8 @@ import logic.Element;
public abstract class BodyPart { public abstract class BodyPart {
protected int inputNeuronsUsed; protected int inputNeuronsUsed;
protected float angle, distFromCenter; protected double angle, distFromCenter;
protected float outputs[]; protected double outputs[];
protected Creature creature; protected Creature creature;
/** /**
@ -26,12 +26,12 @@ public abstract class BodyPart {
* this body part * this body part
* @param creature the creature that owns this body part * @param creature the creature that owns this body part
*/ */
public BodyPart(int inputNeuronsUsed, int outputNeuronsUsed, float angle, float distFromCenter, Creature creature) { public BodyPart(int inputNeuronsUsed, int outputNeuronsUsed, double angle, double distFromCenter, Creature creature) {
this.inputNeuronsUsed = inputNeuronsUsed; this.inputNeuronsUsed = inputNeuronsUsed;
this.angle = angle; this.angle = angle;
this.distFromCenter = distFromCenter; this.distFromCenter = distFromCenter;
this.creature = creature; this.creature = creature;
outputs = new float[outputNeuronsUsed]; outputs = new double[outputNeuronsUsed];
} }
/** /**
@ -40,7 +40,7 @@ public abstract class BodyPart {
* *
* @return the data to send to the brain, must be inputNeuronsUsed long * @return the data to send to the brain, must be inputNeuronsUsed long
*/ */
public abstract float[] act(); public abstract double[] act();
/** /**
* Interact with another element. This will be called every time the body * Interact with another element. This will be called every time the body
@ -52,7 +52,7 @@ public abstract class BodyPart {
* @param distance the distance * @param distance the distance
* @param relAngle the relative angle * @param relAngle the relative angle
*/ */
public abstract void interactWithElement(Element e, float distance, float relAngle); public abstract void interactWithElement(Element e, double distance, double relAngle);
/** /**
* Receive some data from the brain. This is called once every frame, after * Receive some data from the brain. This is called once every frame, after
@ -61,7 +61,7 @@ public abstract class BodyPart {
* @param data the data received from the brain, will be outputNeuronsUsed * @param data the data received from the brain, will be outputNeuronsUsed
* long * long
*/ */
public abstract void readFromBrain(float data[]); public abstract void readFromBrain(double data[]);
/** /**
* This will be called when the * This will be called when the
@ -72,7 +72,7 @@ public abstract class BodyPart {
* @param relY the Y position of this bodypart relative to the center its * @param relY the Y position of this bodypart relative to the center its
* creature * creature
*/ */
protected abstract void draw(ShapeRenderer s, float relX, float relY); protected abstract void draw(ShapeRenderer s, double relX, double relY);
/** /**
* Prepares data and calls draw * Prepares data and calls draw
@ -82,7 +82,7 @@ public abstract class BodyPart {
public final void render(ShapeRenderer s) { public final void render(ShapeRenderer s) {
double relX = Math.cos(creature.getDirection() + angle) * creature.getTorso().getRadius() * distFromCenter; double relX = Math.cos(creature.getDirection() + angle) * creature.getTorso().getRadius() * distFromCenter;
double relY = Math.sin(creature.getDirection() + angle) * creature.getTorso().getRadius() * distFromCenter; double relY = Math.sin(creature.getDirection() + angle) * creature.getTorso().getRadius() * distFromCenter;
draw(s, (float) relX, (float) relY); draw(s, (double) relX, (double) relY);
} }
/** /**
@ -105,11 +105,11 @@ public abstract class BodyPart {
* *
* @return the angle of this bodypart relative to the center of the creature * @return the angle of this bodypart relative to the center of the creature
*/ */
public float getAngle() { public double getAngle() {
return angle; return angle;
} }
public float getDistanceFromCreatureCenter() { public double getDistanceFromCreatureCenter() {
return distFromCenter; return distFromCenter;
} }

View File

@ -20,13 +20,13 @@ import logic.neural.Brain;
public abstract class Creature extends Element implements Runnable { public abstract class Creature extends Element implements Runnable {
public static int brain_hidden_layers = 2, brain_hidden_neurons = 10; public static int brain_hidden_layers = 2, brain_hidden_neurons = 10;
public static float corpseDecayRate = 0, pointsForEatingPlants = 1f, pointsForAttacking = 2f, hpForAttacking = 1f, hpForEatingPlants = 1f; public static double corpseDecayRate = 0, pointsForEatingPlants = 1f, pointsForAttacking = 2f, hpForAttacking = 1f, hpForEatingPlants = 1f;
public static boolean leaveCorpses = false; public static boolean leaveCorpses = false;
private final Brain brain; private final Brain brain;
private final Torso torso; private final Torso torso;
private final ArrayList<BodyPart> bodyParts; private final ArrayList<BodyPart> bodyParts;
private float dir, fitness = 0; private double dir, fitness = 0;
private boolean workerDone = false, killWorker = false; private boolean workerDone = false, killWorker = false;
private Thread workerThread; private Thread workerThread;
@ -36,9 +36,9 @@ public abstract class Creature extends Element implements Runnable {
* @param x * @param x
* @param y * @param y
*/ */
public Creature(float x, float y) { public Creature(double x, double y) {
super(x, y, Torso.default_radius); super(x, y, Torso.default_radius);
dir = (float) (Math.random() * 2 * Math.PI); dir = (double) (Math.random() * 2 * Math.PI);
bodyParts = new ArrayList<BodyPart>(); bodyParts = new ArrayList<BodyPart>();
bodyParts.add(torso = new Torso(this)); bodyParts.add(torso = new Torso(this));
buildBody(); buildBody();
@ -77,10 +77,10 @@ public abstract class Creature extends Element implements Runnable {
return; return;
} }
// collect inputs // collect inputs
float values[] = new float[howManyInputNeurons()]; double values[] = new double[howManyInputNeurons()];
int i = 0; int i = 0;
for (BodyPart b : bodyParts) { for (BodyPart b : bodyParts) {
for (float v : b.act()) { for (double v : b.act()) {
values[i] = v; values[i] = v;
i++; i++;
} }
@ -88,7 +88,7 @@ public abstract class Creature extends Element implements Runnable {
// read from sensors and interact with world // read from sensors and interact with world
interactWithWorld(); interactWithWorld();
// compute behavior // compute behavior
float[] actions = null; double[] actions = null;
try { try {
actions = brain.compute(values); actions = brain.compute(values);
} catch (Exception ex) { } catch (Exception ex) {
@ -99,7 +99,7 @@ public abstract class Creature extends Element implements Runnable {
// Save brain outputs to body parts // Save brain outputs to body parts
for (BodyPart b : bodyParts) { for (BodyPart b : bodyParts) {
int n = 0; int n = 0;
float data[] = new float[b.getOutputNeuronsUsed()]; double data[] = new double[b.getOutputNeuronsUsed()];
while (n < b.getOutputNeuronsUsed()) { while (n < b.getOutputNeuronsUsed()) {
data[n] = actions[i]; data[n] = actions[i];
i++; i++;
@ -122,8 +122,8 @@ public abstract class Creature extends Element implements Runnable {
*/ */
public void interactWithWorld() { public void interactWithWorld() {
for (Element e : Game.get().getWorld().getElements()) { for (Element e : Game.get().getWorld().getElements()) {
float distance = distanceFrom(e); double distance = distanceFrom(e);
float angle = (float) (Math.atan2(getY() - e.getY(), getX() - e.getX())) - (dir - (float) Math.PI); double angle = (double) (Math.atan2(getY() - e.getY(), getX() - e.getX())) - (dir - (double) Math.PI);
for (BodyPart b : bodyParts) { for (BodyPart b : bodyParts) {
b.interactWithElement(e, distance, angle); b.interactWithElement(e, distance, angle);
} }
@ -146,7 +146,7 @@ public abstract class Creature extends Element implements Runnable {
return n; return n;
} }
public void rotate(float amount) { public void rotate(double amount) {
dir += amount; dir += amount;
if (dir > 2 * Math.PI) { if (dir > 2 * Math.PI) {
dir -= 2 * Math.PI; dir -= 2 * Math.PI;
@ -161,7 +161,7 @@ public abstract class Creature extends Element implements Runnable {
* *
* @param amount how much * @param amount how much
*/ */
public void praise(float amount) { public void praise(double amount) {
fitness += amount; fitness += amount;
} }
@ -189,9 +189,9 @@ public abstract class Creature extends Element implements Runnable {
} }
} }
public float getDangerLevel() { public double getDangerLevel() {
int beaks = 0; int beaks = 0;
float danger = 0; double danger = 0;
for (BodyPart b : bodyParts) { for (BodyPart b : bodyParts) {
if (b instanceof Beak) { if (b instanceof Beak) {
beaks++; beaks++;
@ -217,15 +217,15 @@ public abstract class Creature extends Element implements Runnable {
return brain; return brain;
} }
public void setDirection(float dir) { public void setDirection(double dir) {
this.dir = dir; this.dir = dir;
} }
public float getDirection() { public double getDirection() {
return dir; return dir;
} }
public float getFitness() { public double getFitness() {
return fitness; return fitness;
} }

View File

@ -19,18 +19,18 @@ public class Eye extends BodyPart {
private Sight sights[]; private Sight sights[];
private int farthest = -1, seen; private int farthest = -1, seen;
private float farthestDistance = 0; private double farthestDistance = 0;
public static float fov = 2, sightRange = 30; public static double fov = 2, sightRange = 30;
public Eye(int nSights, float angle, Creature creature) { public Eye(int nSights, double angle, Creature creature) {
super(6 * nSights, 0, angle, 0.8f, creature); super(6 * nSights, 0, angle, 0.8f, creature);
sights = new Sight[nSights]; sights = new Sight[nSights];
seen = 0; seen = 0;
} }
@Override @Override
public float[] act() { public double[] act() {
float ret[] = new float[inputNeuronsUsed]; double ret[] = new double[inputNeuronsUsed];
int j = 0; int j = 0;
for (int i = 0; i < sights.length; i++) { for (int i = 0; i < sights.length; i++) {
if (i < seen) { if (i < seen) {
@ -62,7 +62,7 @@ public class Eye extends BodyPart {
} }
@Override @Override
public void interactWithElement(Element e, float distance, float angle) { public void interactWithElement(Element e, double distance, double angle) {
if (e != creature && distance < sightRange && (distance < farthestDistance || seen < sights.length) && Math.abs(angle) < fov / 2) { if (e != creature && distance < sightRange && (distance < farthestDistance || seen < sights.length) && Math.abs(angle) < fov / 2) {
if (seen < sights.length) { if (seen < sights.length) {
sights[seen] = new Sight(e, distance, angle); sights[seen] = new Sight(e, distance, angle);
@ -85,36 +85,36 @@ public class Eye extends BodyPart {
} }
@Override @Override
protected void draw(ShapeRenderer s, float relX, float relY) { protected void draw(ShapeRenderer s, double relX, double relY) {
// Draw eye // Draw eye
s.setColor(1, 1, 1, 1); s.setColor(1, 1, 1, 1);
s.circle(creature.getX() + relX, creature.getY() + relY, 3); s.circle((float) (creature.getX() + relX), (float) (creature.getY() + relY), 3);
// Draw FOV cone // Draw FOV cone
float degrees = fov * 360f / (float) Math.PI; double degrees = fov * 360f / (double) Math.PI;
float orient = (creature.getDirection() + angle) * 180f / (float) Math.PI - degrees / 2; double orient = (creature.getDirection() + angle) * 180f / (double) Math.PI - degrees / 2;
if (Game.get().getWorld().getOptions().getOrDefault("draw_view_cones", 0f) > 0) { if (Game.get().getWorld().getOptions().getOrDefault("draw_view_cones", 0d) > 0) {
s.setColor(0.3f, 0.3f, 0.3f, 1); s.setColor(0.3f, 0.3f, 0.3f, 1);
s.arc((float) relX + creature.getX(), (float) relY + creature.getY(), sightRange, orient, degrees); s.arc((float) (relX + creature.getX()), (float) (relY + creature.getY()), (float) sightRange, (float) orient, (float) degrees);
} }
// Sight Lines // Sight Lines
float c = 0; double c = 0;
if (Game.get().getWorld().getOptions().getOrDefault("draw_sight_lines", 0f) > 0) { if (Game.get().getWorld().getOptions().getOrDefault("draw_sight_lines", 0d) > 0) {
for (Sight sight : sights) { for (Sight sight : sights) {
if (sight != null) { if (sight != null) {
c = sight.getDistance() / sightRange * 2 + sightRange; c = sight.getDistance() / sightRange * 2 + sightRange;
if (sight.getElement() instanceof Creature) { if (sight.getElement() instanceof Creature) {
s.setColor(c, 0, 0, 1); s.setColor((float) c, 0, 0, 1);
} else if (sight.getElement() instanceof Vegetable) { } else if (sight.getElement() instanceof Vegetable) {
s.setColor(0, c, 0, 1); s.setColor(0, (float) c, 0, 1);
} }
s.line(relX + creature.getX(), creature.getY() + relY, sight.getElement().getX(), sight.getElement().getY()); s.line((float) (relX + creature.getX()), (float) (creature.getY() + relY), (float) (sight.getElement().getX()), (float) (sight.getElement().getY()));
} }
} }
} }
} }
@Override @Override
public void readFromBrain(float[] data) { public void readFromBrain(double[] data) {
} }
} }

View File

@ -16,15 +16,15 @@ import logic.Element;
*/ */
public class Movement extends BodyPart { public class Movement extends BodyPart {
private float speed = 0, rotSpeed = 0; private double speed = 0, rotSpeed = 0;
public static float max_speed = 3; public static double max_speed = 3;
public Movement(Creature creature) { public Movement(Creature creature) {
super(0, 4, 0, 0, creature); super(0, 4, 0, 0, creature);
} }
@Override @Override
public float[] act() { public double[] act() {
if (speed > max_speed) { if (speed > max_speed) {
speed = max_speed; speed = max_speed;
} }
@ -32,7 +32,7 @@ public class Movement extends BodyPart {
speed = -max_speed; speed = -max_speed;
} }
// apply speed // apply speed
float xMul = (float) Math.cos(creature.getDirection()), yMul = (float) Math.sin(creature.getDirection()); double xMul = (double) Math.cos(creature.getDirection()), yMul = (double) Math.sin(creature.getDirection());
creature.move(xMul * speed, yMul * speed); creature.move(xMul * speed, yMul * speed);
if (creature.getX() < 0) { if (creature.getX() < 0) {
creature.setX(Game.get().getWorld().getWidth() + creature.getX()); creature.setX(Game.get().getWorld().getWidth() + creature.getX());
@ -45,19 +45,19 @@ public class Movement extends BodyPart {
creature.setY(creature.getY() - Game.get().getWorld().getHeight()); creature.setY(creature.getY() - Game.get().getWorld().getHeight());
} }
creature.rotate(rotSpeed); creature.rotate(rotSpeed);
return new float[]{}; return new double[]{};
} }
@Override @Override
public void interactWithElement(Element e, float distance, float relAngle) { public void interactWithElement(Element e, double distance, double relAngle) {
} }
@Override @Override
protected void draw(ShapeRenderer s, float relX, float relY) { protected void draw(ShapeRenderer s, double relX, double relY) {
} }
@Override @Override
public void readFromBrain(float[] data) { public void readFromBrain(double[] data) {
Log.log(Log.DEBUG, "Fowward: " + data[0] + "Back: " + data[1] + " Rot: " + data[2] + " RotAnti: " + data[3]); Log.log(Log.DEBUG, "Fowward: " + data[0] + "Back: " + data[1] + " Rot: " + data[2] + " RotAnti: " + data[3]);
speed = (data[0] * 2 - data[1] / 2) * max_speed; speed = (data[0] * 2 - data[1] / 2) * max_speed;
rotSpeed = data[2] - data[3]; rotSpeed = data[2] - data[3];

View File

@ -10,9 +10,9 @@ import logic.Element;
public class Sight { public class Sight {
private Element seen; private Element seen;
private float distance, angle; private double distance, angle;
public Sight(Element seen, float distance, float angle) { public Sight(Element seen, double distance, double angle) {
this.seen = seen; this.seen = seen;
this.distance = distance; this.distance = distance;
this.angle = angle; this.angle = angle;
@ -22,11 +22,11 @@ public class Sight {
return seen; return seen;
} }
public float getDistance() { public double getDistance() {
return distance; return distance;
} }
public float getAngle() { public double getAngle() {
return angle; return angle;
} }

View File

@ -10,8 +10,8 @@ import logic.Vegetable;
*/ */
public class Torso extends BodyPart { public class Torso extends BodyPart {
private float hp, prevHp, radius, pain = 0; private double hp, prevHp, radius, pain = 0;
public static float default_radius = 20, max_hp = 100, hpDecay = 0.5f, eatingSpeed = 0.1f; public static double default_radius = 20, max_hp = 100, hpDecay = 0.5f, eatingSpeed = 0.1f;
private boolean eating = false; private boolean eating = false;
public Torso(Creature c) { public Torso(Creature c) {
@ -22,9 +22,9 @@ public class Torso extends BodyPart {
} }
@Override @Override
public void draw(ShapeRenderer s, float x, float y) { public void draw(ShapeRenderer s, double x, double y) {
s.setColor(1 - (hp / max_hp), hp / max_hp, 0, 1); s.setColor((float) (1 - (hp / max_hp)), (float) (hp / max_hp), 0, 1);
s.circle(x + creature.getX(), y + creature.getY(), radius); s.circle((float) (x + creature.getX()), (float) (y + creature.getY()), (float) radius);
// Draw damage/heal marks // Draw damage/heal marks
s.set(ShapeRenderer.ShapeType.Filled); s.set(ShapeRenderer.ShapeType.Filled);
if (getReceivedDamage() > 0) { if (getReceivedDamage() > 0) {
@ -35,15 +35,15 @@ public class Torso extends BodyPart {
s.setColor(0, 1, 0, 1); s.setColor(0, 1, 0, 1);
} }
if (getReceivedDamage() != 0 || eating) { if (getReceivedDamage() != 0 || eating) {
s.circle(x + creature.getX(), y + creature.getY(), 5); s.circle((float) (x + creature.getX()), (float) (y + creature.getY()), 5);
} }
} }
@Override @Override
public float[] act() { public double[] act() {
// apply hunger // apply hunger
hp -= hpDecay; hp -= hpDecay;
float r[] = new float[]{ double r[] = new double[]{
hp/max_hp, hp/max_hp,
eating ? 1f : 0f, eating ? 1f : 0f,
pain pain
@ -55,7 +55,7 @@ public class Torso extends BodyPart {
} }
@Override @Override
public void interactWithElement(Element e, float distance, float relAngle) { public void interactWithElement(Element e, double distance, double relAngle) {
if (e instanceof Vegetable && distance < 0 && hp < max_hp) { if (e instanceof Vegetable && distance < 0 && hp < max_hp) {
e.setSize(e.getSize() - eatingSpeed); e.setSize(e.getSize() - eatingSpeed);
if (e.getSize() == 0) { if (e.getSize() == 0) {
@ -68,7 +68,7 @@ public class Torso extends BodyPart {
} }
@Override @Override
public void readFromBrain(float[] data) { public void readFromBrain(double[] data) {
if (getReceivedDamage() > 0) { if (getReceivedDamage() > 0) {
pain = -1; pain = -1;
} else if (getReceivedDamage() < 0) { } else if (getReceivedDamage() < 0) {
@ -87,7 +87,7 @@ public class Torso extends BodyPart {
* *
* @param amount how much to heal/damage * @param amount how much to heal/damage
*/ */
public void heal(float amount) { public void heal(double amount) {
hp += amount; hp += amount;
if (hp < 0) { if (hp < 0) {
hp = 0; hp = 0;
@ -97,23 +97,23 @@ public class Torso extends BodyPart {
} }
} }
public float getReceivedDamage() { public double getReceivedDamage() {
return prevHp - hp; return prevHp - hp;
} }
public float getRadius() { public double getRadius() {
return radius; return radius;
} }
public void setRadius(float radius) { public void setRadius(double radius) {
this.radius = radius; this.radius = radius;
} }
public float getHp() { public double getHp() {
return hp; return hp;
} }
public void setHp(float hp) { public void setHp(double hp) {
this.hp = hp; this.hp = hp;
} }

View File

@ -11,7 +11,7 @@ import com.mygdx.game.Serializer;
*/ */
public class Brain { public class Brain {
public static float bias = 0.5f; public static double bias = 0.5f;
private Neuron[][] neurons; private Neuron[][] neurons;
private String name; private String name;
@ -41,7 +41,7 @@ public class Brain {
* *
* @param brainMap the new brain map to apply * @param brainMap the new brain map to apply
*/ */
public void remap(float[][][] brainMap) { public void remap(double[][][] brainMap) {
for (int i = 0; i < brainMap.length; i++) { // for each layer (skip input) for (int i = 0; i < brainMap.length; i++) { // for each layer (skip input)
for (int j = 0; j < brainMap[i].length; j++) { // for each neuron for (int j = 0; j < brainMap[i].length; j++) { // for each neuron
// skip input layer // skip input layer
@ -89,17 +89,17 @@ public class Brain {
//s.set(ShapeRenderer.ShapeType.Line); //s.set(ShapeRenderer.ShapeType.Line);
for (int j = 0; j < neurons[i].length; j++) { for (int j = 0; j < neurons[i].length; j++) {
// get neuron result first so cache system can kick in and save some calculations // get neuron result first so cache system can kick in and save some calculations
float nr = neurons[i][j].compute(); double nr = neurons[i][j].compute();
// Draw neuron links // Draw neuron links
float[] links = neurons[i][j].getWeights(); double[] links = neurons[i][j].getWeights();
if (links != null) { if (links != null) {
for (int f = 0; f < links.length; f++) { for (int f = 0; f < links.length; f++) {
s.setColor(links[f] < 0 ? links[f] / 2 * -1 : 0, links[f] > 0 ? links[f] / 2 : 0, 0, 1); s.setColor((float) (links[f] < 0 ? links[f] / 2 * -1 : 0), (float) (links[f] > 0 ? links[f] / 2 : 0), 0, 1);
s.line(i * sepX + offset, j * sepY + offset, (i - 1) * sepX + offset, f * sepY + offset); s.line(i * sepX + offset, j * sepY + offset, (i - 1) * sepX + offset, f * sepY + offset);
} }
} }
// Draw neuron // Draw neuron
s.setColor(1 - nr, nr, 0, 1); s.setColor((float) (1 - nr), (float) nr, 0, 1);
s.circle(i * sepX + offset, j * sepY + offset, 15); s.circle(i * sepX + offset, j * sepY + offset, 15);
} }
} }
@ -113,7 +113,7 @@ public class Brain {
* @throws Exception if the number of inputs given differs from the number * @throws Exception if the number of inputs given differs from the number
* of input neurons of this brain * of input neurons of this brain
*/ */
public void input(float[] values) throws Exception { public void input(double[] values) throws Exception {
if (values.length != neurons[0].length) { if (values.length != neurons[0].length) {
throw new Exception("Brain has " + neurons[0].length throw new Exception("Brain has " + neurons[0].length
+ " input neurons," + " but was supplied with " + " input neurons," + " but was supplied with "
@ -130,9 +130,9 @@ public class Brain {
* @return an array as long as the number of output neurons, containing the * @return an array as long as the number of output neurons, containing the
* result * result
*/ */
public float[] compute() { public double[] compute() {
clearCache(); // unnecessary if already called when changing inputs clearCache(); // unnecessary if already called when changing inputs
float[] res = new float[neurons[neurons.length - 1].length]; double[] res = new double[neurons[neurons.length - 1].length];
for (int i = 0; i < neurons[neurons.length - 1].length; i++) { for (int i = 0; i < neurons[neurons.length - 1].length; i++) {
res[i] = neurons[neurons.length - 1][i].compute(); res[i] = neurons[neurons.length - 1][i].compute();
} }
@ -147,7 +147,7 @@ public class Brain {
* @throws Exception if the number of inputs given differs from the number * @throws Exception if the number of inputs given differs from the number
* of input neurons of this brain * of input neurons of this brain
*/ */
public float[] compute(float[] values) throws Exception { public double[] compute(double[] values) throws Exception {
input(values); input(values);
return compute(); return compute();
} }
@ -158,11 +158,11 @@ public class Brain {
* @return a tridimensional floating point number array representing a full * @return a tridimensional floating point number array representing a full
* mind * mind
*/ */
public float[][][] getMap() { public double[][][] getMap() {
float[][][] res = new float[neurons.length - 1][][]; double[][][] res = new double[neurons.length - 1][][];
for (int i = 1; i < neurons.length; i++) // layers (skip input layer) for (int i = 1; i < neurons.length; i++) // layers (skip input layer)
{ {
res[i - 1] = new float[neurons[i].length][]; res[i - 1] = new double[neurons[i].length][];
for (int j = 0; j < neurons[i].length; j++) // neurons per layer for (int j = 0; j < neurons[i].length; j++) // neurons per layer
{ {
res[i - 1][j] = neurons[i][j].getWeights(); res[i - 1][j] = neurons[i][j].getWeights();
@ -181,11 +181,11 @@ public class Brain {
* of mutated neurons (range: from 0 to 1) * of mutated neurons (range: from 0 to 1)
* @return a mutated brain map of this brain's mind * @return a mutated brain map of this brain's mind
*/ */
public float[][][] getMutatedMap(float mutationProbability, float connectionMutationProbability, float mutationFactor) { public double[][][] getMutatedMap(double mutationProbability, double connectionMutationProbability, double mutationFactor) {
float[][][] res = new float[neurons.length - 1][][]; double[][][] res = new double[neurons.length - 1][][];
for (int i = 1; i < neurons.length; i++) // layers (skip input layer) for (int i = 1; i < neurons.length; i++) // layers (skip input layer)
{ {
res[i - 1] = new float[neurons[i].length][]; res[i - 1] = new double[neurons[i].length][];
for (int j = 0; j < neurons[i].length; j++) // neurons per layer for (int j = 0; j < neurons[i].length; j++) // neurons per layer
{ {
if (Math.random() <= mutationProbability) { if (Math.random() <= mutationProbability) {
@ -205,7 +205,7 @@ public class Brain {
* of mutated neurons (range: from 0 to 1) * of mutated neurons (range: from 0 to 1)
* @param mutationFactor the higher this number, the bigger the mutation * @param mutationFactor the higher this number, the bigger the mutation
*/ */
public void mutate(float mutationProbability, float connectionMutationProbability, float mutationFactor) { public void mutate(double mutationProbability, double connectionMutationProbability, double mutationFactor) {
for (int i = 1; i < neurons.length; i++) // layers (skip input layer) for (int i = 1; i < neurons.length; i++) // layers (skip input layer)
{ {
for (int j = 0; j < neurons[i].length; j++) // neurons per layer for (int j = 0; j < neurons[i].length; j++) // neurons per layer
@ -228,20 +228,20 @@ public class Brain {
* @throws Exception if the brains don't have identical neuron and layer * @throws Exception if the brains don't have identical neuron and layer
* numbers * numbers
*/ */
public float[][][] breed(float[][][] map) throws Exception { public double[][][] breed(double[][][] map) throws Exception {
float[][][] res = new float[neurons.length - 1][][]; double[][][] res = new double[neurons.length - 1][][];
if (map.length != neurons.length - 1) { if (map.length != neurons.length - 1) {
throw new Exception("incompatible brains"); throw new Exception("incompatible brains");
} }
for (int i = 1; i < neurons.length; i++) // layers (skip input layer) for (int i = 1; i < neurons.length; i++) // layers (skip input layer)
{ {
res[i - 1] = new float[neurons[i].length][]; res[i - 1] = new double[neurons[i].length][];
if (map[i - 1].length != neurons[i].length) { if (map[i - 1].length != neurons[i].length) {
throw new Exception("incompatible brains"); throw new Exception("incompatible brains");
} }
for (int j = 0; j < neurons[i].length; j++) // neurons per layer for (int j = 0; j < neurons[i].length; j++) // neurons per layer
{ {
res[i - 1][j] = new float[neurons[i][j].getWeights().length]; res[i - 1][j] = new double[neurons[i][j].getWeights().length];
if (map[i - 1][j].length != neurons[i][j].getWeights().length) { if (map[i - 1][j].length != neurons[i][j].getWeights().length) {
throw new Exception("incompatible brains"); throw new Exception("incompatible brains");
} }

View File

@ -11,9 +11,9 @@ import java.util.logging.Logger;
*/ */
public class Neuron { public class Neuron {
private float[] weights; private double[] weights;
private NeuronCache cache; private NeuronCache cache;
private float bias, output; private double bias, output;
private boolean isInputNeuron; private boolean isInputNeuron;
private int layer, receivesFromLayer; private int layer, receivesFromLayer;
private Brain brain; private Brain brain;
@ -28,7 +28,7 @@ public class Neuron {
* neurons) * neurons)
* @param brain the brain which contains this neuron * @param brain the brain which contains this neuron
*/ */
public Neuron(int layer, int receivesFromLayer, float bias, Brain brain) { public Neuron(int layer, int receivesFromLayer, double bias, Brain brain) {
this(layer, receivesFromLayer, bias, brain, null); this(layer, receivesFromLayer, bias, brain, null);
} }
@ -43,7 +43,7 @@ public class Neuron {
* @param brain the brain which contains this neuron * @param brain the brain which contains this neuron
* @param weights the weights to use to configure this neuron * @param weights the weights to use to configure this neuron
*/ */
public Neuron(int layer, int receivesFromLayer, float bias, Brain brain, float[] weights) { public Neuron(int layer, int receivesFromLayer, double bias, Brain brain, double[] weights) {
this.brain = brain; this.brain = brain;
this.layer = layer; this.layer = layer;
this.receivesFromLayer = receivesFromLayer; this.receivesFromLayer = receivesFromLayer;
@ -65,14 +65,14 @@ public class Neuron {
private void scramble() { private void scramble() {
// init weights // init weights
if (layer > 0) { if (layer > 0) {
weights = new float[brain.getNeurons()[receivesFromLayer].length]; weights = new double[brain.getNeurons()[receivesFromLayer].length];
} else { // layer 0 or negative } else { // layer 0 or negative
isInputNeuron = true; isInputNeuron = true;
weights = new float[0]; weights = new double[0];
} }
// Put random weights // Put random weights
for (int i = 0; i < weights.length; i++) { for (int i = 0; i < weights.length; i++) {
weights[i] = (float) (Math.random() * 5 - 2.5f); weights[i] = (double) (Math.random() * 5 - 2.5f);
} }
} }
@ -84,7 +84,7 @@ public class Neuron {
* *
* @return the output of this neuron. * @return the output of this neuron.
*/ */
public float compute() { public double compute() {
if (weights == null || weights.length == 0) { if (weights == null || weights.length == 0) {
isInputNeuron = true; isInputNeuron = true;
} }
@ -94,7 +94,7 @@ public class Neuron {
if (cache.hasCachedOutput()) { if (cache.hasCachedOutput()) {
return cache.getCachedOutput(); return cache.getCachedOutput();
} }
float a = bias * -1; // activation double a = bias * -1; // activation
for (int i = 0; i < weights.length; i++) { for (int i = 0; i < weights.length; i++) {
if (cache.has(i)) { if (cache.has(i)) {
try { try {
@ -105,13 +105,13 @@ public class Neuron {
} }
} else { } else {
Neuron n = brain.getNeurons()[receivesFromLayer][i]; Neuron n = brain.getNeurons()[receivesFromLayer][i];
float v = n.compute() * weights[i]; double v = n.compute() * weights[i];
a += v; a += v;
cache.put(i, v); cache.put(i, v);
} }
} }
// sigmoid function // sigmoid function
float res = (float) (1 / (1 + Math.pow(Math.E, a * -1))); double res = (double) (1 / (1 + Math.pow(Math.E, a * -1)));
cache.setCachedOutput(res); cache.setCachedOutput(res);
Log.log(Log.DEBUG, "Computed Value " + res + " for neuron"); Log.log(Log.DEBUG, "Computed Value " + res + " for neuron");
return res; return res;
@ -124,11 +124,11 @@ public class Neuron {
* @param mutationFactor controls how much weights mutate * @param mutationFactor controls how much weights mutate
* @return the new weights * @return the new weights
*/ */
public float[] getMutatedWeights(float mutationProbability, float mutationFactor) { public double[] getMutatedWeights(double mutationProbability, double mutationFactor) {
float[] mutatedWeights = new float[weights.length]; double[] mutatedWeights = new double[weights.length];
for (int i = 0; i < weights.length; i++) { for (int i = 0; i < weights.length; i++) {
if (Math.random() <= mutationProbability) { if (Math.random() <= mutationProbability) {
mutatedWeights[i] = weights[i] + (float) (Math.random() * mutationFactor) - mutationFactor / 2; mutatedWeights[i] = weights[i] + (double) (Math.random() * mutationFactor) - mutationFactor / 2;
} else { } else {
mutatedWeights[i] = weights[i]; mutatedWeights[i] = weights[i];
} }
@ -141,16 +141,16 @@ public class Neuron {
* *
* @param output the output you want to set * @param output the output you want to set
*/ */
public void setOutput(float output) { public void setOutput(double output) {
isInputNeuron = true; isInputNeuron = true;
this.output = output; this.output = output;
} }
public float getBias() { public double getBias() {
return bias; return bias;
} }
public void setBias(float bias) { public void setBias(double bias) {
this.bias = bias; this.bias = bias;
} }
@ -166,7 +166,7 @@ public class Neuron {
this.layer = layer; this.layer = layer;
} }
public float[] getWeights() { public double[] getWeights() {
return weights; return weights;
} }
@ -175,7 +175,7 @@ public class Neuron {
* *
* @param weights the new weights to put * @param weights the new weights to put
*/ */
public void setWeights(float[] weights) { public void setWeights(double[] weights) {
this.weights = weights; this.weights = weights;
// Changing the neuron makes the cache invalid // Changing the neuron makes the cache invalid
clearCache(); clearCache();

View File

@ -7,8 +7,8 @@ package logic.neural;
*/ */
public class NeuronCache { public class NeuronCache {
private float[] cache; private double[] cache;
private float cachedOutput; private double cachedOutput;
private boolean cachedOutputValid; private boolean cachedOutputValid;
private boolean[] validity; private boolean[] validity;
@ -18,7 +18,7 @@ public class NeuronCache {
* @param size how many inputs the requiring neuron has. * @param size how many inputs the requiring neuron has.
*/ */
public NeuronCache(int size) { public NeuronCache(int size) {
cache = new float[size]; cache = new double[size];
validity = new boolean[size]; validity = new boolean[size];
clear(); clear();
} }
@ -29,7 +29,7 @@ public class NeuronCache {
* @param index the index of the value * @param index the index of the value
* @param value the value itself * @param value the value itself
*/ */
public void put(int index, float value) { public void put(int index, double value) {
validity[index] = true; validity[index] = true;
cache[index] = value; cache[index] = value;
} }
@ -41,7 +41,7 @@ public class NeuronCache {
* @return the value required * @return the value required
* @throws Exception if value not stored or declared invalid * @throws Exception if value not stored or declared invalid
*/ */
public float get(int index) throws Exception { public double get(int index) throws Exception {
if (validity[index]) { if (validity[index]) {
return cache[index]; return cache[index];
} else { } else {
@ -59,7 +59,7 @@ public class NeuronCache {
return validity[index]; return validity[index];
} }
public float getCachedOutput() { public double getCachedOutput() {
return cachedOutput; return cachedOutput;
} }
@ -67,7 +67,7 @@ public class NeuronCache {
return cachedOutputValid; return cachedOutputValid;
} }
public void setCachedOutput(float cachedOutput) { public void setCachedOutput(double cachedOutput) {
this.cachedOutput = cachedOutput; this.cachedOutput = cachedOutput;
} }

View File

@ -49,7 +49,7 @@ public class GUI extends javax.swing.JFrame implements LogListener {
private boolean shouldUpdateGUI = false; private boolean shouldUpdateGUI = false;
private final Thread guiUpdater; private final Thread guiUpdater;
private final Listener listener; private final Listener listener;
private Map<String, Float> options; private Map<String, Double> options;
private boolean updatingSliders = false, updatingTable = false; private boolean updatingSliders = false, updatingTable = false;
/** /**
@ -67,7 +67,7 @@ public class GUI extends javax.swing.JFrame implements LogListener {
updateGUI(); updateGUI();
} }
}; };
options = new HashMap<String, Float>(); options = new HashMap<String, Double>();
world = new World(options); world = new World(options);
updateSettingsUI(); updateSettingsUI();
settingsTable.getModel().addTableModelListener(new TableModelListener() { settingsTable.getModel().addTableModelListener(new TableModelListener() {
@ -965,25 +965,25 @@ public class GUI extends javax.swing.JFrame implements LogListener {
*/ */
private void saveSliderChanges() { private void saveSliderChanges() {
if (!updatingSliders) { if (!updatingSliders) {
options.put("fps_limit", toggleFPSLimitCheckbox.isSelected() ? 0 : (float) fpsLimitSlider.getValue()); options.put("fps_limit", toggleFPSLimitCheckbox.isSelected() ? 0d : fpsLimitSlider.getValue());
options.put("enable_multithreading", multithreadingCheckbox.isSelected() ? 1f : 0f); options.put("enable_multithreading", multithreadingCheckbox.isSelected() ? 1d : 0d);
options.put("number_of_creatures", (float) nCreaturesSlider.getValue()); options.put("number_of_creatures", (double) nCreaturesSlider.getValue());
options.put("number_of_plants", (float) nPlantsSlider.getValue()); options.put("number_of_plants", (double) nPlantsSlider.getValue());
options.put("corpse_decay_rate", corpseDecaySlider.getValue() / 1000f); options.put("corpse_decay_rate", (double) corpseDecaySlider.getValue() / 1000d);
options.put("enable_corpses", enableCorpsesCheckbox.isSelected() ? 1f : 0f); options.put("enable_corpses", enableCorpsesCheckbox.isSelected() ? 1d : 0d);
options.put("world_width", (float) worldSizeSlider.getValue()); options.put("world_width", (double) worldSizeSlider.getValue());
options.put("world_height", (float) worldSizeSlider.getValue()); options.put("world_height", (double) worldSizeSlider.getValue());
topSizeSlider.setMaximum(nCreaturesSlider.getValue()); topSizeSlider.setMaximum(nCreaturesSlider.getValue());
options.put("parents_count", (float) topSizeSlider.getValue()); options.put("parents_count", (double) topSizeSlider.getValue());
options.put("creature_sight_range", (float) sightRangeSlider.getValue()); options.put("creature_sight_range", (double) sightRangeSlider.getValue());
options.put("creature_hp_decay", (float) hpDecaySlider.getValue() / 1000); options.put("creature_hp_decay", hpDecaySlider.getValue() / 1000d);
options.put("max_ticks", (float) maxTicksSlider.getValue()); options.put("max_ticks", (double) maxTicksSlider.getValue());
options.put("draw_view_cones", drawViewCones.isSelected() ? 1f : 0); options.put("draw_view_cones", drawViewCones.isSelected() ? 1d : 0d);
options.put("draw_sight_lines", drawSightLines.isSelected() ? 1f : 0); options.put("draw_sight_lines", drawSightLines.isSelected() ? 1d : 0d);
options.put("nMutatedBrains", (float) nMutatedBrainsSlider.getValue() / 100); options.put("nMutatedBrains", nMutatedBrainsSlider.getValue() / 100d);
options.put("nMutatedNeurons", (float) nMutatedNeuronsSlider.getValue() / 100); options.put("nMutatedNeurons", nMutatedNeuronsSlider.getValue() / 100d);
options.put("nMutatedConnections", (float) nMutatedConnectionsSlider.getValue() / 100); options.put("nMutatedConnections", nMutatedConnectionsSlider.getValue() / 100d);
options.put("mutationFactor", (float) mutationFactorSlider.getValue() / 100); options.put("mutationFactor", mutationFactorSlider.getValue() / 100d);
world.reloadOptions(); world.reloadOptions();
} }
updateSettingsUI(); updateSettingsUI();
@ -1167,7 +1167,7 @@ public class GUI extends javax.swing.JFrame implements LogListener {
if (f == null) { if (f == null) {
return; return;
} }
float map[][][] = Serializer.loadBrain(Serializer.loadFromFile(f)); double map[][][] = Serializer.loadBrain(Serializer.loadFromFile(f));
Creature c = (Creature) world.spawnCreature(map); Creature c = (Creature) world.spawnCreature(map);
world.selectCreature(c); world.selectCreature(c);
updateGUI(); updateGUI();
@ -1213,7 +1213,7 @@ public class GUI extends javax.swing.JFrame implements LogListener {
private void saveTableChanges() { private void saveTableChanges() {
for (int row = 0; row < settingsTable.getRowCount(); row++) { for (int row = 0; row < settingsTable.getRowCount(); row++) {
options.put((String) settingsTable.getValueAt(row, 0), (Float) settingsTable.getValueAt(row, 1)); options.put((String) settingsTable.getValueAt(row, 0), Double.parseDouble((String) settingsTable.getValueAt(row, 1)));
} }
world.reloadOptions(); world.reloadOptions();
updateSettingsUI(); updateSettingsUI();
@ -1224,7 +1224,7 @@ public class GUI extends javax.swing.JFrame implements LogListener {
*/ */
private void updateSettingsUI() { private void updateSettingsUI() {
updatingSliders = true; updatingSliders = true;
int fps = Math.round(options.get("fps_limit")); int fps = (int) Math.round(options.get("fps_limit"));
if (fps < 1) { if (fps < 1) {
fpsLimitSlider.setValue(60); fpsLimitSlider.setValue(60);
toggleFPSLimitCheckbox.setSelected(true); toggleFPSLimitCheckbox.setSelected(true);
@ -1233,34 +1233,34 @@ public class GUI extends javax.swing.JFrame implements LogListener {
toggleFPSLimitCheckbox.setSelected(false); toggleFPSLimitCheckbox.setSelected(false);
} }
multithreadingCheckbox.setSelected(options.get("enable_multithreading") > 0f); multithreadingCheckbox.setSelected(options.get("enable_multithreading") > 0f);
nCreaturesSlider.setValue(Math.round(options.get("number_of_creatures"))); nCreaturesSlider.setValue((int) Math.round(options.get("number_of_creatures")));
topSizeSlider.setMaximum(nCreaturesSlider.getValue()); topSizeSlider.setMaximum(nCreaturesSlider.getValue());
topSizeSlider.setValue(Math.round(options.get("parents_count"))); topSizeSlider.setValue((int) Math.round(options.get("parents_count")));
nPlantsSlider.setValue(Math.round(options.get("number_of_plants"))); nPlantsSlider.setValue((int) Math.round(options.get("number_of_plants")));
corpseDecaySlider.setValue(Math.round(options.get("corpse_decay_rate") * 1000)); corpseDecaySlider.setValue((int) Math.round(options.get("corpse_decay_rate") * 1000));
enableCorpsesCheckbox.setSelected(options.get("enable_corpses") > 0f); enableCorpsesCheckbox.setSelected(options.get("enable_corpses") > 0f);
worldSizeSlider.setValue(Math.round(options.get("world_height"))); worldSizeSlider.setValue((int) Math.round(options.get("world_height")));
sightRangeSlider.setValue(Math.round(options.get("creature_sight_range"))); sightRangeSlider.setValue((int) Math.round(options.get("creature_sight_range")));
hpDecaySlider.setValue(Math.round(options.get("creature_hp_decay") * 1000)); hpDecaySlider.setValue((int) Math.round(options.get("creature_hp_decay") * 1000));
maxTicksSlider.setValue(Math.round(options.get("max_ticks"))); maxTicksSlider.setValue((int) Math.round(options.get("max_ticks")));
drawViewCones.setSelected(options.get("draw_view_cones") > 0f); drawViewCones.setSelected(options.get("draw_view_cones") > 0f);
drawSightLines.setSelected(options.get("draw_sight_lines") > 0f); drawSightLines.setSelected(options.get("draw_sight_lines") > 0f);
nMutatedBrainsSlider.setValue(Math.round(options.get("nMutatedBrains") * 100)); nMutatedBrainsSlider.setValue((int) Math.round(options.get("nMutatedBrains") * 100));
nMutatedNeuronsSlider.setValue(Math.round(options.get("nMutatedNeurons") * 100)); nMutatedNeuronsSlider.setValue((int) Math.round(options.get("nMutatedNeurons") * 100));
nMutatedConnectionsSlider.setValue(Math.round(options.get("nMutatedConnections") * 100)); nMutatedConnectionsSlider.setValue((int) Math.round(options.get("nMutatedConnections") * 100));
mutationFactorSlider.setValue(Math.round(options.get("mutationFactor") * 100)); mutationFactorSlider.setValue((int) Math.round(options.get("mutationFactor") * 100));
updatingSliders = false; updatingSliders = false;
currentNMutatedNeurons.setText(String.format("%.2f", (float) nMutatedNeuronsSlider.getValue() / 100) + "%"); currentNMutatedNeurons.setText(String.format("%.2f", nMutatedNeuronsSlider.getValue() / 100d) + "%");
currentSightRange.setText(sightRangeSlider.getValue() + ""); currentSightRange.setText(sightRangeSlider.getValue() + "");
currentNMutatedBrains.setText(String.format("%.2f", (float) nMutatedBrainsSlider.getValue() / 100) + "%"); currentNMutatedBrains.setText(String.format("%.2f", nMutatedBrainsSlider.getValue() / 100d) + "%");
currentWorldSize.setText(worldSizeSlider.getValue() + ""); currentWorldSize.setText(worldSizeSlider.getValue() + "");
currentTopSize.setText(topSizeSlider.getValue() + (topSizeSlider.getValue() <= 0 ? " (Auto)" : "")); currentTopSize.setText(topSizeSlider.getValue() + (topSizeSlider.getValue() <= 0 ? " (Auto)" : ""));
currentMaxTicks.setText(maxTicksSlider.getValue() + ""); currentMaxTicks.setText(maxTicksSlider.getValue() + "");
currentHpDecay.setText(hpDecaySlider.getValue() / 1000f + ""); currentHpDecay.setText(hpDecaySlider.getValue() / 1000f + "");
currentMutationFactor.setText(String.format("%.2f", (float) mutationFactorSlider.getValue() / 100)); currentMutationFactor.setText(String.format("%.2f", mutationFactorSlider.getValue() / 100d));
currentFpsLimit.setText("" + fpsLimitSlider.getValue()); currentFpsLimit.setText("" + fpsLimitSlider.getValue());
currentNCreatures.setText(nCreaturesSlider.getValue() + ""); currentNCreatures.setText(nCreaturesSlider.getValue() + "");
currentNMutatedConnections.setText(String.format("%.2f", (float) nMutatedConnectionsSlider.getValue() / 100) + "%"); currentNMutatedConnections.setText(String.format("%.2f", nMutatedConnectionsSlider.getValue() / 100d) + "%");
currentNPlants.setText(nPlantsSlider.getValue() + ""); currentNPlants.setText(nPlantsSlider.getValue() + "");
currentCorpseDecay.setText(corpseDecaySlider.getValue() / 1000f + ""); currentCorpseDecay.setText(corpseDecaySlider.getValue() / 1000f + "");
int row = 0; int row = 0;