From d5cff691514d6804cd5a1a444c9358fef07231bc Mon Sep 17 00:00:00 2001 From: Enrico Fasoli Date: Wed, 1 Jul 2015 16:03:12 +0200 Subject: [PATCH] some improvements --- .nb-gradle/profiles/private/aux-config | 8 +- core/src/com/mygdx/game/Game.java | 2 +- core/src/logic/Creature.java | 32 +++++-- core/src/logic/Vegetable.java | 5 +- core/src/logic/World.java | 100 ++++++++++++++++---- core/src/logic/neural/Brain.java | 27 ++++-- core/src/logic/neural/NeuralConnection.java | 6 ++ core/src/logic/neural/Neuron.java | 6 +- 8 files changed, 143 insertions(+), 43 deletions(-) diff --git a/.nb-gradle/profiles/private/aux-config b/.nb-gradle/profiles/private/aux-config index 29b08c7..3e5ac38 100644 --- a/.nb-gradle/profiles/private/aux-config +++ b/.nb-gradle/profiles/private/aux-config @@ -3,10 +3,6 @@ - - - - file:/home/fazo/Documents/Git/AIrium/core/src/logic/neural/NeuralConnection.java @@ -17,5 +13,9 @@ file:/home/fazo/Documents/Git/AIrium/core/src/logic/World.java + + + + diff --git a/core/src/com/mygdx/game/Game.java b/core/src/com/mygdx/game/Game.java index 0df57f7..86e95cc 100644 --- a/core/src/com/mygdx/game/Game.java +++ b/core/src/com/mygdx/game/Game.java @@ -32,7 +32,7 @@ public class Game extends ApplicationAdapter { public void render() { // Input if(Gdx.input.isKeyJustPressed(Input.Keys.SPACE)){ - world.getElements().clear(); + world.newGen(); } // Update world.update(); diff --git a/core/src/logic/Creature.java b/core/src/logic/Creature.java index 4e19f8c..c214a62 100644 --- a/core/src/logic/Creature.java +++ b/core/src/logic/Creature.java @@ -25,16 +25,16 @@ public class Creature extends Element { hp = 100; speed = 0;//(float) Math.random() * 3; rotSpeed = 0;//(float) Math.random() - 0.5f; - sightRange = 40; - fov = (float) Math.PI / 2; + sightRange = 60; + fov = (float) Math.PI / 1.5f; fitness = 100; - brain = new Brain(3, 2, 1, 4); + brain = new Brain(3, 2, 2, 8); } @Override public void update() { // apply hunger - hp -= 0.1f; + hp -= 0.5f; if (hp < 0) { Game.get().getWorld().getGraveyard().add(this); } @@ -47,6 +47,12 @@ public class Creature extends Element { // apply speed float xMul = (float) Math.cos(dir), yMul = (float) Math.sin(dir); move(xMul * speed, yMul * speed); + if(getX() < 0) setX(0); + if(getY() < 0) setX(0); + if(getX() > Game.get().getWorld().getWidth()) + setX(Game.get().getWorld().getWidth()); + if(getY() > Game.get().getWorld().getHeight()) + setY(Game.get().getWorld().getHeight()); dir += rotSpeed; // try eating eat(); @@ -81,7 +87,11 @@ public class Creature extends Element { float[] actions = brain.compute(); System.out.println("Accel: " + actions[0] + " Rot: " + actions[1]); speed = actions[0]*max_speed; - rotSpeed = actions[1] - 1f; + rotSpeed = actions[1]/10; + } + + public void setHp(float hp) { + this.hp = hp; } @Override @@ -92,7 +102,7 @@ public class Creature extends Element { // Eye double relX = Math.cos(dir) * getSize(), relY = Math.sin(dir) * getSize(); if (sight != null) { - float c = sight.getDistance() / sightRange; + float c = sight.getDistance() / sightRange*2 + sightRange; if (sight.getElement() instanceof Creature) { s.setColor(c, 0, 0, 1); } else if (sight.getElement() instanceof Vegetable) { @@ -145,7 +155,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 ++; + hp++; fitness++; if (hp > 100) { hp = 100; @@ -154,8 +164,16 @@ public class Creature extends Element { } } + public Brain getBrain() { + return brain; + } + public void setDirection(float dir) { this.dir = dir; } + public float getFitness() { + return fitness; + } + } diff --git a/core/src/logic/Vegetable.java b/core/src/logic/Vegetable.java index a88cde7..38c3044 100644 --- a/core/src/logic/Vegetable.java +++ b/core/src/logic/Vegetable.java @@ -6,6 +6,7 @@ package logic; import com.badlogic.gdx.graphics.glutils.ShapeRenderer; +import com.mygdx.game.Game; /** * @@ -22,7 +23,9 @@ public class Vegetable extends Element { @Override public void update() { - + if(getSize() < 0){ + Game.get().getWorld().getDeadPlants().add(this); + } } @Override diff --git a/core/src/logic/World.java b/core/src/logic/World.java index 2adc2bf..da6c0c1 100644 --- a/core/src/logic/World.java +++ b/core/src/logic/World.java @@ -6,6 +6,8 @@ package logic; import java.util.ArrayList; +import java.util.Comparator; +import logic.neural.Brain; /** * @@ -13,34 +15,80 @@ import java.util.ArrayList; */ public class World { + public static final int creatPerGen = 10; private int width, height; public ArrayList elements; - public ArrayList graveyard; + public ArrayList creatures; + public ArrayList graveyard; + public ArrayList plants; + public ArrayList deadPlants; public World(int width, int height) { this.width = width; this.height = height; elements = new ArrayList(); + creatures = new ArrayList(); + plants = new ArrayList(); + deadPlants = new ArrayList(); graveyard = new ArrayList(); + newGen(); } public void update() { - while (elements.size() < 40) { - if (Math.random() < 0.4) { - spawnCreature(); - } else { - spawnVegetable(); - } - /*Creature c = new Creature(300,400); - elements.add(c); - elements.add(new Vegetable(300,450));*/ - } elements.removeAll(graveyard); - graveyard.clear(); - for(Element e: elements) e.update(); + elements.removeAll(deadPlants); + plants.removeAll(deadPlants); + creatures.removeAll(graveyard); + deadPlants.clear(); + if (creatures.isEmpty()) { + // All dead, next gen + newGen(); + } + while (plants.size() < 50) { + spawnVegetable(); + } + for (Creature e : creatures) { + e.update(); + } } - private void spawn(boolean isCreature) { + public void newGen() { + elements.removeAll(creatures); + creatures.clear(); + Comparator creatureComp = new Comparator() { + + @Override + public int compare(Creature t, Creature t1) { + if (t.getFitness() < t1.getFitness()) { + return -1; + } else if (t.getFitness() > t1.getFitness()) { + return 1; + } + return 0; + } + }; + if (graveyard.size() == 0) { // First gen + for (int i = 0; i < creatPerGen; i++) { + spawnCreature(); + } + } else { // Mutate previous gen + //graveyard.sort(creatureComp); + int x = 0; + for (Creature c : graveyard) { + c.getBrain().mutate(5f); + if (x < creatPerGen) { + c.setHp(100); + creatures.add(c); + elements.add(c); + } else { + break; + } + } + graveyard.clear(); + } + } + + private void spawn(boolean isCreature, Brain brain) { int x, y, r; boolean overlaps = false; if (isCreature) { @@ -60,19 +108,27 @@ public class World { } while (overlaps); if (isCreature) { System.out.println("New Creat: " + x + " " + y); - elements.add(new Creature(x, y)); + Creature c = new Creature(x, y); + elements.add(c); + creatures.add(c); } else { System.out.println("New Veg: " + x + " " + y); - elements.add(new Vegetable(x, y)); + Vegetable v = new Vegetable(x, y); + elements.add(v); + plants.add(v); } } private void spawnVegetable() { - spawn(false); + spawn(false, null); } private void spawnCreature() { - spawn(true); + spawn(true, null); + } + + private void spawnCreature(Brain b) { + spawn(true, b); } public int getWidth() { @@ -87,8 +143,12 @@ public class World { return elements; } - public ArrayList getGraveyard() { + public ArrayList getGraveyard() { return graveyard; } - + + public ArrayList getDeadPlants() { + return deadPlants; + } + } diff --git a/core/src/logic/neural/Brain.java b/core/src/logic/neural/Brain.java index 0648aa4..f87ec86 100644 --- a/core/src/logic/neural/Brain.java +++ b/core/src/logic/neural/Brain.java @@ -8,33 +8,38 @@ import java.util.ArrayList; */ public class Brain { + public static final float bias = 0.5f; 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); + populate(nInputs, nOutputs, hiddenLayers, neuronsPerHiddenLayer); + } + + private void populate(int nInputs, int nOutputs, int hiddenLayers, int neuronsPerHiddenLayer) { // Create input neurons for (int i = 0; i < nInputs; i++) { - inputs.add(new Neuron(0)); + inputs.add(new Neuron(0,bias)); } // 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); + Neuron n = new Neuron(i + 1,bias); // 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"); + 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); + Neuron n = new Neuron(hiddenLayers + 1,bias); int conn = 0; for (Neuron s : hidden) { // add connections where applicable @@ -43,13 +48,13 @@ public class Brain { n.getInputs().add(new NeuralConnection(randWeight(), s)); } } - System.out.println("Adding Output Layer Neuron "+i+" with "+conn+" inputs"); + System.out.println("Adding Output Layer Neuron " + i + " with " + conn + " inputs"); outputs.add(n); } } - - private float randWeight(){ - return (float) Math.random()*2-1f; + + private float randWeight() { + return (float) Math.random()*5 - 2.5f; } public void input(float[] values) { @@ -63,7 +68,7 @@ public class Brain { n.clearCachedValue(); } float[] res = new float[outputs.size()]; - for (int i=0;i(); } @@ -44,6 +44,10 @@ public class Neuron { return cachedValue; } + public void mutate(float mutationFactor){ + for(NeuralConnection n : inputs) n.mutate(mutationFactor); + } + public void setOutput(float output) { isInputNeuron = true; this.output = output;