This is simply a base program in which it is easy to code new simulations to test
import java.util.Scanner;
import java.util.Random;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Timer;
import java.util.TimerTask;
import java.awt.event.*;
import java.awt.*;
import javax.swing.*;
import java.awt.event.MouseEvent;
public class NeuralNetworkEnviro extends JPanel{
Timer timer;
int speed = 2;
int screenCordX = 0;
int screenCordY = 0;
public static Circle[] foodArray;
public static Circle base;
int xTransform = 0;
int yTransform = 0;
public static int rNum = 2;
public static int cNum = 5;
public static int inNum = 2;
public static int outNum = 3;
public static int keepBrainNum = 5;
public static int foodNum = 20;
public static int brainNum = 20;
public static double mutationPercent = .10;
static Brain[] brains;
int count = 0;
int maxCount = 10000;
int genNum = 0;
public void paintComponent(Graphics g){
super.paintComponent(g);
double radFov = (20 * Math.PI) / 180;
for(int i = 0; i < brains.length; i++){
g.drawOval(brains[i].getX() + xTransform, brains[i].getY() + yTransform, brains[i].radius * 2, brains[i].radius * 2);
g.drawLine(xTransform + brains[i].getX() + brains[i].radius, yTransform + brains[i].getY() + brains[i].radius, xTransform + brains[i].getX() + brains[i].radius + Math.round((float)(Math.cos(brains[i].rotation)) * 4), yTransform + brains[i].getY() + brains[i].radius - Math.round((float)(Math.sin(brains[i].rotation)) * 4));
}
for(int i = 0; i < foodArray.length; i++){
g.drawOval(foodArray[i].getX() + xTransform, foodArray[i].getY() + yTransform, foodArray[i].getRadius() * 2, foodArray[i].getRadius() * 2);
}
}
public Brain[] shiftArray(int num, Brain[] brainArray){
Brain[] tempBrain = new Brain[brainArray.length];
tempBrain = brainArray.clone();
for(int i = num; i < brainArray.length - 1; i++){
if(i == num){
brainArray[i] = null;
}
else{
brainArray[i] = tempBrain[i - 1];
}
}
return brainArray;
}
public static void main(String[] args){
brains = new Brain[brainNum];
foodArray = new Circle[foodNum];
for(int i = 0; i < foodNum; i++){
foodArray[i] = new Circle(10, (int)Math.round(Math.random() * 640), (int)Math.round(Math.random() * 480));
}
for(int i = 0; i < brainNum; i++){
String[][] newWeights = new String[rNum][cNum * cNum];
brains[i] = new Brain(rNum, cNum, true, newWeights, 5);
}
NeuralNetworkEnviro content = new NeuralNetworkEnviro();
JFrame window = new JFrame();
window.setContentPane(content);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setLocation(120,70);
window.setSize(640,480);
window.setVisible(true);
}
class Task extends TimerTask {
public void run(){
count++;
double[] inputArray = new double[inNum];
double smallestFood = 800;
double newFood = 0;
int smallNum = 0;
if(count > maxCount){
createNextGen();
count = 0;
genNum++;
System.out.println("Generation: " + genNum);
}
for(int i = 0; i < brainNum; i++){
for(int u = 0; u < foodNum; u++){
newFood = brains[i].canSee(foodArray[u], 40);
if(newFood < smallestFood){
smallestFood = newFood;
smallNum = u;
}
//Tests if food can be eaten
int eatTest = brains[i].getDistance(foodArray[u]);
if(eatTest < brains[i].radius + foodArray[u].radius){
foodArray[u] = new Circle(10, (int)Math.round(Math.random() * 640), (int)Math.round(Math.random() * 480));
brains[i].setAddedScore(1);
brains[i].setFoodCount(brains[i].getFoodCount() + 1);
}
}
inputArray[0] = Math.abs((double)(brains[i].canSee(foodArray[smallNum], 40) - 800) / 800);
if(inputArray[0] <= 0 ){
inputArray[1] = 1.0;
}
else{
inputArray[1] = 0;
}
brains[i].calculateWeights(inputArray);
brains[i].calculateMovement();
}
repaint();
}
}
public class mouseListener implements MouseMotionListener, MouseListener {
boolean mouseHeld = false;
int x1, x2, xDistance;
int y1, y2, yDistance;
public void mouseClicked(MouseEvent e){}
public void mouseDragged(MouseEvent e){
if(mouseHeld == true){
x2 = e.getX();
y2 = e.getY();
xDistance = x1 - x2;
yDistance = y1 - y2;
xTransform += -xDistance;
yTransform += -yDistance;
x1 = x2;
y1 = y2;
}
}
public void mouseEntered(MouseEvent e){}
public void mouseExited(MouseEvent e){}
public void mouseMoved(MouseEvent e){}
public void mousePressed(MouseEvent e){
mouseHeld = true;
x1 = e.getX();
y1 = e.getY();
}
public void mouseReleased(MouseEvent e){
mouseHeld = false;
}
public void mouseWheel(MouseEvent e){}
}
public NeuralNetworkEnviro(){
timer = new Timer();
timer.schedule(new Task(), 0, speed);
mouseListener listener = new mouseListener();
addMouseListener(listener);
addMouseMotionListener(listener);
}
public Brain breedBrains(Brain brain1, Brain brain2){
Brain newBrain = new Brain(rNum, cNum, false, new String[rNum][cNum * cNum], 5);
String newGene = "";
for(int i = 0; i < rNum; i++){
for(int u = 0; u < cNum * cNum; u++){
newGene = "";
int crossoverPoint = Math.round((float)(Math.random() * 14));
for(int z = 1; z < 14; z++){
double random = Math.random();
double mutation = Math.random();
if(z == 1){
if(random > .5){
newGene = newGene + brain1.getWeights(i, u).charAt(0);
}
else{
newGene = newGene + brain2.getWeights(i, u).charAt(0);
}
}
if(random > .5 && Character.getNumericValue(brain1.getWeights(i, u).charAt(z)) != -1){
if(mutation < mutationPercent){
if(Character.getNumericValue(brain1.getWeights(i, u).charAt(z)) == 1){
newGene = newGene + "0";
}
else{
newGene = newGene + "1";
}
}
else{
newGene = newGene + brain1.getWeights(i, u).charAt(z);
}
}
else if(random <= .5 && Character.getNumericValue(brain1.getWeights(i, u).charAt(z)) != -1){
if(mutation < mutationPercent){
if(Character.getNumericValue(brain2.getWeights(i, u).charAt(z)) == 1){
newGene = newGene + "0";
}
else{
newGene = newGene + "1";
}
}
else{
newGene = newGene + brain2.getWeights(i, u).charAt(z);
}
}
else{
newGene = newGene + ".";
}
}
newBrain.setWeights(i, u, newGene);
}
}
for(int i = 0; i < rNum * cNum + outNum; i++){
String newFunction = "";
for(int u = 1; u < 14; u++){
if(u == 1){
double negativeRan = Math.random();
if(negativeRan < .5){
newFunction = "" + brain1.getNeuronFunction(i).charAt(0);
}
else{
newFunction = "" + brain2.getNeuronFunction(i).charAt(0);
}
}
double random = Math.random();
if(random < .5 && Character.getNumericValue(brain1.getNeuronFunction(i).charAt(u)) != -1){
newFunction = newFunction + brain1.getNeuronFunction(i).charAt(u);
}
else if(random >= .5 && Character.getNumericValue(brain2.getNeuronFunction(i).charAt(u)) != -1){
newFunction = newFunction + brain2.getNeuronFunction(i).charAt(u);
}
else{
newFunction = newFunction + ".";
}
}
newBrain.setNeuronFunction(i, newFunction);
}
for(int i = 0; i < rNum * cNum + outNum; i++){
String newPower = "";
for(int u = 1; u < 14; u++){
if(u == 1){
newPower = newPower + "+";
}
double random = Math.random();
if(random < .5 && Character.getNumericValue(brain1.getPower(i).charAt(u)) != -1){
newPower = newPower + brain1.getPower(i).charAt(u);
}
else if(random >= .5 && Character.getNumericValue(brain2.getPower(i).charAt(u)) != -1){
newPower = newPower + brain2.getPower(i).charAt(u);
}
else{
newPower = newPower+ ".";
}
}
newBrain.setPower(i, newPower);
}
return newBrain;
}
public void createNextGen(){
Brain[] topBrains = new Brain[brainNum];
for(int i = 0; i < brainNum; i++){
for(int u = 0; u < brainNum; u++){
if(i == 0){
topBrains[i] = brains[i];
break;
}
if(topBrains[Math.abs(u - brainNum) - 1] != null){
if(brains[i].getScore() < topBrains[Math.abs(u - brainNum) - 1].getScore()){
int newPlace = Math.abs(u - brainNum);
System.out.println("Array shifted");
topBrains = (Brain[]) shiftArray(newPlace, topBrains).clone();
topBrains[Math.abs(u - brainNum)] = brains[i];
break;
}
else{
if(u == brainNum - 1){
topBrains = (Brain[]) shiftArray(0, topBrains).clone();
topBrains[0] = brains[i];
}
}
}
}
}
double totalScore = 0;
for(int i = 0; i < brainNum; i++){
totalScore += brains[i].getScore();
}
for(int i = 0; i < brainNum; i++){
brains[i].setPercent((brains[i].getScore() / totalScore) * 100);
}
int comScore = 0;
for(int i = 0; i < brainNum; i++){
comScore += brains[i].getPercent();
brains[i].setPercent(brains[i].getPercent() + comScore);
}
boolean done = false;
boolean done1 = false;
Brain chosenBrain1 = null;
Brain chosenBrain2 = null;
Brain[] newBrainList = new Brain[brainNum];
for(int i = 0; i < keepBrainNum; i++){
newBrainList[i] = topBrains[i];
System.out.println((i + 1) + ": " + topBrains[i].getScore());
topBrains[i].setScore(0);
}
for(int z = keepBrainNum; z < brainNum; z++){
done1 = false;
done = false;
while(done1 == false){
double random = Math.random() * 100;
for(int i = 0; i < brainNum; i++){
if(i == 0){
if(brains[i].getPercent() > random){
chosenBrain1 = brains[i];
System.out.println("Brain 1: " + i);
System.out.println("Score: " + chosenBrain1.getScore());
done1 = true;
break;
}
}
else if(brains[i].getPercent() >= random && brains[i - 1].getPercent() < random){
chosenBrain1 = brains[i];
System.out.println("Brain 1: " + i);
System.out.println("Score: " + chosenBrain1.getScore());
done1 = true;
break;
}
}
}
while(done == false){
double random1 = Math.random() * 100;
for(int i = 0; i < brainNum; i++){
if(i == 0){
if(brains[i].getPercent() > random1){
if(chosenBrain1.equals(brains[i])){
}
else{
chosenBrain2 = brains[i];
System.out.println("Brain 2: " + i);
System.out.println("Score: " + chosenBrain2.getScore());
done = true;
break;
}
}
}
else if(brains[i].getPercent() >= random1 && brains[i - 1].getPercent() < random1){
if(chosenBrain1.equals(brains[i])){
}
else{
chosenBrain2 = brains[i];
System.out.println("Brain 2: " + i);
System.out.println("Score: " + chosenBrain2.getScore());
done = true;
break;
}
}
}
}
newBrainList[z] = breedBrains(chosenBrain1, chosenBrain2);
}
for(int i = 0; i < brainNum; i++){
brains[i] = newBrainList[i];
}
}
}
class Brain{
public int radius;
double percent = 0;
private int divFunction = 8;
private int divNeuron = 8;
private int divPower = 8;
private int divRotation = 2;
private String[][] weights;
private double[] neurons;
private String[] neuronFunction;
private String[] neuronPower;
double dx = Math.random() * 638 + 2;
double dy = Math.random() * 478 + 2;
int score = 0;
int divideNum = 1;
int speedReduce = 1;
int foodCount;
int rowNum;
int colunmNum;
double moveOut, rotationLeftOut, rotationRightOut;
double[] outPuts;
int outNum = 3;
int x, y;
double rotation = 0;
public Brain(int rows, int columnNumber, boolean first, String[][] weight, int bRadius){
weights = new String[rows][columnNumber * columnNumber];
radius = bRadius;
System.arraycopy(weight, 0, weights, 0, weight.length);
rowNum = rows;
colunmNum = columnNumber;
neurons = new double[rowNum * colunmNum];
neuronFunction = new String[neurons.length + NeuralNetworkEnviro.outNum];
neuronPower = new String[neuronFunction.length];
outPuts = new double[outNum];
x = 100;
y = 100;
if(first == true){
generateWeights();
}
}
private void generateWeights(){
for(int i = 0; i < rowNum; i++){
for(int u = 0; u < colunmNum * colunmNum; u++){
double random = (double)(Math.random() * 16);
double negativeRan = Math.random();
if(negativeRan < 0.5){
random = random * -1;
}
weights[i][u] = toBinary(random);
}
}
for(int i = 0; i < neuronFunction.length; i++){
double random = (double)(Math.random() * 16);
double negativeRan = Math.random();
if(negativeRan < 0.5){
random = random * -1;
}
neuronFunction[i] = toBinary(random);
}
for(int i = 0; i < neuronFunction.length; i++){
double random = Math.random() * 16;
neuronPower[i] = toBinary(random);
}
}
public static String toBinary(double num){
double dNum = Math.abs(num);
String sNum = "" + dNum;
String bNum = "";
char ch = sNum.charAt(1);
int nu = Character.getNumericValue(ch);
if(nu == -1){
for(int i = 0; i < sNum.length(); i++){
char c = sNum.charAt(i);
int iNum = Character.getNumericValue(c);
for(int u = 0; u < 4; u++){
if( iNum == -1){
String binaryDec = ".";
bNum = bNum + binaryDec;
break;
}
else{
int binaryNum = iNum % 2;
if(binaryNum == 1){
iNum = (iNum - 1) / 2;
}
else{
iNum = iNum / 2;
}
bNum = bNum + binaryNum;
}
}
}
}
else{
int iNum = 0;
for(int i = 0; i < sNum.length() - 1; i++){
if(i == 0){
char c1 = sNum.charAt(0);
char c2 = sNum.charAt(1);
String twoNum = "" + c1 + c2;
iNum = Integer.parseInt(twoNum);
}
char c = sNum.charAt(i + 1);
if(i != 0){
iNum = Character.getNumericValue(c);
}
for(int u = 0; u < 4; u++){
if( iNum == -1){
String binaryDec = ".";
bNum = bNum + binaryDec;
break;
}
else{
int binaryNum = iNum % 2;
if(binaryNum == 1){
iNum = (iNum - 1) / 2;
}
else{
iNum = iNum / 2;
}
bNum = bNum + binaryNum;
}
}
}
}
if(num < 0){
bNum = "-" + bNum;
}
else{
bNum = "+" + bNum;
}
return bNum;
}
public static double toDecimal(String bNum){
int convertedNum = 0;
double finalNum = 0;
String numString = "";
for(int u = 1; u < (bNum.length()) / 4; u++){
char c;
convertedNum = 0;
for(int i = 0; i < 4; i++){
if(u != 0){
c = bNum.charAt(1 + i + u * 4);
}
else{
c = bNum.charAt(i + u * 4);
}
int num = Character.getNumericValue(c);
if(num == 1){
convertedNum = convertedNum + Math.round((float)Math.pow(2, Math.abs(i)));
}
}
if(u == 1){
numString = numString + convertedNum + ".";
}
else{
numString = numString + convertedNum;
}
}
//System.out.println(numString);
finalNum = Double.parseDouble(numString);
char nChar = bNum.charAt(0);
if(nChar == '-'){
finalNum = finalNum * -1;
}
return finalNum;
}
public double getPercent(){
return percent;
}
public void setPercent(double newPercent){
this.percent = newPercent;
}
public int getScore(){
return score;
}
public String getWeights(int first, int second){
return weights[first][second];
}
public void setWeights(int first, int second, String num){
weights[first][second] = num;
}
public String getNeuronFunction(int num){
return neuronFunction[num];
}
public void setNeuronFunction(int num, String s){
neuronFunction[num] = s;
}
public int getX(){
return this.x;
}
public int getY(){
return this.y;
}
public int getFoodCount(){
return foodCount;
}
public void setAddedScore(int newScore){
this.score += newScore;
}
public void setFoodCount(int newFoodCount){
this.foodCount = newFoodCount;
}
public void setScore(int newSet){
this.score = newSet;
}
public String getPower(int num){
return neuronPower[num];
}
public void setPower(int num, String set){
neuronPower[num] = set;
}
public void calculateWeights(double[] inputArray){
double[] inputs = new double[inputArray.length];
for(int i = 0; i < rowNum * colunmNum; i++){
neurons[i] = 0;
}
for(int i = 0; i < outNum; i++){
outPuts[i] = 0;
}
System.arraycopy(inputArray, 0, inputs, 0, inputArray.length);
int cNum = 0;
for(int i = 0; i < rowNum; i++){
for(int u = 0; u < colunmNum * colunmNum; u++){
if(i == 0){
if(u >= NeuralNetworkEnviro.inNum * colunmNum){
break;
}
cNum = (int)Math.round((float)(u / NeuralNetworkEnviro.inNum));
neurons[cNum] += toDecimal(weights[i][u]) / divNeuron * inputs[u % NeuralNetworkEnviro.inNum];
}
else{
cNum = (int)Math.floor((float)(u / colunmNum));
neurons[cNum + i * colunmNum] = neurons[cNum + i * colunmNum] + toDecimal(weights[i][u]) / divNeuron * neurons[u % colunmNum + (i - 1) * colunmNum];
}
}
for(int u = 0; u < colunmNum; u++){
//neurons[u + i * colunmNum] = 1 / (1 + Math.pow(2.7, -neurons[u + i * colunmNum]));
if(neurons[u + i * colunmNum] > toDecimal(neuronFunction[u + i * colunmNum]) / divFunction){
neurons[u + i * colunmNum] = 1 / (1 + Math.pow(2.7, -neurons[u + i * colunmNum]));
}
else{
neurons[u + i * colunmNum] = 0;
}
/*
if(neurons[u + i * colunmNum] > toDecimal(neuronFunction[u + i * colunmNum]) / divFunction){
neurons[u + i * colunmNum] = toDecimal(neuronPower[u + i * colunmNum]) / divPower;
}
else{
neurons[u + i * colunmNum] = 0;
}
*/
//System.out.println("Neuron " + (u + i * colunmNum) + ": " + neurons[u + i * colunmNum]);
}
}
for(int u = 0; u < colunmNum * outNum; u++){
cNum = (int)Math.floor((float)(u / colunmNum));
this.outPuts[cNum] += (toDecimal(weights[rowNum - 1][u])) / 8 * neurons[u % colunmNum + colunmNum * (rowNum - 1)];
//this.outPuts[cNum] = this.outPuts[cNum] / colunmNum;
}
for(int u = 0; u < outNum; u++){
//this.outPuts[u] = 1 / (1 + Math.pow(2.7, -this.outPuts[u]));
if(this.outPuts[u] > toDecimal(neuronFunction[neurons.length + u]) / divFunction){
this.outPuts[u] = 1 / (1 + Math.pow(2.7, -this.outPuts[u]));
}
else{
this.outPuts[u] = 0;
}
/*
if(this.outPuts[u] > toDecimal(neuronFunction[neurons.length + u]) / divFunction){
this.outPuts[u] = toDecimal(neuronPower[neurons.length + u]) / divPower;
}
else{
this.outPuts[u] = 0;
}
*/
}
//System.out.println("Output 1: " + outPuts[1]);
//System.out.println("Output 2: " + outPuts[2]);
}
public void calculateMovement(){
rotation += (this.outPuts[1] - this.outPuts[2]) / divRotation;
if(rotation > 2 * Math.PI){
rotation = 0;
}
if(rotation < 0){
rotation = 2 * Math.PI;
}
double xVec = Math.cos(rotation) * this.outPuts[0];
double yVec = -Math.sin(rotation) * this.outPuts[0];
dx = dx + (double)(xVec / speedReduce);
dy = dy + (double)(yVec / speedReduce);
if(dx > 640){
dx = (double)4;
}
if(dy > 480){
dy = (double)4;
}
if(dx < 0){
dx = (double)636;
}
if(dy < 0){
dy = (double)476;
}
x = (int)dx;
y = (int)dy;
}
public int canSee(Shapes object, int fov){
double shapeX, shapeY;
if(object.getType().equals("Circle")){
Circle objectC = (Circle)object;
shapeX = (object.getX() + Math.round(objectC.getRadius())) - (this.x - this.radius);
shapeY = (this.y + this.radius) - (object.getY() + Math.round(objectC.getRadius()));
double newAngle = Math.atan(shapeY / shapeX);
if(shapeX < 0){
if(shapeY < 0){
newAngle = newAngle - Math.PI;
}
else{
newAngle = newAngle + Math.PI;
}
}
if(newAngle < 0){
newAngle = newAngle + (2 * Math.PI);
}
if(Math.abs(newAngle - rotation) < (fov * Math.PI / 360)){
return this.getDistance(object);
}
else if(Math.abs(newAngle - rotation) > (2 * Math.PI) - (fov * Math.PI / 360)){
return this.getDistance(object);
}
}
else if(object.getType().equals("Square")){
Square objectS = (Square)object;
shapeX = (object.getX() - Math.round(objectS.getWidth() / 2)) - this.x;
shapeY = this.y - (object.getY() - Math.round(objectS.getHeight() / 2));
double newAngle = Math.atan(shapeY / shapeX);
if(shapeX < 0){
if(shapeY < 0){
newAngle = newAngle + Math.PI / 2;
}
else{
newAngle = newAngle - Math.PI / 2;
}
}
}
return 800;
}
public int getDistance(Shapes object){
int distance = 0;
if(object.getType().equals("Circle")){
distance = Math.round((float)Math.sqrt(Math.pow((double)(object.getX() +
((Circle)object).getRadius()) - (this.x + this.radius), 2.0) + Math.pow((double)(object.getY() + ((Circle)object).getRadius()) - (this.y + this.radius), 2.0)));
}
else if(object.getType().equals("Square")){
distance = (int) Math.round(Math.sqrt(Math.pow((double)(object.getX() + ((Square) object).getWidth() / 2) - this.x, 2.0) + Math.pow((double)(object.getY() + ((Square) object).getHeight() / 2) - this.y, 2.0)));
}
return distance;
}
}
class Shapes{
int x;
int y;
String type;
public Shapes(){
}
public String getType(){
return type;
}
public int getX(){
return x;
}
public int getY(){
return y;
}
}
class Circle extends Shapes{
int radius;
public Circle(int radius, int x, int y){
this.x = x;
this.y = y;
this.radius = radius;
this.type = "Circle";
}
public int getRadius(){
return this.radius;
}
}
class Square extends Shapes{
int height;
int width;
public Square(int height, int width, int x, int y){
this.x = x;
this.y = y;
this.height = height;
this.width = width;
this.type = "Square";
}
public String getType(){
return type;
}
public int getHeight(){
return this.height;
}
public int getWidth(){
return this.width;
}
}
To learn more HTML/CSS, check out these tutorials!