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

big update with carnivores

This commit is contained in:
Enrico Fasoli 2015-07-02 21:42:11 +02:00
parent 480d763f95
commit 61519e6cf3
6 changed files with 146 additions and 57 deletions

1
.gitignore vendored
View File

@ -1,4 +1,5 @@
.nb-gradle/profiles/private/* .nb-gradle/profiles/private/*
.nb-gradle/profiles/private/aux-config
## Java ## Java

View File

@ -4,9 +4,14 @@
<auxiliary> <auxiliary>
<editor-bookmarks xmlns="http://www.netbeans.org/ns/editor-bookmarks/2" lastBookmarkId="0"/> <editor-bookmarks xmlns="http://www.netbeans.org/ns/editor-bookmarks/2" lastBookmarkId="0"/>
<open-files xmlns="http://www.netbeans.org/ns/projectui-open-files/2"> <open-files xmlns="http://www.netbeans.org/ns/projectui-open-files/2">
<group/> <group>
<file>file:/home/fazo/Documents/Git/AIrium/core/src/com/mygdx/game/Game.java</file>
<file>file:/home/fazo/Documents/Git/AIrium/core/src/logic/neural/Neuron.java</file>
<file>file:/home/fazo/Documents/Git/AIrium/core/src/logic/Creature.java</file>
<file>file:/home/fazo/Documents/Git/AIrium/core/src/logic/neural/Brain.java</file>
<file>file:/home/fazo/Documents/Git/AIrium/core/src/logic/World.java</file>
</group>
</open-files> </open-files>
<editor-bookmarks lastBookmarkId="0" xmlns="http://www.netbeans.org/ns/editor-bookmarks/2"/>
<open-files xmlns="http://www.netbeans.org/ns/projectui-open-files/2"> <open-files xmlns="http://www.netbeans.org/ns/projectui-open-files/2">
<group> <group>
<file>file:/home/fazo/Documents/Git/AIrium/core/src/com/mygdx/game/Game.java</file> <file>file:/home/fazo/Documents/Git/AIrium/core/src/com/mygdx/game/Game.java</file>

View File

@ -16,13 +16,14 @@ public class Game extends ApplicationAdapter {
private World world; private World world;
private float cameraSpeed = 15; private float cameraSpeed = 15;
private BitmapFont font; private BitmapFont font;
private boolean paused = false;
@Override @Override
public void create() { public void create() {
game = this; game = this;
world = new World(2500, 2500); world = new World(2500, 2500);
shaper = new ShapeRenderer(); shaper = new ShapeRenderer();
shaper.setAutoShapeType(true);
font = new BitmapFont(); font = new BitmapFont();
} }
@ -50,8 +51,13 @@ public class Game extends ApplicationAdapter {
if (Gdx.input.isKeyJustPressed(Input.Keys.MINUS)) { if (Gdx.input.isKeyJustPressed(Input.Keys.MINUS)) {
shaper.scale(1.5f, 1.5f, 1); shaper.scale(1.5f, 1.5f, 1);
} }
if (Gdx.input.isKeyJustPressed(Input.Keys.P)) {
paused = !paused;
}
// Update // Update
if (!paused) {
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);

View File

@ -18,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, hp, speed, sightRange, fov, fitness, rotSpeed; private float dir, hp, speed, sightRange, fov, fitness, rotSpeed, beak;
private boolean eating = false; private boolean eating = false, killing = false;
private Sight sight; private Sight sight;
public Creature(float x, float y) { public Creature(float x, float y) {
@ -31,15 +31,20 @@ public class Creature extends Element {
sightRange = 100; sightRange = 100;
fov = (float) Math.PI / 2.5f; fov = (float) Math.PI / 2.5f;
fitness = 0; fitness = 0;
brain = new Brain(4, 3, 1, 8); brain = new Brain(6, 5, 2, 10);
} }
@Override @Override
public void update() { public void update() {
// apply hunger // apply hunger
hp -= 0.5f; hp -= 0.5f;
if (hp < 0) { if (hp < 0) { // Dead
Game.get().getWorld().getGraveyard().add(this); Game.get().getWorld().getGraveyard().add(this);
Vegetable carcass = new Vegetable(getX(), getY());
carcass.setSize(getSize());
//carcass.setDecayRate(0.01f);
Game.get().getWorld().add(carcass);
return;
} }
if (speed > max_speed) { if (speed > max_speed) {
speed = max_speed; speed = max_speed;
@ -54,7 +59,7 @@ public class Creature extends Element {
setX(Game.get().getWorld().getWidth() + getX()); setX(Game.get().getWorld().getWidth() + getX());
} }
if (getY() < 0) { if (getY() < 0) {
setX(Game.get().getWorld().getHeight()+getY()); setY(Game.get().getWorld().getHeight() + getY());
} }
if (getX() > Game.get().getWorld().getWidth()) { if (getX() > Game.get().getWorld().getWidth()) {
setX(getX() - Game.get().getWorld().getWidth()); setX(getX() - Game.get().getWorld().getWidth());
@ -72,42 +77,54 @@ public class Creature extends Element {
if (dir < 0) { if (dir < 0) {
dir += 2 * Math.PI; dir += 2 * Math.PI;
} }
sight = look(); // take a look sight = lookAndHit(); // take a look
// feed data to brain // feed data to brain
float[] values = new float[4]; float[] values = new float[brain.getNeurons()[0].length];
// 0: see food // 0: sight: see food?
// 1: distance // 1: sight: see creat?
// 2: angle // 2: sight: distance
// 3: food sensor // 3: sight: angle
// 4: sight: size for vegetables, hunger for creatures
// 5: food sensor
if (sight == null || sight.getElement() == null) { if (sight == null || sight.getElement() == null) {
// See nothing
values[0] = 0; values[0] = 0;
values[1] = 0; values[1] = 0;
values[2] = 0; values[2] = 0;
} else if (sight.getElement() instanceof Vegetable) { values[3] = 0;
values[1] = 1; values[4] = 0;
values[1] = sight.getDistance() / sightRange; } else {
values[2] = sight.getAngle(); // See something
values[2] = sight.getDistance() / sightRange;
values[3] = sight.getAngle();
if (sight.getElement() instanceof Vegetable) {
values[0] = 1f;
values[1] = 0;
values[4] = sight.getElement().getSize() / default_radius;
} else { } else {
values[0] = 0f; values[0] = 0f;
values[1] = sight.getDistance() / sightRange; values[1] = 1f;
values[2] = sight.getAngle(); values[4] = 100 - ((Creature) sight.getElement()).getHp() / 100;
} }
values[3] = eating ? 1 : 0; }
values[5] = eating ? 1 : 0;
// compute behavior
float[] actions = null;
try { try {
brain.input(values); actions = brain.compute(values);
} catch (Exception ex) { } catch (Exception ex) {
// Should not happen // Should not happen
Logger.getLogger(Creature.class.getName()).log(Level.SEVERE, null, ex); Logger.getLogger(Creature.class.getName()).log(Level.SEVERE, null, ex);
} }
// compute behavior Log.log(Log.DEBUG, "Accel: " + actions[0] + " RotClock: " + actions[1] + " RotAntiClock: " + actions[2] + " Beak: " + actions[3]);
float[] actions = brain.compute(); speed = (actions[0] * 2 - actions[4] / 2) * max_speed;
Log.log(Log.DEBUG, "Accel: " + actions[0] + " RotClock: " + actions[1] + " RotAntiClock: " + actions[2]);
speed = actions[0] * max_speed;
rotSpeed = actions[1] - actions[2]; rotSpeed = actions[1] - actions[2];
beak = actions[3];
if (beak > 20) {
beak = 20;
} else if (beak < 0) {
beak = 0;
} }
public void setHp(float hp) {
this.hp = hp;
} }
@Override @Override
@ -116,7 +133,7 @@ public class Creature extends Element {
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(), getY(), getSize());
// Eye // Eye
double relX = Math.cos(dir) * getSize(), relY = Math.sin(dir) * getSize(); double relX = Math.cos(dir), relY = Math.sin(dir);
s.setColor(1, 1, 1, 1); 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;
@ -126,17 +143,29 @@ public class Creature extends Element {
s.setColor(0, c, 0, 1); s.setColor(0, c, 0, 1);
} }
} }
s.circle((float) relX + getX() , (float) relY + getY() , 3); // Eye
s.circle((float) relX * getSize() * 0.6f + getX(), (float) relY * getSize() * 0.6f + getY(), 3);
if (killing) {
// Evil mark
s.set(ShapeRenderer.ShapeType.Filled);
s.setColor(1, 0, 0, 1);
s.circle(getX(), getY(), 5);
}
s.set(ShapeRenderer.ShapeType.Line);
// Beak
s.setColor(1, 1, 0, beak / 20);
s.line((float) (relX * getSize() * 0.8f + getX()), (float) (relY * getSize() * 0.8f + getY()), (float) (relX * getSize() * (1.5f + beak / 20) + getX()), (float) (relY * getSize() * (1.5f + beak / 20) + getY()));
//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 * getSize() + getX(), (float) relY * getSize() + getY(), sightRange, orient, degrees);
} }
public Sight look() { public Sight lookAndHit() {
Element seen = null; Element seen = null;
float dist = 0, angle = 0, ndir = dir - (float) Math.PI; float dist = 0, angle = 0, ndir = dir - (float) Math.PI;
killing = false;
for (Element e : Game.get().getWorld().getElements()) { for (Element e : Game.get().getWorld().getElements()) {
if (e == this) { if (e == this) {
continue; continue;
@ -146,11 +175,9 @@ public class Creature extends Element {
continue; continue;
} }
//Log.log(Log.DEBUG,"TempDist "+tempDist+" SightRange "+sightRange); //Log.log(Log.DEBUG,"TempDist "+tempDist+" SightRange "+sightRange);
if (tempDist > dist && seen != null) {
continue;
}
float relAngle = (float) (Math.atan2(getY() - e.getY(), getX() - e.getX())); float relAngle = (float) (Math.atan2(getY() - e.getY(), getX() - e.getX()));
//if((relAngle > dir-fov/2 && relAngle < dir+fov/2)){ if (tempDist < dist || seen == null) {
// Check if Visible
if (Math.abs(relAngle - ndir) < fov) { if (Math.abs(relAngle - ndir) < fov) {
// Visible // Visible
seen = e; seen = e;
@ -159,6 +186,20 @@ public class Creature extends Element {
} }
//Log.log(Log.DEBUG,"RelAngle "+relAngle+" Dir "+ndir); //Log.log(Log.DEBUG,"RelAngle "+relAngle+" Dir "+ndir);
} }
// Check if attackable
if (e instanceof Creature && beak > 5 && tempDist < beak * 1.5f && Math.abs(relAngle - ndir) < (float) Math.PI / 10f) {
// Attacking!
hp++;
fitness++;
if (hp > 100) {
hp = 100;
}
killing = true;
Creature c = (Creature) e;
c.setHp(c.getHp() - 0.2f);
}
}
if (seen != null) { if (seen != null) {
return new Sight(seen, dist, angle); return new Sight(seen, dist, angle);
} else { } else {
@ -172,7 +213,9 @@ public class Creature extends Element {
if (overlaps(e)) { if (overlaps(e)) {
eating = true; eating = true;
e.setSize(e.getSize() - 0.1f); e.setSize(e.getSize() - 0.1f);
if(e.getSize() == 0) e.setSize(0); if (e.getSize() == 0) {
e.setSize(0);
}
hp++; hp++;
fitness++; fitness++;
if (hp > 100) { if (hp > 100) {
@ -199,4 +242,11 @@ public class Creature extends Element {
hp = 100; hp = 100;
} }
public float getHp() {
return hp;
}
public void setHp(float hp) {
this.hp = hp;
}
} }

View File

@ -15,7 +15,7 @@ import com.mygdx.game.Game;
public class Vegetable extends Element { public class Vegetable extends Element {
public static final int default_radius = 5; public static final int default_radius = 5;
private float x, y; private float decayRate = 0;
public Vegetable(float x, float y) { public Vegetable(float x, float y) {
super(x, y, default_radius); super(x, y, default_radius);
@ -23,6 +23,7 @@ public class Vegetable extends Element {
@Override @Override
public void update() { public void update() {
setSize(getSize()-decayRate);
if (getSize() <= 0) { if (getSize() <= 0) {
Game.get().getWorld().getDeadPlants().add(this); Game.get().getWorld().getDeadPlants().add(this);
} }
@ -33,4 +34,12 @@ public class Vegetable extends Element {
s.setColor(1, 1, 1, 1); s.setColor(1, 1, 1, 1);
s.circle(getX(), getY(), getSize()); s.circle(getX(), getY(), getSize());
} }
public float getDecayRate() {
return decayRate;
}
public void setDecayRate(float decayRate) {
this.decayRate = decayRate;
}
} }

View File

@ -18,8 +18,9 @@ import java.util.logging.Logger;
public class World { public class World {
private final int width, height, nPlants, creatPerGen; private final int width, height, nPlants, creatPerGen;
private int generation = 0; private int generation = 1;
public ArrayList<Element> elements; public ArrayList<Element> elements;
public ArrayList<Element> toAdd;
public ArrayList<Creature> creatures; public ArrayList<Creature> creatures;
public ArrayList<Creature> graveyard; public ArrayList<Creature> graveyard;
public ArrayList<Vegetable> plants; public ArrayList<Vegetable> plants;
@ -30,8 +31,9 @@ public class World {
this.height = height; this.height = height;
elements = new ArrayList(); elements = new ArrayList();
creatures = new ArrayList(); creatures = new ArrayList();
toAdd = new ArrayList();
creatPerGen = Math.min(Math.round(width * height / 20000), 50); creatPerGen = Math.min(Math.round(width * height / 20000), 50);
nPlants = Math.round(width * height / 5000); nPlants = Math.round(width * height / 5500);
plants = new ArrayList(); plants = new ArrayList();
deadPlants = new ArrayList(); deadPlants = new ArrayList();
graveyard = new ArrayList(); graveyard = new ArrayList();
@ -39,6 +41,15 @@ public class World {
} }
public void update() { public void update() {
for (Element e : toAdd) {
elements.add(e);
if (e instanceof Creature) {
creatures.add((Creature) e);
} else if (e instanceof Vegetable) {
plants.add((Vegetable) e);
}
}
toAdd.clear();
elements.removeAll(graveyard); elements.removeAll(graveyard);
elements.removeAll(deadPlants); elements.removeAll(deadPlants);
plants.removeAll(deadPlants); plants.removeAll(deadPlants);
@ -69,14 +80,15 @@ public class World {
} }
}; };
if (graveyard.isEmpty() || restart) { // First gen if (graveyard.isEmpty() || restart) { // First gen
generation = 0; generation = 1;
Log.log(Log.INFO, "Starting from generation 1: spawning "+creatPerGen+" creatures.");
for (int i = 0; i < creatPerGen; i++) { for (int i = 0; i < creatPerGen; i++) {
spawnCreature(); spawnCreature();
} }
} else { // Evolve previous gen } else { // Evolve previous gen
graveyard.sort(creatureComp); // sort by fitness graveyard.sort(creatureComp); // sort by fitness
// Prepare best agent list // Prepare best agent list
int topSize = (int) Math.floor(graveyard.size() * 0.1f); int topSize = (int) Math.round(graveyard.size() * 0.05f);
Creature[] top = new Creature[topSize]; Creature[] top = new Creature[topSize];
// Calculate avg fitness and prepare best agent list // Calculate avg fitness and prepare best agent list
float avgFitness = 0; float avgFitness = 0;
@ -105,7 +117,7 @@ public class World {
Logger.getLogger(World.class.getName()).log(Level.SEVERE, null, ex); Logger.getLogger(World.class.getName()).log(Level.SEVERE, null, ex);
} }
Creature ne = spawnCreature(n); Creature ne = spawnCreature(n);
//ne.getBrain().mutate(0.1f); // mutate children ne.getBrain().mutate(0.05f); // mutate children
} }
graveyard.clear(); graveyard.clear();
generation++; generation++;
@ -136,12 +148,14 @@ public class World {
if (brainMap != null) { if (brainMap != null) {
c.getBrain().remap(brainMap); c.getBrain().remap(brainMap);
} }
//add(c);
elements.add(c); elements.add(c);
creatures.add(c); creatures.add(c);
return c; return c;
} else { } else {
Log.log(Log.DEBUG, "New Veg: " + x + " " + y); Log.log(Log.DEBUG, "New Veg: " + x + " " + y);
Vegetable v = new Vegetable(x, y); Vegetable v = new Vegetable(x, y);
//add(v);
elements.add(v); elements.add(v);
plants.add(v); plants.add(v);
return v; return v;
@ -168,6 +182,10 @@ public class World {
return height; return height;
} }
public void add(Element e) {
toAdd.add(e);
}
public ArrayList<Element> getElements() { public ArrayList<Element> getElements() {
return elements; return elements;
} }