AI Flappy Bird Processing Java

i’ll make it easy and place the walls in without it
here sketch without the tables

int s = 20;
int hw;
int Total = 500;
ArrayList<Enemy> population, saved;
ArrayList<Wall> wall = new ArrayList<Wall>();
int gen;
int mgen = 5;
int mmove = 5;
EndArea ea;
int bests[] = new int[5];
int beste[] = new int[5];
Table wallTable,genTable;
TableRow wallRow,genRow;
int map = 0;
int col;
float hisc,higen;
int ro;

void setup(){
  size(700,580);
  for (int i = 0; i < 5; i++){
    bests[i] = 0;
    beste[i] = 0;
  }
  genTable = loadTable("gen.csv");
  genRow = genTable.getRow(0);
  ro = genRow.getInt(0);
  ro += 1;
  genRow.setInt(0,ro);
  genRow = genTable.addRow();
  saveTable(genTable,"gen.csv");
  ea = new EndArea(26,25);
  loadSnake();
  population = new ArrayList<Enemy>();
  saved = new ArrayList<Enemy>();
  /*wallTable = loadTable("wall.csv");
  col = wallTable.getColumnCount();
  hw = height/s - 1;
  for (int i = 0; i <= col-1; i++){
    int tr = map*2;
    wallRow = wallTable.getRow(tr);
    int xx = wallRow.getInt(i);
    wallRow = wallTable.getRow(tr+1);
    int yy = wallRow.getInt(i);
    wall.add(new Wall(xx,yy));
  }*/
  for (int i = 0; i < Total; i++){
    population.add(new Enemy());
  }
  for (int i = 0; i < 29; i++){
    wall.add(new Wall(i,0));
    wall.add(new Wall(i,28));
    wall.add(new Wall(0,i));
    wall.add(new Wall(28,i));
  }
  for (int i = 0; i < 23; i++){
    wall.add(new Wall(i,4));
    wall.add(new Wall(6 + i,8));
    wall.add(new Wall(i,12));
    wall.add(new Wall(6 + i,16));
    wall.add(new Wall(i,20));
    wall.add(new Wall(6 + i,24));
  }
}

void draw(){
  background(0);
  fill(255);
  textSize(20);
  text("Gen: " + gen, 29 * s, 1 * s);
  text("HS: " + int(hisc), 29 * s, 2 * s);
  text("HG: " + int(higen), 29 * s, 3 * s);
  text("Pop: " + population.size(), 29 * s, 4 * s);
  if (population.size() == 0){
    nextGeneration();
  }
  for (Enemy e: population){
    e.check();
    e.look();
    e.think();
  }
  for (int i = population.size()-1; i >= 0; i--){
    Enemy e = population.get(i);
    if (e.collide == true || e.won == true || e.failed == true){
      saved.add(e);
      population.remove(i);
    }
  }
  
  for (Wall w: wall){
    w.show();
  }
  ea.show();
  for (Enemy e: population){
    e.show();
  }
}

here EndArea

class EndArea{
  int x,y;
  int h = s*3;
  int w = s * 2;
  EndArea(int x, int y){
    this.x = x*s;
    this.y = y*s;
  }
  
  void show(){
    fill(0,255,0);
    rect(x,y,w,h);
  }
}

here Enemy

class Enemy{
  PVector pos;
  int r = 12;
  float score = 0;
  float fitness = 0;
  float nx,ny;
  boolean collide = false;
  boolean won = false;
  boolean failed;
  int timer = 100;
  int nummove = 0;
  float sy,cd,sd;
  
  float[] inputs = new float[12];
  NeuralNetwork brain;
  
  Enemy(){
    pos = new PVector(2 * s, 2 * s);
    sy = pos.y;
    sd = dist(ea.x,ea.y,pos.x,pos.y);
    nx = pos.x;
    ny = pos.y;
    brain = new NeuralNetwork(12, 94, 4);
  }
  Enemy(NeuralNetwork b){
    pos = new PVector(2 * s, 2 * s);
    sy = pos.y;
    sd = dist(ea.x,ea.y,pos.x,pos.y);
    nx = pos.x;
    ny = pos.y;
    brain = b.clone();
  }
  
