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

implemented first shitty genetic algorithm

This commit is contained in:
Enrico Fasoli 2015-07-02 12:38:56 +02:00
parent 19ea71a073
commit 3d43a4ce68
5 changed files with 108 additions and 43 deletions

View File

@ -32,7 +32,7 @@ public class Game extends ApplicationAdapter {
public void render() { public void render() {
// Input // Input
if(Gdx.input.isKeyJustPressed(Input.Keys.SPACE)){ if(Gdx.input.isKeyJustPressed(Input.Keys.SPACE)){
world.newGen(); world.newGen(false);
} }
// Update // Update
world.update(); world.update();

View File

@ -15,7 +15,7 @@ public class Log {
public static final int INFO = 1; public static final int INFO = 1;
public static final int DEBUG = 2; public static final int DEBUG = 2;
private static int logLevel = 0; private static int logLevel = 1;
public static void log(int level, String msg) { public static void log(int level, String msg) {
if (level <= logLevel) { if (level <= logLevel) {

View File

@ -28,7 +28,7 @@ public class Creature extends Element {
rotSpeed = 0;//(float) Math.random() - 0.5f; rotSpeed = 0;//(float) Math.random() - 0.5f;
sightRange = 60; sightRange = 60;
fov = (float) Math.PI / 1.5f; fov = (float) Math.PI / 1.5f;
fitness = 100; fitness = 0;
brain = new Brain(3, 2, 2, 8); brain = new Brain(3, 2, 2, 8);
} }
@ -177,4 +177,9 @@ public class Creature extends Element {
return fitness; return fitness;
} }
public void reset(){
fitness = 0;
hp = 100;
}
} }

View File

@ -8,6 +8,8 @@ package logic;
import com.mygdx.game.Log; import com.mygdx.game.Log;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Comparator; import java.util.Comparator;
import java.util.logging.Level;
import java.util.logging.Logger;
import logic.neural.Brain; import logic.neural.Brain;
/** /**
@ -17,7 +19,7 @@ import logic.neural.Brain;
public class World { public class World {
public static final int creatPerGen = 10; public static final int creatPerGen = 10;
private int width, height; private int width, height, generation = 0;
public ArrayList<Element> elements; public ArrayList<Element> elements;
public ArrayList<Creature> creatures; public ArrayList<Creature> creatures;
public ArrayList<Creature> graveyard; public ArrayList<Creature> graveyard;
@ -32,7 +34,7 @@ public class World {
plants = new ArrayList(); plants = new ArrayList();
deadPlants = new ArrayList(); deadPlants = new ArrayList();
graveyard = new ArrayList(); graveyard = new ArrayList();
newGen(); newGen(true);
} }
public void update() { public void update() {
@ -43,7 +45,7 @@ public class World {
deadPlants.clear(); deadPlants.clear();
if (creatures.isEmpty()) { if (creatures.isEmpty()) {
// All dead, next gen // All dead, next gen
newGen(); newGen(false);
} }
while (plants.size() < 50) { while (plants.size() < 50) {
spawnVegetable(); spawnVegetable();
@ -53,43 +55,65 @@ public class World {
} }
} }
public void newGen() { public void newGen(boolean restart) {
elements.removeAll(creatures); elements.removeAll(creatures);
creatures.clear(); graveyard.addAll(creatures);
Comparator creatureComp = new Comparator<Creature>() { Comparator creatureComp = new Comparator<Creature>() {
@Override @Override
public int compare(Creature t, Creature t1) { public int compare(Creature t, Creature t1) {
if (t.getFitness() < t1.getFitness()) { // put the highest fitness first (sort in reverse)
return -1; return (int) (t1.getFitness() - t.getFitness() );
} else if (t.getFitness() > t1.getFitness()) { /*if (t.getFitness() < t1.getFitness()) {
return 1; return -1;
} } else if (t.getFitness() > t1.getFitness()) {
return 0; return 1;
}
return 0;*/
} }
}; };
if (graveyard.size() == 0) { // First gen if (graveyard.isEmpty() || restart) { // First gen
generation = 0;
for (int i = 0; i < creatPerGen; i++) { for (int i = 0; i < creatPerGen; i++) {
spawnCreature(); spawnCreature();
} }
} else { // Mutate previous gen } else { // Evolve previous gen
//graveyard.sort(creatureComp); // Calculate avg fitness
int x = 0; float avgFitness = 0;
for (Creature c : graveyard) { for (Creature c : graveyard) {
c.getBrain().remap(c.getBrain().getMutatedMap(3f)); avgFitness += c.getFitness();
if (x < creatPerGen) { }
c.setHp(100); avgFitness = avgFitness / graveyard.size();
creatures.add(c); Log.log(Log.INFO, "Gen " + generation + " done. Avg fitness: " + avgFitness);
elements.add(c); // Start evolution
} else { graveyard.sort(creatureComp);
break; for (int i = 0; i < creatPerGen / 2; i++) {
Creature c = graveyard.get(i);
c.reset();
// Mutate
if (i != 0) {
try {
// create a child
float[][][] mind = c.getBrain().breed(graveyard.get(i - 1).getBrain().getMap());
// spawn it
spawnCreature(mind);
} catch (Exception ex) {
// Should never happen
Logger.getLogger(World.class.getName()).log(Level.SEVERE, null, ex);
}
} }
// Mutate parent
c.getBrain().remap(c.getBrain().getMutatedMap(0.1f));
// Add it back in
creatures.add(c);
elements.add(c);
} }
graveyard.clear(); graveyard.clear();
generation++;
} }
} }
private void spawn(boolean isCreature, Brain brain) { private void spawn(boolean isCreature, float[][][] brainMap) {
int x, y, r; int x, y, r;
boolean overlaps = false; boolean overlaps = false;
if (isCreature) { if (isCreature) {
@ -108,12 +132,15 @@ public class World {
} }
} while (overlaps); } while (overlaps);
if (isCreature) { if (isCreature) {
Log.log(Log.INFO,"New Creat: " + x + " " + y); Log.log(Log.INFO, "New Creat: " + x + " " + y);
Creature c = new Creature(x, y); Creature c = new Creature(x, y);
if (brainMap != null) {
c.getBrain().remap(brainMap);
}
elements.add(c); elements.add(c);
creatures.add(c); creatures.add(c);
} else { } else {
Log.log(Log.INFO,"New Veg: " + x + " " + y); Log.log(Log.INFO, "New Veg: " + x + " " + y);
Vegetable v = new Vegetable(x, y); Vegetable v = new Vegetable(x, y);
elements.add(v); elements.add(v);
plants.add(v); plants.add(v);
@ -128,7 +155,7 @@ public class World {
spawn(true, null); spawn(true, null);
} }
private void spawnCreature(Brain b) { private void spawnCreature(float[][][] b) {
spawn(true, b); spawn(true, b);
} }

View File

@ -56,10 +56,11 @@ public class Brain {
public void remap(float[][][] brainMap) { public void remap(float[][][] brainMap) {
for (int i = 0; i < brainMap.length; i++) { // for each layer for (int i = 0; i < brainMap.length; i++) { // for each layer
for (int j = 0; j < brainMap[i].length; j++) { // for each neuron for (int j = 0; j < brainMap[i].length; j++) { // for each neuron
if (neurons[i][j] == null) { // skip input layer
neurons[i][j] = new Neuron(j, bias, this, brainMap[i][j]); if (neurons[i+1][j] == null) {
neurons[i+1][j] = new Neuron(j, bias, this, brainMap[i][j]);
} else { } else {
neurons[i][j].setWeights(brainMap[i][j]); neurons[i+1][j].setWeights(brainMap[i][j]);
} }
} }
} }
@ -126,15 +127,13 @@ public class Brain {
* mind * mind
*/ */
public float[][][] getMap() { public float[][][] getMap() {
float[][][] res = new float[neurons.length][neurons[1].length][neurons[1].length]; float[][][] res = new float[neurons.length-1][][];
for (int i = 0; i < neurons.length; i++) // layers for (int i = 1; i < neurons.length; i++) // layers (skip input layer)
{ {
for (int j = 0; i < neurons[i].length; j++) // neurons per layer res[i-1] = new float[neurons[i].length][];
for (int j = 0; j < neurons[i].length; j++) // neurons per layer
{ {
if (neurons[i][j] == null) { res[i-1][j] = neurons[i][j].getWeights();
continue;
}
res[i][j] = neurons[i][j].getWeights();
} }
} }
return res; return res;
@ -147,13 +146,47 @@ public class Brain {
* @return a mutated brain map of this brain's mind * @return a mutated brain map of this brain's mind
*/ */
public float[][][] getMutatedMap(float mutationFactor) { public float[][][] getMutatedMap(float mutationFactor) {
float[][][] res = new float[neurons.length][][]; float[][][] res = new float[neurons.length-1][][];
for (int i = 0; i < neurons.length; i++) // layers for (int i = 1; i < neurons.length; i++) // layers (skip input layer)
{ {
res[i] = new float[neurons[i].length][]; res[i-1] = new float[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][j] = neurons[i][j].mutate(mutationFactor); res[i-1][j] = neurons[i][j].mutate(mutationFactor);
}
}
return res;
}
public float[][][] breed(float[][][] map) throws Exception {
float[][][] res = new float[neurons.length-1][][];
if (map.length != neurons.length-1) {
throw new Exception("incompatible brains");
}
for (int i = 1; i < neurons.length; i++) // layers (skip input layer)
{
res[i-1] = new float[neurons[i].length][];
if (map[i-1].length != neurons[i].length) {
throw new Exception("incompatible brains");
}
for (int j = 0; j < neurons[i].length; j++) // neurons per layer
{
// j = 8 not valid for neurons[i][j]. investigate why.
//System.out.println(i+" "+j+" | "+neurons[i].length+" "+res[i-1].length+" "+neurons[i][j].getWeights().length);
//System.out.println(neurons[i].length +" has to be > "+j);
res[i-1][j] = new float[neurons[i][j].getWeights().length];
if (map[i-1][j].length != neurons[i][j].getWeights().length) {
throw new Exception("incompatible brains");
}
for (int z = 0; z < neurons[i][j].getWeights().length; z++) // each weight
{
// Combine the two weights
if (Math.random() < 0.5) {
res[i-1][j][z] = map[i-1][j][z];
} else {
res[i-1][j][z] = neurons[i][j].getWeights()[z];
}
}
} }
} }
return res; return res;