mirror of
https://github.com/fazo96/AIrium.git
synced 2025-01-10 09:34:20 +01:00
added stuffffff and genetic algo
This commit is contained in:
parent
3d43a4ce68
commit
54e5dbb30f
51
core/src/com/mygdx/game/Camera.java
Normal file
51
core/src/com/mygdx/game/Camera.java
Normal 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;
|
||||
}
|
||||
|
||||
}
|
@ -4,8 +4,6 @@ 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.Texture;
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
|
||||
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
|
||||
import logic.Element;
|
||||
import logic.World;
|
||||
@ -13,39 +11,49 @@ import logic.World;
|
||||
public class Game extends ApplicationAdapter {
|
||||
|
||||
private static Game game;
|
||||
SpriteBatch batch;
|
||||
ShapeRenderer shaper;
|
||||
Texture img;
|
||||
private Camera camera;
|
||||
private World world;
|
||||
|
||||
@Override
|
||||
public void create() {
|
||||
game = this;
|
||||
batch = new SpriteBatch();
|
||||
img = new Texture("badlogic.jpg");
|
||||
world = new World(640, 480);
|
||||
world = new World(1920, 1080);
|
||||
shaper = new ShapeRenderer();
|
||||
camera = new Camera();
|
||||
//shaper.setAutoShapeType(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render() {
|
||||
// Input
|
||||
if(Gdx.input.isKeyJustPressed(Input.Keys.SPACE)){
|
||||
// Controls
|
||||
if (Gdx.input.isKeyJustPressed(Input.Keys.SPACE)) {
|
||||
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
|
||||
world.update();
|
||||
// Draw
|
||||
Gdx.gl.glClearColor(0, 0, 0, 1);
|
||||
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
|
||||
/*batch.begin();
|
||||
batch.draw(img, 0, 0);
|
||||
batch.end();*/
|
||||
shaper.setColor(1, 1, 1, 1);
|
||||
shaper.begin(ShapeRenderer.ShapeType.Line);
|
||||
//shaper.circle(640, 480, 100);
|
||||
for(Element e: world.getElements()) e.render(shaper);
|
||||
for (Element e : world.getElements()) {
|
||||
e.render(shaper);
|
||||
}
|
||||
shaper.setColor(0.3f, 0.3f, 0.3f, 1);
|
||||
shaper.rect(camera.getX(), camera.getY(), world.getWidth(), world.getHeight());
|
||||
shaper.end();
|
||||
}
|
||||
|
||||
@ -53,6 +61,10 @@ public class Game extends ApplicationAdapter {
|
||||
return world;
|
||||
}
|
||||
|
||||
public Camera getCamera() {
|
||||
return camera;
|
||||
}
|
||||
|
||||
public static Game get() {
|
||||
return game;
|
||||
}
|
||||
|
@ -3,6 +3,8 @@ package logic;
|
||||
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
|
||||
import com.mygdx.game.Game;
|
||||
import com.mygdx.game.Log;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import logic.neural.Brain;
|
||||
|
||||
/**
|
||||
@ -16,8 +18,8 @@ public class Creature extends Element {
|
||||
public static final float max_speed = 3;
|
||||
|
||||
private Brain brain;
|
||||
private float dir, speed, sightRange, fov, fitness, rotSpeed;
|
||||
private float hp;
|
||||
private float dir, hp, speed, sightRange, fov, fitness, rotSpeed;
|
||||
private boolean eating = false;
|
||||
private Sight sight;
|
||||
|
||||
public Creature(float x, float y) {
|
||||
@ -29,7 +31,7 @@ public class Creature extends Element {
|
||||
sightRange = 60;
|
||||
fov = (float) Math.PI / 1.5f;
|
||||
fitness = 0;
|
||||
brain = new Brain(3, 2, 2, 8);
|
||||
brain = new Brain(4, 3, 1, 6);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -48,12 +50,18 @@ public class Creature extends Element {
|
||||
// apply speed
|
||||
float xMul = (float) Math.cos(dir), yMul = (float) Math.sin(dir);
|
||||
move(xMul * speed, yMul * speed);
|
||||
if(getX() < 0) setX(0);
|
||||
if(getY() < 0) setX(0);
|
||||
if(getX() > Game.get().getWorld().getWidth())
|
||||
setX(Game.get().getWorld().getWidth());
|
||||
if(getY() > Game.get().getWorld().getHeight())
|
||||
setY(Game.get().getWorld().getHeight());
|
||||
if (getX() < 0) {
|
||||
setX(Game.get().getWorld().getWidth()+getX());
|
||||
}
|
||||
if (getY() < 0) {
|
||||
setX(Game.get().getWorld().getHeight()+getY());
|
||||
}
|
||||
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;
|
||||
// try eating
|
||||
eat();
|
||||
@ -66,29 +74,36 @@ public class Creature extends Element {
|
||||
}
|
||||
sight = look(); // take a look
|
||||
// feed data to brain
|
||||
float[] values = new float[3];
|
||||
// 0: type of sight
|
||||
float[] values = new float[4];
|
||||
// 0: see food
|
||||
// 1: distance
|
||||
// 2: angle
|
||||
if (sight == null) {
|
||||
// 3: food sensor
|
||||
if (sight == null || sight.getElement() == null) {
|
||||
values[0] = 0;
|
||||
values[1] = 1;
|
||||
values[1] = 0;
|
||||
values[2] = 0;
|
||||
} else if (sight.getElement() instanceof Creature) {
|
||||
values[0] = 1;
|
||||
} else if (sight.getElement() instanceof Vegetable) {
|
||||
values[1] = 1;
|
||||
values[1] = sight.getDistance() / sightRange;
|
||||
values[2] = sight.getAngle();
|
||||
} else {
|
||||
values[0] = 0.5f;
|
||||
values[0] = 0f;
|
||||
values[1] = sight.getDistance() / sightRange;
|
||||
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
|
||||
float[] actions = brain.compute();
|
||||
Log.log(Log.DEBUG,"Accel: " + actions[0] + " Rot: " + actions[1]);
|
||||
speed = actions[0]*max_speed;
|
||||
rotSpeed = actions[1]/10;
|
||||
Log.log(Log.DEBUG, "Accel: " + actions[0] + " RotClock: " + actions[1] + " RotAntiClock: " + actions[2]);
|
||||
speed = actions[0] * max_speed;
|
||||
rotSpeed = actions[1] - actions[2];
|
||||
}
|
||||
|
||||
public void setHp(float hp) {
|
||||
@ -99,25 +114,24 @@ public class Creature extends Element {
|
||||
public void render(ShapeRenderer s) {
|
||||
// Body
|
||||
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
|
||||
double relX = Math.cos(dir) * getSize(), relY = Math.sin(dir) * getSize();
|
||||
s.setColor(1, 1, 1, 1);
|
||||
if (sight != null) {
|
||||
float c = sight.getDistance() / sightRange*2 + sightRange;
|
||||
float c = sight.getDistance() / sightRange * 2 + sightRange;
|
||||
if (sight.getElement() instanceof Creature) {
|
||||
s.setColor(c, 0, 0, 1);
|
||||
} else if (sight.getElement() instanceof Vegetable) {
|
||||
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
|
||||
float degrees = fov * 180f / (float) Math.PI;
|
||||
float orient = dir * 180f / (float) Math.PI - degrees / 2;
|
||||
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() {
|
||||
@ -153,9 +167,12 @@ public class Creature extends Element {
|
||||
}
|
||||
|
||||
public void eat() {
|
||||
for (Element e : Game.get().getWorld().getElements()) {
|
||||
if (e instanceof Vegetable && overlaps(e)) {
|
||||
eating = false;
|
||||
for (Element e : Game.get().getWorld().getPlants()) {
|
||||
if (overlaps(e)) {
|
||||
eating = true;
|
||||
e.setSize(e.getSize() - 0.1f);
|
||||
if(e.getSize() == 0) e.setSize(0);
|
||||
hp++;
|
||||
fitness++;
|
||||
if (hp > 100) {
|
||||
@ -177,9 +194,9 @@ public class Creature extends Element {
|
||||
return fitness;
|
||||
}
|
||||
|
||||
public void reset(){
|
||||
public void reset() {
|
||||
fitness = 0;
|
||||
hp = 100;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ public class Vegetable extends Element {
|
||||
|
||||
@Override
|
||||
public void update() {
|
||||
if(getSize() < 0){
|
||||
if (getSize() <= 0) {
|
||||
Game.get().getWorld().getDeadPlants().add(this);
|
||||
}
|
||||
}
|
||||
@ -31,6 +31,6 @@ public class Vegetable extends Element {
|
||||
@Override
|
||||
public void render(ShapeRenderer s) {
|
||||
s.setColor(1, 1, 1, 1);
|
||||
s.circle(getX(), getY(), getSize());
|
||||
s.circle(getX() + Game.get().getCamera().getX(), getY() + Game.get().getCamera().getY(), getSize());
|
||||
}
|
||||
}
|
||||
|
@ -41,16 +41,16 @@ public class World {
|
||||
elements.removeAll(graveyard);
|
||||
elements.removeAll(deadPlants);
|
||||
plants.removeAll(deadPlants);
|
||||
creatures.removeAll(graveyard);
|
||||
deadPlants.clear();
|
||||
creatures.removeAll(graveyard);
|
||||
if (creatures.isEmpty()) {
|
||||
// All dead, next gen
|
||||
newGen(false);
|
||||
}
|
||||
while (plants.size() < 50) {
|
||||
while (plants.size() < (width*height)/5000) {
|
||||
spawnVegetable();
|
||||
}
|
||||
for (Creature e : creatures) {
|
||||
for (Element e : elements) {
|
||||
e.update();
|
||||
}
|
||||
}
|
||||
@ -63,7 +63,7 @@ public class World {
|
||||
@Override
|
||||
public int compare(Creature t, Creature t1) {
|
||||
// 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()) {
|
||||
return -1;
|
||||
} else if (t.getFitness() > t1.getFitness()) {
|
||||
@ -132,7 +132,7 @@ public class World {
|
||||
}
|
||||
} while (overlaps);
|
||||
if (isCreature) {
|
||||
Log.log(Log.INFO, "New Creat: " + x + " " + y);
|
||||
Log.log(Log.DEBUG, "New Creat: " + x + " " + y);
|
||||
Creature c = new Creature(x, y);
|
||||
if (brainMap != null) {
|
||||
c.getBrain().remap(brainMap);
|
||||
@ -140,7 +140,7 @@ public class World {
|
||||
elements.add(c);
|
||||
creatures.add(c);
|
||||
} else {
|
||||
Log.log(Log.INFO, "New Veg: " + x + " " + y);
|
||||
Log.log(Log.DEBUG, "New Veg: " + x + " " + y);
|
||||
Vegetable v = new Vegetable(x, y);
|
||||
elements.add(v);
|
||||
plants.add(v);
|
||||
@ -179,4 +179,12 @@ public class World {
|
||||
return deadPlants;
|
||||
}
|
||||
|
||||
public ArrayList<Creature> getCreatures() {
|
||||
return creatures;
|
||||
}
|
||||
|
||||
public ArrayList<Vegetable> getPlants() {
|
||||
return plants;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -57,10 +57,10 @@ public class Brain {
|
||||
for (int i = 0; i < brainMap.length; i++) { // for each layer
|
||||
for (int j = 0; j < brainMap[i].length; j++) { // for each neuron
|
||||
// skip input layer
|
||||
if (neurons[i+1][j] == null) {
|
||||
neurons[i+1][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 {
|
||||
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
|
||||
* 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++) {
|
||||
neurons[0][i].setOutput(values[i]);
|
||||
}
|
||||
@ -114,8 +119,10 @@ public class Brain {
|
||||
*
|
||||
* @param values
|
||||
* @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);
|
||||
return compute();
|
||||
}
|
||||
@ -127,13 +134,13 @@ public class Brain {
|
||||
* mind
|
||||
*/
|
||||
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)
|
||||
{
|
||||
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
|
||||
{
|
||||
res[i-1][j] = neurons[i][j].getWeights();
|
||||
res[i - 1][j] = neurons[i][j].getWeights();
|
||||
}
|
||||
}
|
||||
return res;
|
||||
@ -146,27 +153,27 @@ public class Brain {
|
||||
* @return a mutated brain map of this brain's mind
|
||||
*/
|
||||
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)
|
||||
{
|
||||
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
|
||||
{
|
||||
res[i-1][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) {
|
||||
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) {
|
||||
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
|
||||
@ -174,17 +181,17 @@ public class Brain {
|
||||
// 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) {
|
||||
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];
|
||||
res[i - 1][j][z] = map[i - 1][j][z];
|
||||
} else {
|
||||
res[i-1][j][z] = neurons[i][j].getWeights()[z];
|
||||
res[i - 1][j][z] = neurons[i][j].getWeights()[z];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user