  void mutate(){
    brain.mutate(0.1);
  }
  
  void think(){
    inputs[8] = pos.x;
    inputs[9] = pos.y;
    inputs[10] = ea.x;
    inputs[11] = ea.y;
    float[] guess = brain.output(inputs);
    if (guess[0] > guess[1] && guess[0] > guess[2] && guess[0] > guess[3]){move(0,-1);}
    if (guess[1] > guess[0] && guess[1] > guess[2] && guess[1] > guess[3]){move(0,1);}
    if (guess[2] > guess[1] && guess[2] > guess[0] && guess[2] > guess[3]){move(-1,0);}
    if (guess[3] > guess[0] && guess[3] > guess[2] && guess[3] > guess[0]){move(1,0);}
  }
  
  void show(){
    if (timer > -1){timer -= 1;}
    if (timer <= 0 && won == false){
      float d = dist(nx,ny,pos.x,pos.y);
      if (d < s){
        failed = true;
      }
      else {
        nx = pos.x;
        ny = pos.y;
        timer = 40;
        cd = dist(ea.x,ea.y,pos.x,pos.y);
        if (cd < sd){
          sd = cd;
          score += 1;
        }
      }
    }
    if (pos.y > sy + (s*2)){score += 1;}
    fill(255,0,0);
    stroke(0);
    rect(pos.x,pos.y,s,s);
  }
  
  void check(){
    for (int i = 0; i < wall.size(); i++){
      Wall w = wall.get(i);
      float d = dist(w.pos.x,w.pos.y,pos.x,pos.y);
      if (d < s){
        collide = true;
      }
    }// wall
    if (pos.x >= ea.x && pos.x < ea.x + ea.w && pos.y >= ea.y && pos.y < ea.y + ea.h){
      won = true;
      score = score * 2;
    }
  }// check
  
  void move(int xspd, int yspd){
    if (won == false){
      pos.x += xspd;
      pos.y += yspd;
    }
    xspd = 0;
    yspd = 0;
  }
  void look() {
    PVector direction;
    for (int i = 0; i< 8; i++) {
      // player sees in 16 direction, so we have to divide one full rotation (360 degrees) with 16
      // so angle between two nearest directions will be 22.5 degree
      direction = PVector.fromAngle(i*(TWO_PI/8));
      direction.mult(10);
      // get the normalized distance to the ball if found in the current direction
      // if got no ball in the current direction, mag will be zero
      float mag = lookInDirection(direction); 
      inputs[i] = mag; //feed this to the input
      
      // this is how the visualisation
      stroke(255,0,0);
      if (mag > 0) {
        direction.mult(1/mag);
        direction.add(pos);
        fill(0);
        //text(1/mag, direction.x, direction.y);
        stroke(0, 255,0);
      }else{
        //if no ball in current direction
        direction.mult(60);
        direction.add(pos);
        stroke(255, 0,0);
      }
      line(pos.x, pos.y, direction.x, direction.y);
    }
  }

  float lookInDirection(PVector direction) {

    PVector position = new PVector(pos.x, pos.y);//the position where we are currently looking for the balls
    float distance = 0;
    //move once in the desired direction before starting 
    position.add(direction);
    distance +=1;

    //look in the direction
    while (distance< 60) {
      for (Wall a: wall) {
        if (a.lookForHit(position) ) { 
          // found ball
          return  1/distance;
        }
      }

      //look further in the direction
      position.add(direction);

      // next distance
      distance +=1;
    }
    return 0;
  }
  
  void saveEnemy() {
    //save snakes brain
    saveTable(brain.NetToTable(), "data/Snake.csv");
  }
}

here GA

void nextGeneration(){
  getBest();
  for (int i = 0; i < Total-5; i++){
    population.add(pickOne());
  }
  for (int i = 0; i < 5; i++){
    population.add(new Enemy());
  }
  population.add(bestOne());
  gen++;
  if (gen == 100){
    exit();
  }
}

