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:
parent
19ea71a073
commit
3d43a4ce68
@ -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();
|
||||||
|
@ -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) {
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user