mirror of
https://github.com/fazo96/AIrium.git
synced 2025-01-25 11:54:20 +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;
|
import logic.neural.Brain;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A (hopefully) smart biological creature.
|
* A (hopefully) smart biological creature in the simulated world.
|
||||||
*
|
*
|
||||||
* @author fazo
|
* @author fazo
|
||||||
*/
|
*/
|
||||||
@ -24,6 +24,12 @@ public class Creature extends Element implements Runnable {
|
|||||||
private Sight[] sights;
|
private Sight[] sights;
|
||||||
private Thread workerThread;
|
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) {
|
public Creature(float x, float y) {
|
||||||
super(x, y, default_radius);
|
super(x, y, default_radius);
|
||||||
dir = (float) (Math.random() * 2 * Math.PI);
|
dir = (float) (Math.random() * 2 * Math.PI);
|
||||||
@ -157,13 +163,14 @@ public class Creature extends Element implements Runnable {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void render(ShapeRenderer s) {
|
public void render(ShapeRenderer s) {
|
||||||
// Body
|
// Draw Body
|
||||||
s.setColor(1 - (hp / max_hp), hp / max_hp, 0, 1);
|
s.setColor(1 - (hp / max_hp), hp / max_hp, 0, 1);
|
||||||
s.circle(getX(), getY(), getSize());
|
s.circle(getX(), getY(), getSize());
|
||||||
// Vision
|
// Prepare vision stuff
|
||||||
double relX = Math.cos(dir), relY = Math.sin(dir);
|
double relX = Math.cos(dir), relY = Math.sin(dir);
|
||||||
float c = 0;
|
float c = 0;
|
||||||
float eyeX = (float) (relX * getSize() * 0.6f), eyeY = (float) (relY * getSize() * 0.6f);
|
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) {
|
if (Game.get().getWorld().getOptions().getOrDefault("draw_sight_lines", 0f) > 0) {
|
||||||
for (Sight sight : sights) {
|
for (Sight sight : sights) {
|
||||||
if (sight != null) {
|
if (sight != null) {
|
||||||
@ -180,19 +187,21 @@ public class Creature extends Element implements Runnable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Draw eye
|
||||||
if (sights[0] == null && sights[1] == null) {
|
if (sights[0] == null && sights[1] == null) {
|
||||||
s.setColor(1, 1, 1, 1);
|
s.setColor(1, 1, 1, 1);
|
||||||
} else {
|
} else {
|
||||||
s.setColor(sights[1] == null ? 0 : 1, sights[0] == null ? 0 : 1, 0, 1);
|
s.setColor(sights[1] == null ? 0 : 1, sights[0] == null ? 0 : 1, 0, 1);
|
||||||
}
|
}
|
||||||
s.circle(getX() + eyeX, getY() + eyeY, 3);
|
s.circle(getX() + eyeX, getY() + eyeY, 3);
|
||||||
//FOV
|
// Draw FOV cone
|
||||||
float degrees = fov * 360f / (float) Math.PI;
|
float degrees = fov * 360f / (float) Math.PI;
|
||||||
float orient = dir * 180f / (float) Math.PI - degrees / 2;
|
float orient = dir * 180f / (float) Math.PI - degrees / 2;
|
||||||
if (Game.get().getWorld().getOptions().getOrDefault("draw_view_cones", 0f) > 0) {
|
if (Game.get().getWorld().getOptions().getOrDefault("draw_view_cones", 0f) > 0) {
|
||||||
s.setColor(0.3f, 0.3f, 0.3f, 1);
|
s.setColor(0.3f, 0.3f, 0.3f, 1);
|
||||||
s.arc((float) eyeX + getX(), (float) eyeY + getY(), sightRange, orient, degrees);
|
s.arc((float) eyeX + getX(), (float) eyeY + getY(), sightRange, orient, degrees);
|
||||||
}
|
}
|
||||||
|
// Draw damage/heal marks
|
||||||
if (hp < prevHp) {
|
if (hp < prevHp) {
|
||||||
// Damage mark
|
// Damage mark
|
||||||
s.set(ShapeRenderer.ShapeType.Filled);
|
s.set(ShapeRenderer.ShapeType.Filled);
|
||||||
@ -205,11 +214,17 @@ public class Creature extends Element implements Runnable {
|
|||||||
s.circle(getX(), getY(), 5);
|
s.circle(getX(), getY(), 5);
|
||||||
}
|
}
|
||||||
s.set(ShapeRenderer.ShapeType.Line);
|
s.set(ShapeRenderer.ShapeType.Line);
|
||||||
// Beak
|
// Draw Beak
|
||||||
s.setColor(beak / max_beak, 1 - beak / max_beak, 0, 1);
|
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()));
|
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() {
|
public Sight[] interactWithWorld() {
|
||||||
Sight[] newSights = new Sight[2];
|
Sight[] newSights = new Sight[2];
|
||||||
// Try to see plant
|
// Try to see plant
|
||||||
@ -299,28 +314,21 @@ public class Creature extends Element implements Runnable {
|
|||||||
return newSights;
|
return newSights;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void eat() {
|
/**
|
||||||
eating = false;
|
* Apply a modification to this creature's health. Can be negative.
|
||||||
for (Element e : Game.get().getWorld().getPlants()) {
|
*
|
||||||
if (overlaps(e)) {
|
* @param amount how much to heal/damage
|
||||||
eating = true;
|
*/
|
||||||
e.setSize(e.getSize() - 0.1f);
|
|
||||||
if (e.getSize() == 0) {
|
|
||||||
e.setSize(0);
|
|
||||||
}
|
|
||||||
hp++;
|
|
||||||
fitness++;
|
|
||||||
if (hp > max_hp) {
|
|
||||||
hp = max_hp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void heal(float amount) {
|
private void heal(float amount) {
|
||||||
hp += amount;
|
hp += amount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Praise this creature by increasing fitness. Can be negative to decrease
|
||||||
|
* fitness
|
||||||
|
*
|
||||||
|
* @param amount how much
|
||||||
|
*/
|
||||||
private void praise(float amount) {
|
private void praise(float amount) {
|
||||||
fitness += amount;
|
fitness += amount;
|
||||||
}
|
}
|
||||||
@ -340,9 +348,11 @@ public class Creature extends Element implements Runnable {
|
|||||||
public void startWorker() {
|
public void startWorker() {
|
||||||
workerDone = false;
|
workerDone = false;
|
||||||
if (workerThread == null) {
|
if (workerThread == null) {
|
||||||
|
// Create a new thread
|
||||||
workerThread = new Thread(this);
|
workerThread = new Thread(this);
|
||||||
workerThread.start();
|
workerThread.start();
|
||||||
} else {
|
} else {
|
||||||
|
// Interrupt current thread, throwing it out of sleep
|
||||||
workerThread.interrupt();
|
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;
|
package logic;
|
||||||
|
|
||||||
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
|
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Represents a dynamic simulation element with a circular shape
|
||||||
*
|
*
|
||||||
* @author fazo
|
* @author fazo
|
||||||
*/
|
*/
|
||||||
@ -15,35 +11,89 @@ public abstract class Element {
|
|||||||
|
|
||||||
private float x, y, size;
|
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) {
|
public Element(float x, float y, float size) {
|
||||||
this.x = x;
|
this.x = x;
|
||||||
this.y = y;
|
this.y = y;
|
||||||
this.size = size;
|
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) {
|
public float distanceFrom(Element e) {
|
||||||
return (float) Math.sqrt(Math.pow(e.x - x, 2) + Math.pow(e.y - y, 2)) - getSize() - e.getSize();
|
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) {
|
public boolean overlaps(Element e) {
|
||||||
return distanceFrom(e) < 0;
|
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) {
|
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;
|
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) {
|
public boolean overlaps(float x, float y) {
|
||||||
return overlaps(x, y, 1);
|
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) {
|
public void move(float deltaX, float deltaY) {
|
||||||
x += deltaX;
|
x += deltaX;
|
||||||
y += deltaY;
|
y += deltaY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run one iteration of this object's logic
|
||||||
|
*/
|
||||||
public abstract void update();
|
public abstract void update();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draw this object
|
||||||
|
*
|
||||||
|
* @param s the ShapeRenderer used to draw this object
|
||||||
|
*/
|
||||||
public abstract void render(ShapeRenderer s);
|
public abstract void render(ShapeRenderer s);
|
||||||
|
|
||||||
public float getX() {
|
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;
|
package logic;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Stores a sight of an element, as seen from a creature's eye
|
||||||
*
|
*
|
||||||
* @author fazo
|
* @author fazo
|
||||||
*/
|
*/
|
||||||
public class Sight {
|
public class Sight {
|
||||||
|
|
||||||
private Element seen;
|
private Element seen;
|
||||||
private float distance, angle;
|
private float distance, 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;
|
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;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* Represents a small plant-like vegetable with circular shape
|
||||||
* @author fazo
|
* @author fazo
|
||||||
*/
|
*/
|
||||||
public class Vegetable extends Element {
|
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;
|
package logic;
|
||||||
|
|
||||||
import com.mygdx.game.Game;
|
import com.mygdx.game.Game;
|
||||||
@ -18,6 +13,8 @@ import java.util.logging.Level;
|
|||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* This class represents an instance of a simulation, its world and its
|
||||||
|
* configuration
|
||||||
*
|
*
|
||||||
* @author fazo
|
* @author fazo
|
||||||
*/
|
*/
|
||||||
@ -40,6 +37,12 @@ public class World implements Runnable {
|
|||||||
private final ArrayList<Vegetable> deadPlants;
|
private final ArrayList<Vegetable> deadPlants;
|
||||||
private final ArrayList<Listener> listeners;
|
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) {
|
public World(Map<String, Float> options) {
|
||||||
if (options == null) {
|
if (options == null) {
|
||||||
this.options = new HashMap<String, Float>();
|
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() {
|
public void reloadOptions() {
|
||||||
width = Math.round(options.getOrDefault("world_width", 2000f));
|
width = Math.round(options.getOrDefault("world_width", 2000f));
|
||||||
height = Math.round(options.getOrDefault("world_height", 2000f));
|
height = Math.round(options.getOrDefault("world_height", 2000f));
|
||||||
@ -262,6 +269,14 @@ public class World implements Runnable {
|
|||||||
mutationFactor = options.getOrDefault("nMutationFactor", 1f);
|
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) {
|
private Element spawn(boolean isCreature, float[][][] brainMap) {
|
||||||
int x, y, r;
|
int x, y, r;
|
||||||
boolean overlaps = false;
|
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) {
|
public void selectCreatureAt(int x, int y) {
|
||||||
selected = null; // Clear selection
|
selected = null; // Clear selection
|
||||||
try {
|
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) {
|
public void fire(int eventCode) {
|
||||||
for (Listener f : listeners) {
|
for (Listener f : listeners) {
|
||||||
f.on(eventCode);
|
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
|
* @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 {
|
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) {
|
||||||
@ -237,9 +248,6 @@ public class Brain {
|
|||||||
}
|
}
|
||||||
for (int j = 0; j < neurons[i].length; j++) // neurons per layer
|
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];
|
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");
|
||||||
|
@ -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;
|
package logic.neural;
|
||||||
|
|
||||||
import com.mygdx.game.Log;
|
import com.mygdx.game.Log;
|
||||||
@ -10,6 +5,7 @@ import java.util.logging.Level;
|
|||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* A neuron in some brain. See Brain class.
|
||||||
*
|
*
|
||||||
* @author fazo
|
* @author fazo
|
||||||
*/
|
*/
|
||||||
@ -22,10 +18,27 @@ public class Neuron {
|
|||||||
private int layer;
|
private int layer;
|
||||||
private Brain brain;
|
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) {
|
public Neuron(int layer, float bias, Brain brain) {
|
||||||
this(layer, bias, brain, null);
|
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) {
|
public Neuron(int layer, float bias, Brain brain, float[] weights) {
|
||||||
this.brain = brain;
|
this.brain = brain;
|
||||||
this.layer = layer;
|
this.layer = layer;
|
||||||
@ -37,6 +50,9 @@ public class Neuron {
|
|||||||
cache = new NeuronCache(this.weights.length);
|
cache = new NeuronCache(this.weights.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Randomize the weights of this neuron
|
||||||
|
*/
|
||||||
private void scramble() {
|
private void scramble() {
|
||||||
// init weights
|
// init weights
|
||||||
if (layer > 0) {
|
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() {
|
public float compute() {
|
||||||
if (isInputNeuron) {
|
if (isInputNeuron) {
|
||||||
return output;
|
return output;
|
||||||
@ -67,16 +91,27 @@ public class Neuron {
|
|||||||
// This should never happen
|
// This should never happen
|
||||||
Logger.getLogger(Neuron.class.getName()).log(Level.SEVERE, null, ex);
|
Logger.getLogger(Neuron.class.getName()).log(Level.SEVERE, null, ex);
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
Neuron n = brain.getNeurons()[layer - 1][i];
|
Neuron n = brain.getNeurons()[layer - 1][i];
|
||||||
a += n.compute() * weights[i];
|
float v = n.compute() * weights[i];
|
||||||
|
a += v;
|
||||||
|
cache.put(i, v);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// sigmoid function
|
// sigmoid function
|
||||||
float res = (float) (1 / (1 + Math.pow(Math.E, a * -1)));
|
float res = (float) (1 / (1 + Math.pow(Math.E, a * -1)));
|
||||||
|
cache.setCachedOutput(res);
|
||||||
Log.log(Log.DEBUG, "Computed Value " + res + " for neuron");
|
Log.log(Log.DEBUG, "Computed Value " + res + " for neuron");
|
||||||
return res;
|
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) {
|
public float[] getMutatedWeights(float mutationProbability, float mutationFactor) {
|
||||||
float[] mutatedWeights = new float[weights.length];
|
float[] mutatedWeights = new float[weights.length];
|
||||||
for (int i = 0; i < weights.length; i++) {
|
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) {
|
public void setOutput(float output) {
|
||||||
isInputNeuron = true;
|
isInputNeuron = true;
|
||||||
this.output = output;
|
this.output = output;
|
||||||
@ -140,6 +158,11 @@ public class Neuron {
|
|||||||
return weights;
|
return weights;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Change the neuron weights
|
||||||
|
*
|
||||||
|
* @param weights the new weights to put
|
||||||
|
*/
|
||||||
public void setWeights(float[] weights) {
|
public void setWeights(float[] weights) {
|
||||||
this.weights = weights;
|
this.weights = weights;
|
||||||
// Changing the neuron makes the cache invalid
|
// Changing the neuron makes the cache invalid
|
||||||
|
Loading…
Reference in New Issue
Block a user