Enemy bestOne(){
  int index = 0;
  index = beste[0];
  Enemy b = saved.get(index);
  Enemy child = new Enemy(b.brain);
  return child;
}

Enemy pickOne(){// pick an enemy from the top 5
  int index = 0;
  float choose = random(4);
  choose = round(choose);
  index = beste[int(choose)];
  Enemy b = saved.get(index);
  Enemy child = new Enemy(b.brain);
  child.mutate();
  return child;
}

Enemy loadSnake() {

    Enemy load = new Enemy();
    Table t = loadTable("data/Snake.csv");
    load.brain.TableToNet(t);
    return load;
  }

void getBest(){// loop through all the enemies and get the scores
  for (int i = 0; i < saved.size(); i++){
    Enemy s = saved.get(i);
    if (s.score > bests[0]){
      bests[4] = bests[3];
      bests[3] = bests[2];
      bests[2] = bests[1];
      bests[1] = bests[0];
      bests[0] = int(s.score);
      beste[4] = beste[3];
      beste[3] = beste[2];
      beste[2] = beste[1];
      beste[1] = beste[0];
      beste[0] = i;
      if (s.score > hisc){
        hisc = s.score;
        higen = gen;
        s.saveEnemy();
      }
    }
    else if (s.score > bests[1]){
      bests[4] = bests[3];
      bests[3] = bests[2];
      bests[2] = bests[1];
      bests[1] = int(s.score);
      beste[4] = beste[3];
      beste[3] = beste[2];
      beste[2] = beste[1];
      beste[1] = i;
    }
    else if (s.score > bests[2]){
      bests[4] = bests[3];
      bests[3] = bests[2];
      bests[2] = int(s.score);
      beste[4] = beste[3];
      beste[3] = beste[2];
      beste[2] = i;
    }
    else if (s.score > bests[3]){
      bests[4] = bests[3];
      bests[3] = int(s.score);
      beste[4] = beste[3];
      beste[3] = i;
    }
    else if (s.score > bests[4]){
      bests[4] = int(s.score);
      beste[4] = i;
    }
  }
}

here Matrix, i changed it

class Matrix {
  
  //local variables
  int rows;
  int cols;
  float[][] matrix;
  
  //---------------------------------------------------------------------------------------------------------------------------------------------------------  
  //constructor
  Matrix(int r, int c) {
    rows = r;
    cols = c;
    matrix = new float[rows][cols];
  }
  
  //---------------------------------------------------------------------------------------------------------------------------------------------------------  
  //constructor from 2D array
  Matrix(float[][] m) {
    matrix = m;
    cols = m.length;
    rows = m[0].length;
  }
  
  //---------------------------------------------------------------------------------------------------------------------------------------------------------  
  //print matrix
  void output() {
    for (int i =0; i<rows; i++) {
      for (int j = 0; j<cols; j++) {
        print(matrix[i][j] + "  ");
      }
      println(" ");
    }
    println();
  }
  //---------------------------------------------------------------------------------------------------------------------------------------------------------  
  
