mirror of
https://github.com/fazo96/AIrium.git
synced 2025-01-09 09:29:53 +01:00
performance improvements and some javadocs
This commit is contained in:
parent
abb3c96cdf
commit
70089e4379
@ -8,7 +8,7 @@ import java.util.logging.Logger;
|
||||
import logic.neural.Brain;
|
||||
|
||||
/**
|
||||
* A (hopefully) smart biological creature.
|
||||
* A (hopefully) smart biological creature in the simulated world.
|
||||
*
|
||||
* @author fazo
|
||||
*/
|
||||
@ -24,6 +24,12 @@ public class Creature extends Element implements Runnable {
|
||||
private Sight[] sights;
|
||||
private Thread workerThread;
|
||||
|
||||
/**
|
||||
* Create a creature with a random mind at given position in space
|
||||
*
|
||||
* @param x
|
||||
* @param y
|
||||
*/
|
||||
public Creature(float x, float y) {
|
||||
super(x, y, default_radius);
|
||||
dir = (float) (Math.random() * 2 * Math.PI);
|
||||
@ -157,13 +163,14 @@ public class Creature extends Element implements Runnable {
|
||||
|
||||
@Override
|
||||
public void render(ShapeRenderer s) {
|
||||
// Body
|
||||
// Draw Body
|
||||
s.setColor(1 - (hp / max_hp), hp / max_hp, 0, 1);
|
||||
s.circle(getX(), getY(), getSize());
|
||||
// Vision
|
||||
// Prepare vision stuff
|
||||
double relX = Math.cos(dir), relY = Math.sin(dir);
|
||||
float c = 0;
|
||||
float eyeX = (float) (relX * getSize() * 0.6f), eyeY = (float) (relY * getSize() * 0.6f);
|
||||
// Draw Sight Lines
|
||||
if (Game.get().getWorld().getOptions().getOrDefault("draw_sight_lines", 0f) > 0) {
|
||||
for (Sight sight : sights) {
|
||||
if (sight != null) {
|
||||
@ -180,19 +187,21 @@ public class Creature extends Element implements Runnable {
|
||||
}
|
||||
}
|
||||
}
|
||||
// Draw eye
|
||||
if (sights[0] == null && sights[1] == null) {
|
||||
s.setColor(1, 1, 1, 1);
|
||||
} else {
|
||||
s.setColor(sights[1] == null ? 0 : 1, sights[0] == null ? 0 : 1, 0, 1);
|
||||
}
|
||||
s.circle(getX() + eyeX, getY() + eyeY, 3);
|
||||
//FOV
|
||||
// Draw FOV cone
|
||||
float degrees = fov * 360f / (float) Math.PI;
|
||||
float orient = dir * 180f / (float) Math.PI - degrees / 2;
|
||||
if (Game.get().getWorld().getOptions().getOrDefault("draw_view_cones", 0f) > 0) {
|
||||
s.setColor(0.3f, 0.3f, 0.3f, 1);
|
||||
s.arc((float) eyeX + getX(), (float) eyeY + getY(), sightRange, orient, degrees);
|
||||
}
|
||||
// Draw damage/heal marks
|
||||
if (hp < prevHp) {
|
||||
// Damage mark
|
||||
s.set(ShapeRenderer.ShapeType.Filled);
|
||||
@ -205,11 +214,17 @@ public class Creature extends Element implements Runnable {
|
||||
s.circle(getX(), getY(), 5);
|
||||
}
|
||||
s.set(ShapeRenderer.ShapeType.Line);
|
||||
// Beak
|
||||
// Draw Beak
|
||||
s.setColor(beak / max_beak, 1 - beak / max_beak, 0, 1);
|
||||
s.line((float) (relX * getSize() * 0.8f + getX()), (float) (relY * getSize() * 0.8f + getY()), (float) (relX * getSize() * (1.5f + beak / max_beak) + getX()), (float) (relY * getSize() * (1.5f + beak / max_beak) + getY()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Store Sight information (what the creature sees) and eat/attack if
|
||||
* applicable
|
||||
*
|
||||
* @return the sight information retrieved
|
||||
*/
|
||||
public Sight[] interactWithWorld() {
|
||||
Sight[] newSights = new Sight[2];
|
||||
// Try to see plant
|
||||
@ -299,28 +314,21 @@ public class Creature extends Element implements Runnable {
|
||||
return newSights;
|
||||
}
|
||||
|
||||
public void eat() {
|
||||
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 > max_hp) {
|
||||
hp = max_hp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply a modification to this creature's health. Can be negative.
|
||||
*
|
||||
* @param amount how much to heal/damage
|
||||
*/
|
||||
private void heal(float amount) {
|
||||
hp += amount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Praise this creature by increasing fitness. Can be negative to decrease
|
||||
* fitness
|
||||
*
|
||||
* @param amount how much
|
||||
*/
|
||||
private void praise(float amount) {
|
||||
fitness += amount;
|
||||
}
|
||||
@ -340,9 +348,11 @@ public class Creature extends Element implements Runnable {
|
||||
public void startWorker() {
|
||||
workerDone = false;
|
||||
if (workerThread == null) {
|
||||
// Create a new thread
|
||||
workerThread = new Thread(this);
|
||||
workerThread.start();
|
||||
} else {
|
||||
// Interrupt current thread, throwing it out of sleep
|
||||
workerThread.interrupt();
|
||||
}
|
||||
}
|
||||
|
@ -1,13 +1,9 @@
|
||||
/*
|
||||
* 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 logic;
|
||||
|
||||
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
|
||||
|
||||
/**
|
||||
* Represents a dynamic simulation element with a circular shape
|
||||
*
|
||||
* @author fazo
|
||||
*/
|
||||
@ -15,35 +11,89 @@ public abstract class Element {
|
||||
|
||||
private float x, y, size;
|
||||
|
||||
/**
|
||||
* Create an element at given position with given radius. Elements have a
|
||||
* circular shape.
|
||||
*
|
||||
* @param x the x position
|
||||
* @param y the y position
|
||||
* @param size the element body radius
|
||||
*/
|
||||
public Element(float x, float y, float size) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the distance between the circumference of this element and
|
||||
* another one's, taking into account the size. This means that two elements
|
||||
* whose circumference is touching will have a distance of 0, and two
|
||||
* overlapping elements will have a negative distance
|
||||
*
|
||||
* @param e the element whose distance from this one will be checked
|
||||
* @return the distance from the element. It's 0 if they are just touching,
|
||||
* negative if they are colliding and positive if they are not
|
||||
*/
|
||||
public float distanceFrom(Element e) {
|
||||
return (float) Math.sqrt(Math.pow(e.x - x, 2) + Math.pow(e.y - y, 2)) - getSize() - e.getSize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this element overlaps another one, causing a collision
|
||||
*
|
||||
* @param e the element which position will be checked to see if it overlaps
|
||||
* this one
|
||||
* @return true if the elements are overlapping, causing a collision
|
||||
*/
|
||||
public boolean overlaps(Element e) {
|
||||
return distanceFrom(e) < 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this element overlaps a circular object, causing a collision
|
||||
*
|
||||
* @param x the position of the center of the circular object
|
||||
* @param y the position of the center of the circular object
|
||||
* @param radius the radius of the circular object
|
||||
* @return true if the object overlaps this one
|
||||
*/
|
||||
public boolean overlaps(float x, float y, float radius) {
|
||||
return (float) Math.sqrt(Math.pow(x - this.x, 2) + Math.pow(y - this.y, 2)) < getSize() + radius;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a point in space occupies the same space as this object
|
||||
*
|
||||
* @param x the x position of the point to check
|
||||
* @param y the y position of the point to check
|
||||
* @return true if the point is part of this object's area
|
||||
*/
|
||||
public boolean overlaps(float x, float y) {
|
||||
return overlaps(x, y, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate this object is space
|
||||
*
|
||||
* @param deltaX x translation
|
||||
* @param deltaY y translation
|
||||
*/
|
||||
public void move(float deltaX, float deltaY) {
|
||||
x += deltaX;
|
||||
y += deltaY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run one iteration of this object's logic
|
||||
*/
|
||||
public abstract void update();
|
||||
|
||||
/**
|
||||
* Draw this object
|
||||
*
|
||||
* @param s the ShapeRenderer used to draw this object
|
||||
*/
|
||||
public abstract void render(ShapeRenderer s);
|
||||
|
||||
public float getX() {
|
||||
|
@ -1,15 +1,12 @@
|
||||
/*
|
||||
* 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 logic;
|
||||
|
||||
/**
|
||||
* Stores a sight of an element, as seen from a creature's eye
|
||||
*
|
||||
* @author fazo
|
||||
*/
|
||||
public class Sight {
|
||||
|
||||
private Element seen;
|
||||
private float distance, angle;
|
||||
|
||||
@ -30,5 +27,5 @@ public class Sight {
|
||||
public float getAngle() {
|
||||
return angle;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -1,15 +1,10 @@
|
||||
/*
|
||||
* 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 logic;
|
||||
|
||||
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
|
||||
import com.mygdx.game.Game;
|
||||
|
||||
/**
|
||||
*
|
||||
* Represents a small plant-like vegetable with circular shape
|
||||
* @author fazo
|
||||
*/
|
||||
public class Vegetable extends Element {
|
||||
|
@ -1,8 +1,3 @@
|
||||
/*
|
||||
* 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 logic;
|
||||
|
||||
import com.mygdx.game.Game;
|
||||
@ -18,6 +13,8 @@ import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* This class represents an instance of a simulation, its world and its
|
||||
* configuration
|
||||
*
|
||||
* @author fazo
|
||||
*/
|
||||
@ -40,6 +37,12 @@ public class World implements Runnable {
|
||||
private final ArrayList<Vegetable> deadPlants;
|
||||
private final ArrayList<Listener> listeners;
|
||||
|
||||
/**
|
||||
* Create a new World. Can be customized with given options.
|
||||
*
|
||||
* @param options customization options. Can be null. See the
|
||||
* "reloadOptions" function for possible options
|
||||
*/
|
||||
public World(Map<String, Float> options) {
|
||||
if (options == null) {
|
||||
this.options = new HashMap<String, Float>();
|
||||
@ -240,6 +243,10 @@ public class World implements Runnable {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies current options. Uses default alternatives if options are not
|
||||
* provided
|
||||
*/
|
||||
public void reloadOptions() {
|
||||
width = Math.round(options.getOrDefault("world_width", 2000f));
|
||||
height = Math.round(options.getOrDefault("world_height", 2000f));
|
||||
@ -262,6 +269,14 @@ public class World implements Runnable {
|
||||
mutationFactor = options.getOrDefault("nMutationFactor", 1f);
|
||||
}
|
||||
|
||||
/**
|
||||
* Spawn a new random element in the world, at a random position.
|
||||
*
|
||||
* @param isCreature true if you want to spawn a creature
|
||||
* @param brainMap the brain configuration. Used if spawning a creature. If
|
||||
* null, a random mind will be created
|
||||
* @return the spawned element
|
||||
*/
|
||||
private Element spawn(boolean isCreature, float[][][] brainMap) {
|
||||
int x, y, r;
|
||||
boolean overlaps = false;
|
||||
@ -301,6 +316,13 @@ public class World implements Runnable {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets currently select creature to the first creature that overlaps given
|
||||
* coordinates
|
||||
*
|
||||
* @param x the x coordinate of the creature you want to select
|
||||
* @param y the x coordinate of the creature you want to select
|
||||
*/
|
||||
public void selectCreatureAt(int x, int y) {
|
||||
selected = null; // Clear selection
|
||||
try {
|
||||
@ -314,6 +336,12 @@ public class World implements Runnable {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fire an event
|
||||
*
|
||||
* @param eventCode the event code. Look at the Listener class for event
|
||||
* codes.
|
||||
*/
|
||||
public void fire(int eventCode) {
|
||||
for (Listener f : listeners) {
|
||||
f.on(eventCode);
|
||||
|
@ -83,7 +83,7 @@ public class Brain {
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw this brain's status.
|
||||
* Draw this brain's status to the screen.
|
||||
*
|
||||
* @param s the ShapeRenderer to use for the drawing
|
||||
*/
|
||||
@ -224,6 +224,17 @@ public class Brain {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Combine this brain with another one's map to get an offspring. The brains
|
||||
* must have identical neuron configuration. There are huge amounts of
|
||||
* combinations, so you can call multiple times to get different children
|
||||
* from the same parents
|
||||
*
|
||||
* @param map the brain to "breed" with this one
|
||||
* @return a child brain from the two brains
|
||||
* @throws Exception if the brains don't have identical neuron and layer
|
||||
* numbers
|
||||
*/
|
||||
public float[][][] breed(float[][][] map) throws Exception {
|
||||
float[][][] res = new float[neurons.length - 1][][];
|
||||
if (map.length != neurons.length - 1) {
|
||||
@ -237,9 +248,6 @@ public class Brain {
|
||||
}
|
||||
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");
|
||||
|
@ -1,8 +1,3 @@
|
||||
/*
|
||||
* 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 logic.neural;
|
||||
|
||||
import com.mygdx.game.Log;
|
||||
@ -10,6 +5,7 @@ import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* A neuron in some brain. See Brain class.
|
||||
*
|
||||
* @author fazo
|
||||
*/
|
||||
@ -22,10 +18,27 @@ public class Neuron {
|
||||
private int layer;
|
||||
private Brain brain;
|
||||
|
||||
/**
|
||||
* Create a neuron with given brain, bias, and at the given layer with 0
|
||||
* being the input layer, with random weights
|
||||
*
|
||||
* @param layer the layer in which this neuron is positioned
|
||||
* @param bias the bias of this neuron
|
||||
* @param brain the brain which contains this neuron
|
||||
*/
|
||||
public Neuron(int layer, float bias, Brain brain) {
|
||||
this(layer, bias, brain, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a neuron with given brain, bias, and at the given layer with 0
|
||||
* being the input layer, with given weights
|
||||
*
|
||||
* @param layer the layer in which this neuron is positioned
|
||||
* @param bias the bias of this neuron
|
||||
* @param brain the brain which contains this neuron
|
||||
* @param weights the weights to use to configure this neuron
|
||||
*/
|
||||
public Neuron(int layer, float bias, Brain brain, float[] weights) {
|
||||
this.brain = brain;
|
||||
this.layer = layer;
|
||||
@ -37,6 +50,9 @@ public class Neuron {
|
||||
cache = new NeuronCache(this.weights.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Randomize the weights of this neuron
|
||||
*/
|
||||
private void scramble() {
|
||||
// init weights
|
||||
if (layer > 0) {
|
||||
@ -51,6 +67,14 @@ public class Neuron {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the output of this neuron using the previous layer. Does nothing
|
||||
* with input neurons. Uses a cache to store the output until it is
|
||||
* invalidated by using the clearCache function. This function is recursive,
|
||||
* meaning it will calculate all necessary neuron outputs to get this one.
|
||||
*
|
||||
* @return the output of this neuron.
|
||||
*/
|
||||
public float compute() {
|
||||
if (isInputNeuron) {
|
||||
return output;
|
||||
@ -67,16 +91,27 @@ public class Neuron {
|
||||
// This should never happen
|
||||
Logger.getLogger(Neuron.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
} else {
|
||||
Neuron n = brain.getNeurons()[layer - 1][i];
|
||||
float v = n.compute() * weights[i];
|
||||
a += v;
|
||||
cache.put(i, v);
|
||||
}
|
||||
Neuron n = brain.getNeurons()[layer - 1][i];
|
||||
a += n.compute() * weights[i];
|
||||
}
|
||||
// sigmoid function
|
||||
float res = (float) (1 / (1 + Math.pow(Math.E, a * -1)));
|
||||
cache.setCachedOutput(res);
|
||||
Log.log(Log.DEBUG, "Computed Value " + res + " for neuron");
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a copy of the weights, with a mutation
|
||||
*
|
||||
* @param mutationProbability controls how many weights actually mutates
|
||||
* @param mutationFactor controls how much weights mutate
|
||||
* @return the new weights
|
||||
*/
|
||||
public float[] getMutatedWeights(float mutationProbability, float mutationFactor) {
|
||||
float[] mutatedWeights = new float[weights.length];
|
||||
for (int i = 0; i < weights.length; i++) {
|
||||
@ -90,27 +125,10 @@ public class Neuron {
|
||||
}
|
||||
|
||||
/**
|
||||
* Broken, doesn't work for some reason.
|
||||
* Use this to manually set the output of input neurons
|
||||
*
|
||||
* @return
|
||||
* @param output the output you want to set
|
||||
*/
|
||||
public float[] getInputs() {
|
||||
float inputs[] = new float[weights.length];
|
||||
for (int i = 0; i < inputs.length; i++) {
|
||||
if (cache.has(i)) {
|
||||
try {
|
||||
inputs[i] = cache.get(i);
|
||||
} catch (Exception ex) {
|
||||
// Shouldnt happen
|
||||
Logger.getLogger(Neuron.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
} else {
|
||||
inputs[i] = 0;
|
||||
}
|
||||
}
|
||||
return inputs;
|
||||
}
|
||||
|
||||
public void setOutput(float output) {
|
||||
isInputNeuron = true;
|
||||
this.output = output;
|
||||
@ -140,6 +158,11 @@ public class Neuron {
|
||||
return weights;
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the neuron weights
|
||||
*
|
||||
* @param weights the new weights to put
|
||||
*/
|
||||
public void setWeights(float[] weights) {
|
||||
this.weights = weights;
|
||||
// Changing the neuron makes the cache invalid
|
||||
|
Loading…
Reference in New Issue
Block a user