1
0
mirror of https://github.com/fazo96/AIrium.git synced 2025-03-29 21:18:39 +01:00

added stuffffff and genetic algo

This commit is contained in:
Enrico Fasoli 2015-07-02 13:51:44 +02:00
parent 3d43a4ce68
commit 54e5dbb30f
6 changed files with 166 additions and 71 deletions

View File

@ -0,0 +1,51 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package com.mygdx.game;
/**
*
* @author fazo
*/
public class Camera {
private int x, y, speed;
public Camera() {
x = 0;
y = 0;
speed = 5;
}
public void translate(int deltaX, int deltaY) {
x += deltaX;
y += deltaY;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public int getSpeed() {
return speed;
}
public void setSpeed(int speed) {
this.speed = speed;
}
}

View File

@ -4,8 +4,6 @@ import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input; import com.badlogic.gdx.Input;
import com.badlogic.gdx.graphics.GL20; import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer; import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import logic.Element; import logic.Element;
import logic.World; import logic.World;
@ -13,39 +11,49 @@ import logic.World;
public class Game extends ApplicationAdapter { public class Game extends ApplicationAdapter {
private static Game game; private static Game game;
SpriteBatch batch;
ShapeRenderer shaper; ShapeRenderer shaper;
Texture img; private Camera camera;
private World world; private World world;
@Override @Override
public void create() { public void create() {
game = this; game = this;
batch = new SpriteBatch(); world = new World(1920, 1080);
img = new Texture("badlogic.jpg");
world = new World(640, 480);
shaper = new ShapeRenderer(); shaper = new ShapeRenderer();
camera = new Camera();
//shaper.setAutoShapeType(true); //shaper.setAutoShapeType(true);
} }
@Override @Override
public void render() { public void render() {
// Input // Controls
if(Gdx.input.isKeyJustPressed(Input.Keys.SPACE)){ if (Gdx.input.isKeyJustPressed(Input.Keys.SPACE)) {
world.newGen(false); world.newGen(false);
} }
if (Gdx.input.isKeyPressed(Input.Keys.RIGHT)) {
camera.translate(-camera.getSpeed(), 0);
}
if (Gdx.input.isKeyPressed(Input.Keys.LEFT)) {
camera.translate(1+camera.getSpeed(), 0);
}
if (Gdx.input.isKeyPressed(Input.Keys.UP)) {
camera.translate(0, -camera.getSpeed());
}
if (Gdx.input.isKeyPressed(Input.Keys.DOWN)) {
camera.translate(0, camera.getSpeed());
}
// Update // Update
world.update(); world.update();
// Draw // Draw
Gdx.gl.glClearColor(0, 0, 0, 1); Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
/*batch.begin();
batch.draw(img, 0, 0);
batch.end();*/
shaper.setColor(1, 1, 1, 1); shaper.setColor(1, 1, 1, 1);
shaper.begin(ShapeRenderer.ShapeType.Line); shaper.begin(ShapeRenderer.ShapeType.Line);
//shaper.circle(640, 480, 100); for (Element e : world.getElements()) {
for(Element e: world.getElements()) e.render(shaper); e.render(shaper);
}
shaper.setColor(0.3f, 0.3f, 0.3f, 1);
shaper.rect(camera.getX(), camera.getY(), world.getWidth(), world.getHeight());
shaper.end(); shaper.end();
} }
@ -53,6 +61,10 @@ public class Game extends ApplicationAdapter {
return world; return world;
} }
public Camera getCamera() {
return camera;
}
public static Game get() { public static Game get() {
return game; return game;
} }

View File

@ -3,6 +3,8 @@ package logic;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer; import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.mygdx.game.Game; import com.mygdx.game.Game;
import com.mygdx.game.Log; import com.mygdx.game.Log;
import java.util.logging.Level;
import java.util.logging.Logger;
import logic.neural.Brain; import logic.neural.Brain;
/** /**
@ -16,8 +18,8 @@ public class Creature extends Element {
public static final float max_speed = 3; public static final float max_speed = 3;
private Brain brain; private Brain brain;
private float dir, speed, sightRange, fov, fitness, rotSpeed; private float dir, hp, speed, sightRange, fov, fitness, rotSpeed;
private float hp; private boolean eating = false;
private Sight sight; private Sight sight;
public Creature(float x, float y) { public Creature(float x, float y) {
@ -29,7 +31,7 @@ public class Creature extends Element {
sightRange = 60; sightRange = 60;
fov = (float) Math.PI / 1.5f; fov = (float) Math.PI / 1.5f;
fitness = 0; fitness = 0;
brain = new Brain(3, 2, 2, 8); brain = new Brain(4, 3, 1, 6);
} }
@Override @Override
@ -48,12 +50,18 @@ public class Creature extends Element {
// apply speed // apply speed
float xMul = (float) Math.cos(dir), yMul = (float) Math.sin(dir); float xMul = (float) Math.cos(dir), yMul = (float) Math.sin(dir);
move(xMul * speed, yMul * speed); move(xMul * speed, yMul * speed);
if(getX() < 0) setX(0); if (getX() < 0) {
if(getY() < 0) setX(0); setX(Game.get().getWorld().getWidth()+getX());
if(getX() > Game.get().getWorld().getWidth()) }
setX(Game.get().getWorld().getWidth()); if (getY() < 0) {
if(getY() > Game.get().getWorld().getHeight()) setX(Game.get().getWorld().getHeight()+getY());
setY(Game.get().getWorld().getHeight()); }
if (getX() > Game.get().getWorld().getWidth()) {
setX(getX()-Game.get().getWorld().getWidth());
}
if (getY() > Game.get().getWorld().getHeight()) {
setY(getY()-Game.get().getWorld().getHeight());
}
dir += rotSpeed; dir += rotSpeed;
// try eating // try eating
eat(); eat();
@ -66,29 +74,36 @@ public class Creature extends Element {
} }
sight = look(); // take a look sight = look(); // take a look
// feed data to brain // feed data to brain
float[] values = new float[3]; float[] values = new float[4];
// 0: type of sight // 0: see food
// 1: distance // 1: distance
// 2: angle // 2: angle
if (sight == null) { // 3: food sensor
if (sight == null || sight.getElement() == null) {
values[0] = 0; values[0] = 0;
values[1] = 1; values[1] = 0;
values[2] = 0; values[2] = 0;
} else if (sight.getElement() instanceof Creature) { } else if (sight.getElement() instanceof Vegetable) {
values[0] = 1; values[1] = 1;
values[1] = sight.getDistance() / sightRange; values[1] = sight.getDistance() / sightRange;
values[2] = sight.getAngle(); values[2] = sight.getAngle();
} else { } else {
values[0] = 0.5f; values[0] = 0f;
values[1] = sight.getDistance() / sightRange; values[1] = sight.getDistance() / sightRange;
values[2] = sight.getAngle(); values[2] = sight.getAngle();
} }
brain.input(values); values[3] = eating ? 1 : 0;
try {
brain.input(values);
} catch (Exception ex) {
// Should not happen
Logger.getLogger(Creature.class.getName()).log(Level.SEVERE, null, ex);
}
// compute behavior // compute behavior
float[] actions = brain.compute(); float[] actions = brain.compute();
Log.log(Log.DEBUG,"Accel: " + actions[0] + " Rot: " + actions[1]); Log.log(Log.DEBUG, "Accel: " + actions[0] + " RotClock: " + actions[1] + " RotAntiClock: " + actions[2]);
speed = actions[0]*max_speed; speed = actions[0] * max_speed;
rotSpeed = actions[1]/10; rotSpeed = actions[1] - actions[2];
} }
public void setHp(float hp) { public void setHp(float hp) {
@ -99,25 +114,24 @@ public class Creature extends Element {
public void render(ShapeRenderer s) { public void render(ShapeRenderer s) {
// Body // Body
s.setColor(1 - (hp / 100), hp / 100, 0, 1); s.setColor(1 - (hp / 100), hp / 100, 0, 1);
s.circle(getX(), getY(), getSize()); s.circle(getX() + Game.get().getCamera().getX(), getY() + Game.get().getCamera().getY(), getSize());
// Eye // Eye
double relX = Math.cos(dir) * getSize(), relY = Math.sin(dir) * getSize(); double relX = Math.cos(dir) * getSize(), relY = Math.sin(dir) * getSize();
s.setColor(1, 1, 1, 1);
if (sight != null) { if (sight != null) {
float c = sight.getDistance() / sightRange*2 + sightRange; float c = sight.getDistance() / sightRange * 2 + sightRange;
if (sight.getElement() instanceof Creature) { if (sight.getElement() instanceof Creature) {
s.setColor(c, 0, 0, 1); s.setColor(c, 0, 0, 1);
} else if (sight.getElement() instanceof Vegetable) { } else if (sight.getElement() instanceof Vegetable) {
s.setColor(0, c, 0, 1); s.setColor(0, c, 0, 1);
} else {
s.setColor(1, 1, 1, 1);
} }
} }
s.circle((float) relX + getX(), (float) relY + getY(), 3); s.circle((float) relX + getX() + Game.get().getCamera().getX(), (float) relY + getY() + Game.get().getCamera().getY(), 3);
//FOV //FOV
float degrees = fov * 180f / (float) Math.PI; float degrees = fov * 180f / (float) Math.PI;
float orient = dir * 180f / (float) Math.PI - degrees / 2; float orient = dir * 180f / (float) Math.PI - degrees / 2;
s.setColor(0.3f, 0.3f, 0.3f, 1); s.setColor(0.3f, 0.3f, 0.3f, 1);
s.arc((float) relX + getX(), (float) relY + getY(), sightRange, orient, degrees); s.arc((float) relX + getX() + Game.get().getCamera().getX(), (float) relY + getY() + Game.get().getCamera().getY(), sightRange, orient, degrees);
} }
public Sight look() { public Sight look() {
@ -153,9 +167,12 @@ public class Creature extends Element {
} }
public void eat() { public void eat() {
for (Element e : Game.get().getWorld().getElements()) { eating = false;
if (e instanceof Vegetable && overlaps(e)) { for (Element e : Game.get().getWorld().getPlants()) {
if (overlaps(e)) {
eating = true;
e.setSize(e.getSize() - 0.1f); e.setSize(e.getSize() - 0.1f);
if(e.getSize() == 0) e.setSize(0);
hp++; hp++;
fitness++; fitness++;
if (hp > 100) { if (hp > 100) {
@ -177,9 +194,9 @@ public class Creature extends Element {
return fitness; return fitness;
} }
public void reset(){ public void reset() {
fitness = 0; fitness = 0;
hp = 100; hp = 100;
} }
} }

View File

@ -23,7 +23,7 @@ public class Vegetable extends Element {
@Override @Override
public void update() { public void update() {
if(getSize() < 0){ if (getSize() <= 0) {
Game.get().getWorld().getDeadPlants().add(this); Game.get().getWorld().getDeadPlants().add(this);
} }
} }
@ -31,6 +31,6 @@ public class Vegetable extends Element {
@Override @Override
public void render(ShapeRenderer s) { public void render(ShapeRenderer s) {
s.setColor(1, 1, 1, 1); s.setColor(1, 1, 1, 1);
s.circle(getX(), getY(), getSize()); s.circle(getX() + Game.get().getCamera().getX(), getY() + Game.get().getCamera().getY(), getSize());
} }
} }

View File

@ -41,16 +41,16 @@ public class World {
elements.removeAll(graveyard); elements.removeAll(graveyard);
elements.removeAll(deadPlants); elements.removeAll(deadPlants);
plants.removeAll(deadPlants); plants.removeAll(deadPlants);
creatures.removeAll(graveyard);
deadPlants.clear(); deadPlants.clear();
creatures.removeAll(graveyard);
if (creatures.isEmpty()) { if (creatures.isEmpty()) {
// All dead, next gen // All dead, next gen
newGen(false); newGen(false);
} }
while (plants.size() < 50) { while (plants.size() < (width*height)/5000) {
spawnVegetable(); spawnVegetable();
} }
for (Creature e : creatures) { for (Element e : elements) {
e.update(); e.update();
} }
} }
@ -63,7 +63,7 @@ public class World {
@Override @Override
public int compare(Creature t, Creature t1) { public int compare(Creature t, Creature t1) {
// put the highest fitness first (sort in reverse) // put the highest fitness first (sort in reverse)
return (int) (t1.getFitness() - t.getFitness() ); return (int) (t1.getFitness() - t.getFitness());
/*if (t.getFitness() < t1.getFitness()) { /*if (t.getFitness() < t1.getFitness()) {
return -1; return -1;
} else if (t.getFitness() > t1.getFitness()) { } else if (t.getFitness() > t1.getFitness()) {
@ -132,7 +132,7 @@ public class World {
} }
} while (overlaps); } while (overlaps);
if (isCreature) { if (isCreature) {
Log.log(Log.INFO, "New Creat: " + x + " " + y); Log.log(Log.DEBUG, "New Creat: " + x + " " + y);
Creature c = new Creature(x, y); Creature c = new Creature(x, y);
if (brainMap != null) { if (brainMap != null) {
c.getBrain().remap(brainMap); c.getBrain().remap(brainMap);
@ -140,7 +140,7 @@ public class World {
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.DEBUG, "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);
@ -179,4 +179,12 @@ public class World {
return deadPlants; return deadPlants;
} }
public ArrayList<Creature> getCreatures() {
return creatures;
}
public ArrayList<Vegetable> getPlants() {
return plants;
}
} }

View File

@ -57,10 +57,10 @@ public class Brain {
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
// skip input layer // skip input layer
if (neurons[i+1][j] == null) { if (neurons[i + 1][j] == null) {
neurons[i+1][j] = new Neuron(j, bias, this, brainMap[i][j]); neurons[i + 1][j] = new Neuron(j, bias, this, brainMap[i][j]);
} else { } else {
neurons[i+1][j].setWeights(brainMap[i][j]); neurons[i + 1][j].setWeights(brainMap[i][j]);
} }
} }
} }
@ -86,8 +86,13 @@ public class Brain {
* *
* @param values the array of input. Its length must match the number of * @param values the array of input. Its length must match the number of
* input neurons of this brain * input neurons of this brain
* @throws Exception if the number of inputs given differs from the number
* of input neurons of this brain
*/ */
public void input(float[] values) { public void input(float[] values) throws Exception {
if (values.length != neurons[0].length) {
throw new Exception("Not enough or too many inputs");
}
for (int i = 0; i < values.length; i++) { for (int i = 0; i < values.length; i++) {
neurons[0][i].setOutput(values[i]); neurons[0][i].setOutput(values[i]);
} }
@ -114,8 +119,10 @@ public class Brain {
* *
* @param values * @param values
* @return the results of the neural network * @return the results of the neural network
* @throws Exception if the number of inputs given differs from the number
* of input neurons of this brain
*/ */
public float[] compute(float[] values) { public float[] compute(float[] values) throws Exception {
input(values); input(values);
return compute(); return compute();
} }
@ -127,13 +134,13 @@ public class Brain {
* mind * mind
*/ */
public float[][][] getMap() { public float[][][] getMap() {
float[][][] res = new float[neurons.length-1][][]; float[][][] res = new float[neurons.length - 1][][];
for (int i = 1; i < neurons.length; i++) // layers (skip input layer) for (int i = 1; i < neurons.length; i++) // layers (skip input layer)
{ {
res[i-1] = 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-1][j] = neurons[i][j].getWeights(); res[i - 1][j] = neurons[i][j].getWeights();
} }
} }
return res; return res;
@ -146,27 +153,27 @@ 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-1][][]; float[][][] res = new float[neurons.length - 1][][];
for (int i = 1; i < neurons.length; i++) // layers (skip input layer) for (int i = 1; i < neurons.length; i++) // layers (skip input layer)
{ {
res[i-1] = 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-1][j] = neurons[i][j].mutate(mutationFactor); res[i - 1][j] = neurons[i][j].mutate(mutationFactor);
} }
} }
return res; return res;
} }
public float[][][] breed(float[][][] map) throws Exception { public float[][][] breed(float[][][] map) throws Exception {
float[][][] res = new float[neurons.length-1][][]; float[][][] res = new float[neurons.length - 1][][];
if (map.length != neurons.length-1) { if (map.length != neurons.length - 1) {
throw new Exception("incompatible brains"); throw new Exception("incompatible brains");
} }
for (int i = 1; i < neurons.length; i++) // layers (skip input layer) for (int i = 1; i < neurons.length; i++) // layers (skip input layer)
{ {
res[i-1] = new float[neurons[i].length][]; res[i - 1] = new float[neurons[i].length][];
if (map[i-1].length != neurons[i].length) { if (map[i - 1].length != neurons[i].length) {
throw new Exception("incompatible brains"); throw new Exception("incompatible brains");
} }
for (int j = 0; j < neurons[i].length; j++) // neurons per layer for (int j = 0; j < neurons[i].length; j++) // neurons per layer
@ -174,17 +181,17 @@ public class Brain {
// j = 8 not valid for neurons[i][j]. investigate why. // 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(i+" "+j+" | "+neurons[i].length+" "+res[i-1].length+" "+neurons[i][j].getWeights().length);
//System.out.println(neurons[i].length +" has to be > "+j); //System.out.println(neurons[i].length +" has to be > "+j);
res[i-1][j] = new float[neurons[i][j].getWeights().length]; res[i - 1][j] = new float[neurons[i][j].getWeights().length];
if (map[i-1][j].length != neurons[i][j].getWeights().length) { if (map[i - 1][j].length != neurons[i][j].getWeights().length) {
throw new Exception("incompatible brains"); throw new Exception("incompatible brains");
} }
for (int z = 0; z < neurons[i][j].getWeights().length; z++) // each weight for (int z = 0; z < neurons[i][j].getWeights().length; z++) // each weight
{ {
// Combine the two weights // Combine the two weights
if (Math.random() < 0.5) { if (Math.random() < 0.5) {
res[i-1][j][z] = map[i-1][j][z]; res[i - 1][j][z] = map[i - 1][j][z];
} else { } else {
res[i-1][j][z] = neurons[i][j].getWeights()[z]; res[i - 1][j][z] = neurons[i][j].getWeights()[z];
} }
} }
} }