  //multiply by scalar
  void multiply(float n ) {

    for (int i =0; i<rows; i++) {
      for (int j = 0; j<cols; j++) {
        matrix[i][j] *= n;
      }
    }
  }

//---------------------------------------------------------------------------------------------------------------------------------------------------------  
  //return a matrix which is this matrix dot product parameter matrix 
  Matrix dot(Matrix n) {
    Matrix result = new Matrix(rows, n.cols);
   
    if (cols == n.rows) {
      //for each spot in the new matrix
      for (int i =0; i<rows; i++) {
        for (int j = 0; j<n.cols; j++) {
          float sum = 0;
          for (int k = 0; k<cols; k++) {
            sum+= matrix[i][k]*n.matrix[k][j];
          }
          result.matrix[i][j] = sum;
        }
      }
    }

    return result;
  }
//---------------------------------------------------------------------------------------------------------------------------------------------------------  
  //set the matrix to random ints between -1 and 1
  void randomize() {
    for (int i =0; i<rows; i++) {
      for (int j = 0; j<cols; j++) {
        matrix[i][j] = random(-1, 1);
      }
    }
  }

//---------------------------------------------------------------------------------------------------------------------------------------------------------  
  //add a scalar to the matrix
  void Add(float n ) {
    for (int i =0; i<rows; i++) {
      for (int j = 0; j<cols; j++) {
        matrix[i][j] += n;
      }
    }
  }
//---------------------------------------------------------------------------------------------------------------------------------------------------------  
  ///return a matrix which is this matrix + parameter matrix
  Matrix add(Matrix n ) {
    Matrix newMatrix = new Matrix(rows, cols);
    if (cols == n.cols && rows == n.rows) {
      for (int i =0; i<rows; i++) {
        for (int j = 0; j<cols; j++) {
          newMatrix.matrix[i][j] = matrix[i][j] + n.matrix[i][j];
        }
      }
    }
    return newMatrix;
  }
//---------------------------------------------------------------------------------------------------------------------------------------------------------  
  //return a matrix which is this matrix - parameter matrix
  Matrix subtract(Matrix n ) {
    Matrix newMatrix = new Matrix(cols, rows);
    if (cols == n.cols && rows == n.rows) {
      for (int i =0; i<rows; i++) {
        for (int j = 0; j<cols; j++) {
          newMatrix.matrix[i][j] = matrix[i][j] - n.matrix[i][j];
        }
      }
    }
    return newMatrix;
  }
//---------------------------------------------------------------------------------------------------------------------------------------------------------  
  //return a matrix which is this matrix * parameter matrix (element wise multiplication)
  Matrix multiply(Matrix n ) {
    Matrix newMatrix = new Matrix(rows, cols);
    if (cols == n.cols && rows == n.rows) {
      for (int i =0; i<rows; i++) {
        for (int j = 0; j<cols; j++) {
          newMatrix.matrix[i][j] = matrix[i][j] * n.matrix[i][j];
        }
      }
    }
    return newMatrix;
  }
//---------------------------------------------------------------------------------------------------------------------------------------------------------  
  //return a matrix which is the transpose of this matrix
  Matrix transpose() {
    Matrix n = new Matrix(cols, rows);
    for (int i =0; i<rows; i++) {
      for (int j = 0; j<cols; j++) {
        n.matrix[j][i] = matrix[i][j];
      }
    }
    return n;
  }
//---------------------------------------------------------------------------------------------------------------------------------------------------------  
  //Creates a single column array from the parameter array
  Matrix singleColumnMatrixFromArray(float[] arr) {
    Matrix n = new Matrix(arr.length, 1);
    for (int i = 0; i< arr.length; i++) {
      n.matrix[i][0] = arr[i];
    }
    return n;
  }
  //---------------------------------------------------------------------------------------------------------------------------------------------------------  
  //sets this matrix from an array
  void fromArray(float[] arr) {
    for (int i = 0; i< rows; i++) {
      for (int j = 0; j< cols; j++) {
        matrix[i][j] =  arr[j+i*cols];
      }
    }
  }
//---------------------------------------------------------------------------------------------------------------------------------------------------------    
  //returns an array which represents this matrix
  float[] toArray() {
    float[] arr = new float[rows*cols];
    for (int i = 0; i< rows; i++) {
      for (int j = 0; j< cols; j++) {
        arr[j+i*cols] = matrix[i][j];
      }
    }
    return arr;
  }

//---------------------------------------------------------------------------------------------------------------------------------------------------------  
  //for ix1 matrixes adds one to the bottom
  Matrix addBias() {
    Matrix n = new Matrix(rows+1, 1);
    for (int i =0; i<rows; i++) {
      n.matrix[i][0] = matrix[i][0];
    }
    n.matrix[rows][0] = 1;
    return n;
  }
//---------------------------------------------------------------------------------------------------------------------------------------------------------  
  //applies the activation function(sigmoid) to each element of the matrix
  Matrix activate() {
    Matrix n = new Matrix(rows, cols);
    for (int i =0; i<rows; i++) {
      for (int j = 0; j<cols; j++) {
        n.matrix[i][j] = sigmoid(matrix[i][j]);
      }
    }
    return n;
  }
  
//---------------------------------------------------------------------------------------------------------------------------------------------------------    
  //sigmoid activation function
  float sigmoid(float x) {
    float y = 1 / (1 + pow((float)Math.E, -x));
    return y;
  }
  //returns the matrix that is the derived sigmoid function of the current matrix
  Matrix sigmoidDerived() {
    Matrix n = new Matrix(rows, cols);
    for (int i =0; i<rows; i++) {
      for (int j = 0; j<cols; j++) {
        n.matrix[i][j] = (matrix[i][j] * (1- matrix[i][j]));
      }
    }
    return n;
  }

//---------------------------------------------------------------------------------------------------------------------------------------------------------  
  //returns the matrix which is this matrix with the bottom layer removed
  Matrix removeBottomLayer() {
    Matrix n = new Matrix(rows-1, cols);      
    for (int i =0; i<n.rows; i++) {
      for (int j = 0; j<cols; j++) {
        n.matrix[i][j] = matrix[i][j];
      }
    }
    return n;
  }
//---------------------------------------------------------------------------------------------------------------------------------------------------------  
  //Mutation function for genetic algorithm 
  
