diff --git a/.nb-gradle/profiles/private/aux-config b/.nb-gradle/profiles/private/aux-config
index af2bccb..29b08c7 100644
--- a/.nb-gradle/profiles/private/aux-config
+++ b/.nb-gradle/profiles/private/aux-config
@@ -8,7 +8,14 @@
-
+
+ file:/home/fazo/Documents/Git/AIrium/core/src/logic/neural/NeuralConnection.java
+ file:/home/fazo/Documents/Git/AIrium/core/src/com/mygdx/game/Game.java
+ file:/home/fazo/Documents/Git/AIrium/core/src/logic/neural/Neuron.java
+ file:/home/fazo/Documents/Git/AIrium/core/src/logic/Creature.java
+ file:/home/fazo/Documents/Git/AIrium/core/src/logic/neural/Brain.java
+ file:/home/fazo/Documents/Git/AIrium/core/src/logic/World.java
+
diff --git a/core/src/logic/Creature.java b/core/src/logic/Creature.java
index a0a5786..4e19f8c 100644
--- a/core/src/logic/Creature.java
+++ b/core/src/logic/Creature.java
@@ -2,6 +2,7 @@ package logic;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.mygdx.game.Game;
+import logic.neural.Brain;
/**
* A (hopefully) smart biological creature.
@@ -11,8 +12,10 @@ import com.mygdx.game.Game;
public class Creature extends Element {
public static final int default_radius = 20;
+ public static final float max_speed = 3;
- private float dir, speed, accel, sightRange, fov, fitness, rotSpeed;
+ private Brain brain;
+ private float dir, speed, sightRange, fov, fitness, rotSpeed;
private float hp;
private Sight sight;
@@ -20,12 +23,12 @@ public class Creature extends Element {
super(x, y, default_radius);
dir = (float) (Math.random() * 2 * Math.PI);
hp = 100;
- speed = (float) Math.random() * 3;
- rotSpeed = (float) Math.random() - 0.5f;
- accel = 0f;
+ speed = 0;//(float) Math.random() * 3;
+ rotSpeed = 0;//(float) Math.random() - 0.5f;
sightRange = 40;
fov = (float) Math.PI / 2;
fitness = 100;
+ brain = new Brain(3, 2, 1, 4);
}
@Override
@@ -35,12 +38,11 @@ public class Creature extends Element {
if (hp < 0) {
Game.get().getWorld().getGraveyard().add(this);
}
- speed += accel; // apply acceleration
- if (speed > 0) {
- speed -= 0.001; // attrito
+ if (speed > max_speed) {
+ speed = max_speed;
}
- if (speed < 0) {
- speed = 0;
+ if (speed < -max_speed) {
+ speed = -max_speed;
}
// apply speed
float xMul = (float) Math.cos(dir), yMul = (float) Math.sin(dir);
@@ -48,11 +50,38 @@ public class Creature extends Element {
dir += rotSpeed;
// try eating
eat();
- fitness -= 0.1;
+ //fitness -= 0.1;
if (dir > 2 * Math.PI) {
dir -= 2 * Math.PI;
}
- sight = look();
+ if (dir < 0) {
+ dir += 2 * Math.PI;
+ }
+ sight = look(); // take a look
+ // feed data to brain
+ float[] values = new float[3];
+ // 0: type of sight
+ // 1: distance
+ // 2: angle
+ if (sight == null) {
+ values[0] = 0;
+ values[1] = 1;
+ values[2] = 0;
+ } else if (sight.getElement() instanceof Creature) {
+ values[0] = 1;
+ values[1] = sight.getDistance() / sightRange;
+ values[2] = sight.getAngle();
+ } else {
+ values[0] = 0.5f;
+ values[1] = sight.getDistance() / sightRange;
+ values[2] = sight.getAngle();
+ }
+ brain.input(values);
+ // compute behavior
+ float[] actions = brain.compute();
+ System.out.println("Accel: " + actions[0] + " Rot: " + actions[1]);
+ speed = actions[0]*max_speed;
+ rotSpeed = actions[1] - 1f;
}
@Override
@@ -116,7 +145,7 @@ public class Creature extends Element {
for (Element e : Game.get().getWorld().getElements()) {
if (e instanceof Vegetable && overlaps(e)) {
e.setSize(e.getSize() - 0.1f);
- hp += 0.1f;
+ hp ++;
fitness++;
if (hp > 100) {
hp = 100;
diff --git a/core/src/logic/World.java b/core/src/logic/World.java
index b5f523e..2adc2bf 100644
--- a/core/src/logic/World.java
+++ b/core/src/logic/World.java
@@ -25,8 +25,8 @@ public class World {
}
public void update() {
- while (elements.size() < 20) {
- if (Math.random() < 0.2) {
+ while (elements.size() < 40) {
+ if (Math.random() < 0.4) {
spawnCreature();
} else {
spawnVegetable();
diff --git a/core/src/logic/neural/Brain.java b/core/src/logic/neural/Brain.java
index c6ae108..0648aa4 100644
--- a/core/src/logic/neural/Brain.java
+++ b/core/src/logic/neural/Brain.java
@@ -1,9 +1,74 @@
package logic.neural;
+import java.util.ArrayList;
+
/**
*
* @author fazo
*/
public class Brain {
+
+ private ArrayList inputs, outputs, hidden;
+
+ public Brain(int nInputs, int nOutputs, int hiddenLayers, int neuronsPerHiddenLayer) {
+ inputs = new ArrayList(nInputs);
+ outputs = new ArrayList(nOutputs);
+ hidden = new ArrayList(hiddenLayers * neuronsPerHiddenLayer);
+ // Create input neurons
+ for (int i = 0; i < nInputs; i++) {
+ inputs.add(new Neuron(0));
+ }
+ // popiulate hidden layers
+ for (int i = 0; i < hiddenLayers; i++) {
+ for (int j = 0; j < neuronsPerHiddenLayer; j++) {
+ // create neuron
+ Neuron n = new Neuron(i + 1);
+ // add connections
+ for (Neuron s : inputs) {
+ n.getInputs().add(new NeuralConnection(randWeight(), s));
+ }
+ hidden.add(n);
+ System.out.println("Adding Hidden Layer "+(i+1)+" Neuron "+j+" with "+inputs.size()+" inputs");
+ }
+ }
+ // populate output layer
+ for (int i = 0; i < nOutputs; i++) {
+ // add neuron
+ Neuron n = new Neuron(hiddenLayers + 1);
+ int conn = 0;
+ for (Neuron s : hidden) {
+ // add connections where applicable
+ if (s.getLayer() == hiddenLayers) {
+ conn++;
+ n.getInputs().add(new NeuralConnection(randWeight(), s));
+ }
+ }
+ System.out.println("Adding Output Layer Neuron "+i+" with "+conn+" inputs");
+ outputs.add(n);
+ }
+ }
+ private float randWeight(){
+ return (float) Math.random()*2-1f;
+ }
+
+ public void input(float[] values) {
+ for (int i = 0; i < values.length; i++) {
+ inputs.get(i).setOutput(values[i]);
+ }
+ }
+
+ public float[] compute() {
+ for (Neuron n : hidden) {
+ n.clearCachedValue();
+ }
+ float[] res = new float[outputs.size()];
+ for (int i=0;i inputs, outputs;
+
+ private ArrayList inputs;
+ private float bias, output;
+ private boolean isInputNeuron;
+ private int layer;
+ private float cachedValue;
+ private boolean cachedValueValid = false;
+
+ public Neuron(int layer) {
+ this.layer = layer;
+ inputs = new ArrayList();
+ }
+
+ public float compute() {
+ if (isInputNeuron) {
+ return output;
+ }
+ if (cachedValueValid) {
+ return cachedValue;
+ }
+ float a = bias * -1; // activation
+ for (NeuralConnection i : inputs) {
+ a += i.compute();
+ }
+ System.out.println("Computed Value "+a+" for neuron");
+ cachedValueValid = true;
+ // sigmoid function
+ cachedValue = (float) (1 / (1 + Math.pow(Math.E, a * -1)));
+ System.out.println("Computed Value "+cachedValue+" for neuron");
+ return cachedValue;
+ }
+
+ public void setOutput(float output) {
+ isInputNeuron = true;
+ this.output = output;
+ }
+
+ public ArrayList getInputs() {
+ return inputs;
+ }
+
+ public float getBias() {
+ return bias;
+ }
+
+ public void setBias(float bias) {
+ this.bias = bias;
+ }
+
+ public boolean isIsInputNeuron() {
+ return isInputNeuron;
+ }
+
+ public int getLayer() {
+ return layer;
+ }
+
+ public void setLayer(int layer) {
+ this.layer = layer;
+ }
+
+ public void clearCachedValue() {
+ cachedValueValid = false;
+ for(NeuralConnection n : inputs) n.clearCachedValue();
+ }
+
}