diff --git a/.nb-gradle/profiles/private/aux-config b/.nb-gradle/profiles/private/aux-config index af2bccb..fd3bee1 100644 --- a/.nb-gradle/profiles/private/aux-config +++ b/.nb-gradle/profiles/private/aux-config @@ -8,7 +8,13 @@ - + + 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/com/mygdx/game/Game.java b/core/src/com/mygdx/game/Game.java index 8c9f642..bcfde4b 100644 --- a/core/src/com/mygdx/game/Game.java +++ b/core/src/com/mygdx/game/Game.java @@ -4,6 +4,7 @@ import com.badlogic.gdx.ApplicationAdapter; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Input; import com.badlogic.gdx.graphics.GL20; +import com.badlogic.gdx.graphics.g2d.BitmapFont; import com.badlogic.gdx.graphics.glutils.ShapeRenderer; import logic.Element; import logic.World; @@ -13,14 +14,16 @@ public class Game extends ApplicationAdapter { private static Game game; ShapeRenderer shaper; private World world; - private float cameraSpeed = 5; + private float cameraSpeed = 15; + private BitmapFont font; @Override public void create() { + game = this; - world = new World(1920, 1080); + world = new World(2500, 2500); shaper = new ShapeRenderer(); - //shaper.setAutoShapeType(true); + font = new BitmapFont(); } @Override @@ -63,6 +66,7 @@ public class Game extends ApplicationAdapter { } } shaper.setColor(0.3f, 0.3f, 0.3f, 1); + // draw borders shaper.rect(0, 0, world.getWidth(), world.getHeight()); shaper.end(); } diff --git a/core/src/logic/World.java b/core/src/logic/World.java index 8f02706..363e53e 100644 --- a/core/src/logic/World.java +++ b/core/src/logic/World.java @@ -10,7 +10,6 @@ import java.util.ArrayList; import java.util.Comparator; import java.util.logging.Level; import java.util.logging.Logger; -import logic.neural.Brain; /** * @@ -18,8 +17,8 @@ import logic.neural.Brain; */ public class World { - private int width, height, generation = 0; - private final int nPlants, creatPerGen; + private final int width, height, nPlants, creatPerGen; + private int generation = 0; public ArrayList elements; public ArrayList creatures; public ArrayList graveyard; @@ -66,12 +65,6 @@ public class World { public int compare(Creature t, Creature t1) { // put the highest fitness first (sort in reverse) return (int) (t1.getFitness() - t.getFitness()); - /*if (t.getFitness() < t1.getFitness()) { - return -1; - } else if (t.getFitness() > t1.getFitness()) { - return 1; - } - return 0;*/ } }; if (graveyard.isEmpty() || restart) { // First gen @@ -80,42 +73,45 @@ public class World { spawnCreature(); } } else { // Evolve previous gen - // Calculate avg fitness + graveyard.sort(creatureComp); // sort by fitness + // Prepare best agent list + int topSize = (int) Math.floor(graveyard.size() * 0.1f); + Creature[] top = new Creature[topSize]; + // Calculate avg fitness and prepare best agent list float avgFitness = 0; - for (Creature c : graveyard) { + for (int i = 0; i < graveyard.size(); i++) { + Creature c = graveyard.get(i); + if (i < topSize) { + top[i] = graveyard.get(i); + Log.log(Log.INFO, "Gen " + generation + " Top " + (i + 1) + ": " + c.getFitness()); + } avgFitness += c.getFitness(); } avgFitness = avgFitness / graveyard.size(); Log.log(Log.INFO, "Gen " + generation + " done. Avg fitness: " + avgFitness); - // Start evolution - graveyard.sort(creatureComp); - 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); - } + // Generate children + for (Creature c : graveyard) { + int first = (int) Math.floor(Math.random() * topSize); + int sec = first; + while (sec == first) { + sec = (int) Math.floor(Math.random() * topSize); } - // Mutate parent - c.getBrain().remap(c.getBrain().getMutatedMap(0.1f)); - // Add it back in - creatures.add(c); - elements.add(c); + float[][][] n = null; + try { + n = top[first].getBrain().breed(top[sec].getBrain().getMap()); + } catch (Exception ex) { + // Should not happen + Logger.getLogger(World.class.getName()).log(Level.SEVERE, null, ex); + } + Creature ne = spawnCreature(n); + //ne.getBrain().mutate(0.1f); // mutate children } graveyard.clear(); generation++; } } - private void spawn(boolean isCreature, float[][][] brainMap) { + private Element spawn(boolean isCreature, float[][][] brainMap) { int x, y, r; boolean overlaps = false; if (isCreature) { @@ -141,11 +137,13 @@ public class World { } elements.add(c); creatures.add(c); + return c; } else { Log.log(Log.DEBUG, "New Veg: " + x + " " + y); Vegetable v = new Vegetable(x, y); elements.add(v); plants.add(v); + return v; } } @@ -153,12 +151,12 @@ public class World { spawn(false, null); } - private void spawnCreature() { - spawn(true, null); + private Creature spawnCreature() { + return (Creature) spawn(true, null); } - private void spawnCreature(float[][][] b) { - spawn(true, b); + private Creature spawnCreature(float[][][] b) { + return (Creature) spawn(true, b); } public int getWidth() { diff --git a/core/src/logic/neural/Brain.java b/core/src/logic/neural/Brain.java index 43e08cc..2add9ad 100644 --- a/core/src/logic/neural/Brain.java +++ b/core/src/logic/neural/Brain.java @@ -149,7 +149,7 @@ public class Brain { /** * Get a map of this brain's mind.. with a mutation * - * @param mutationFactor the highest this number, the bigger the mutation + * @param mutationFactor the higher this number, the bigger the mutation * @return a mutated brain map of this brain's mind */ public float[][][] getMutatedMap(float mutationFactor) { @@ -165,6 +165,21 @@ public class Brain { return res; } + /** + * Apply a mutation to this brain + * + * @param mutationFactor the higher this number, the bigger the mutation + */ + public void mutate(float mutationFactor) { + for (int i = 1; i < neurons.length; i++) // layers (skip input layer) + { + for (int j = 0; j < neurons[i].length; j++) // neurons per layer + { + neurons[i][j].setWeights(neurons[i][j].mutate(mutationFactor)); + } + } + } + public float[][][] breed(float[][][] map) throws Exception { float[][][] res = new float[neurons.length - 1][][]; if (map.length != neurons.length - 1) { diff --git a/desktop/src/com/mygdx/game/desktop/DesktopLauncher.java b/desktop/src/com/mygdx/game/desktop/DesktopLauncher.java index 5a92449..e7de7e6 100644 --- a/desktop/src/com/mygdx/game/desktop/DesktopLauncher.java +++ b/desktop/src/com/mygdx/game/desktop/DesktopLauncher.java @@ -5,11 +5,16 @@ import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration; import com.mygdx.game.Game; public class DesktopLauncher { - public static void main (String[] arg) { - LwjglApplicationConfiguration config = new LwjglApplicationConfiguration(); - config.height = 600; - config.width = 800; - config.resizable = false; - new LwjglApplication(new Game(), config); - } + + public static void main(String[] arg) { + LwjglApplicationConfiguration.disableAudio = true; + LwjglApplicationConfiguration config = new LwjglApplicationConfiguration(); + config.height = 600; + config.width = 800; + config.resizable = false; + config.vSyncEnabled = false; // Setting to false disables vertical sync + config.foregroundFPS = 60; // Setting to 0 disables foreground fps throttling + config.backgroundFPS = 0; // Setting to 0 disables background fps throttling + new LwjglApplication(new Game(), config); + } }