  void mutate(float mutationRate) {
    
    //for each element in the matrix
    for (int i =0; i<rows; i++) {
      for (int j = 0; j<cols; j++) {
        float rand = random(1);
        if (rand<mutationRate) {//if chosen to be mutated
          matrix[i][j] += randomGaussian()/5;//add a random value to it(can be negative)
          
          //set the boundaries to 1 and -1
          if (matrix[i][j]>1) {
            matrix[i][j] = 1;
          }
          if (matrix[i][j] <-1) {
            matrix[i][j] = -1;
          }
        }
      }
    }
  }
//---------------------------------------------------------------------------------------------------------------------------------------------------------  
  //returns a matrix which has a random number of values from this matrix and the rest from the parameter matrix
  Matrix crossover(Matrix partner) {
    Matrix child = new Matrix(rows, cols);
    
    //pick a random point in the matrix
    int randC = floor(random(cols));
    int randR = floor(random(rows));
    for (int i =0; i<rows; i++) {
      for (int j = 0; j<cols; j++) {

        if ((i< randR)|| (i==randR && j<=randC)) { //if before the random point then copy from this matric
          child.matrix[i][j] = matrix[i][j];
        } else { //if after the random point then copy from the parameter array
          child.matrix[i][j] = partner.matrix[i][j];
        }
      }
    }
    return child;
  }
//---------------------------------------------------------------------------------------------------------------------------------------------------------  
  //return a copy of this matrix
  Matrix clone() {
    Matrix clone = new  Matrix(rows, cols);
    for (int i =0; i<rows; i++) {
      for (int j = 0; j<cols; j++) {
        clone.matrix[i][j] = matrix[i][j];
      }
    }
    return clone;
  }
}

here NN, also been changed

class NeuralNetwork{
  int iNodes;
  int hNodes;
  int oNodes;
  
  Matrix whi,whh,woh;
  
  NeuralNetwork(int inputs, int hiddenNo, int outputNo){
    iNodes = inputs;
    oNodes = outputNo;
    hNodes = hiddenNo;
    whi = new Matrix(hNodes, iNodes +1);
    whh = new Matrix(hNodes, hNodes +1);
    woh = new Matrix(oNodes, hNodes +1);
    whi.randomize();
    whh.randomize();
    woh.randomize();
  }
  
  float mut(float val, float rate){
    if (random(1) > rate){
      return val + randomGaussian() * .1;
    } else{
      return val;
    }
  }
  
  NeuralNetwork clone() {
    NeuralNetwork clone  = new NeuralNetwork(iNodes, hNodes, oNodes); 
    clone.whi = whi.clone();
    clone.whh = whh.clone();
    clone.woh = woh.clone();

    return clone;
  }
  
  void mutate(float mr) {
    //mutates each weight matrix
    whi.mutate(mr);
    whh.mutate(mr);
    woh.mutate(mr);
  }
  
  float[] output(float[] inputsArr) {

    //convert array to matrix
    //Note woh has nothing to do with it its just a function in the Matrix class
    Matrix inputs = woh.singleColumnMatrixFromArray(inputsArr);

    //add bias 
    Matrix inputsBias = inputs.addBias();

    //apply layer one weights to the inputs
    Matrix hiddenInputs = whi.dot(inputsBias);

    //pass through activation function(sigmoid)
    Matrix hiddenOutputs = hiddenInputs.activate();

    //add bias
    Matrix hiddenOutputsBias = hiddenOutputs.addBias();

    //apply layer two weights
    Matrix hiddenInputs2 = whh.dot(hiddenOutputsBias);
    Matrix hiddenOutputs2 = hiddenInputs2.activate();
    Matrix hiddenOutputsBias2 = hiddenOutputs2.addBias();

    //apply level three weights
    Matrix outputInputs = woh.dot(hiddenOutputsBias2);
    //pass through activation function(sigmoid)
    Matrix outputs = outputInputs.activate();

    //convert to an array and return
    return outputs.toArray();
  }////////////////////////////////////////////////////////////////////////////
  
  NeuralNetwork crossover(NeuralNetwork partner) {

    //creates a new child with layer matrices from both parents
    NeuralNetwork child = new NeuralNetwork(iNodes, hNodes, oNodes);
    child.whi = whi.crossover(partner.whi);
    child.whh = whh.crossover(partner.whh);
    child.woh = woh.crossover(partner.woh);
    return child;
  }
  
   Table NetToTable() {

    //create table
    Table t = new Table();


    //convert the matricies to an array 
    float[] whiArr = whi.toArray();
    float[] whhArr = whh.toArray();
    float[] wohArr = woh.toArray();

    //set the amount of columns in the table
    for (int i = 0; i< max(whiArr.length, whhArr.length, wohArr.length); i++) {
      t.addColumn();
    }

    //set the first row as whi
    TableRow tr = t.addRow();

    for (int i = 0; i< whiArr.length; i++) {
      tr.setFloat(i, whiArr[i]);
    }


    //set the second row as whh
    tr = t.addRow();

    for (int i = 0; i< whhArr.length; i++) {
      tr.setFloat(i, whhArr[i]);
    }

    //set the third row as woh
    tr = t.addRow();

    for (int i = 0; i< wohArr.length; i++) {
      tr.setFloat(i, wohArr[i]);
    }

    //return table
    return t;
  }
  
  void TableToNet(Table t) {

    //create arrays to tempurarily store the data for each matrix
    float[] whiArr = new float[whi.rows * whi.cols];
    float[] whhArr = new float[whh.rows * whh.cols];
    float[] wohArr = new float[woh.rows * woh.cols];

    //set the whi array as the first row of the table
    TableRow tr = t.getRow(0);

    for (int i = 0; i< whiArr.length; i++) {
      whiArr[i] = tr.getFloat(i);
    }


    //set the whh array as the second row of the table
    tr = t.getRow(1);

    for (int i = 0; i< whhArr.length; i++) {
      whhArr[i] = tr.getFloat(i);
    }

    //set the woh array as the third row of the table

    tr = t.getRow(2);

    for (int i = 0; i< wohArr.length; i++) {
      wohArr[i] = tr.getFloat(i);
    }


    //convert the arrays to matrices and set them as the layer matrices 
    whi.fromArray(whiArr);
    whh.fromArray(whhArr);
    woh.fromArray(wohArr);
  }
 }

here wall

class Wall{
  PVector pos;
  Wall(int x, int y){
    pos = new PVector(x*s,y*s);
  }
  
  void show(){
    fill(150,75,0);
    stroke(0);
    rect(pos.x,pos.y,s,s);
  }
  
   boolean lookForHit(PVector loc) {
   // circle collision detection
    if (dist(pos.x, pos.y, loc.x, loc.y)< 50) {
      return true;
    }
    return false;
  }
}

you should be able to run this