AI Flappy Bird Processing Java

Hi I’m trying to learn to build an AI from the flappy bird video from coding train. I got another game I’m using what I learn on, anyways I reached the part of the video where he saves the bird in js & tried several ways to copy it in java but failed. He turns the bird in a string then saves it then loads it. Very useful when making an AI.

here sketch

ArrayList<bird> population, saved;
ArrayList<pipe> pipes;
float TOTAL;
int Gens;
float counter;
int con = 0;
void setup()
{
  size(640, 480);

  TOTAL = 550;
  pipes = new ArrayList<pipe>();
  population = new ArrayList<bird>();
  saved = new ArrayList<bird>();
  for (int i = 0; i < TOTAL; i++)
  {
    population.add(new bird());
  }
  counter = 0;
}

void draw()
{
  background(51);
  fill(255);
  textSize(30);
  text("Bird: " + population.size(), 10, 30);
  text("Count: " + con, 10, 60);
  text("Gen: " + Gens, 10, 90);
  if (counter % 75 == 0)
  {
    pipes.add(new pipe());
    con += 1;
  }

  for (int i = pipes.size()-1; i >= 0; i--)
  {
    pipe p = pipes.get(i);
    p.update();
    if (p.offscreen())
    {
      pipes.remove(i);
    }

    for (int j = population.size()-1; j >= 0; j--)
    {
      bird b = population.get(j);
      if (p.hit(b) || b.dead())
      {
        saved.add(b);
        population.remove(j);
      }
    }
  }

  if (population.size() == 0)
  {
    counter = 0;
    nextGeneration();
    pipes.clear();
    pipes.add(new pipe());
  }

  for (bird b : population)
  {
    b.show();
    b.update();
    b.think(pipes);
  }

  for (int i = pipes.size()-1; i >= 0; i--)
  {
    pipe p = pipes.get(i);
    p.show();
  }

  counter++;
}

void keyPressed(){// here the problem
  if (key == 's'){
    float sbird = population.get(0);
    String json = sbird.serialize();
  }
}

here ga

void nextGeneration(){
  Gens++;
  println("Generation "+ Gens);
  calculateFitness();
  for (int i = 0; i < TOTAL; i++){
    population.add(pickOne());
  }
  saved.clear();
}

bird pickOne(){
  con = 0;
  int index = 0;
  float r = random(1);
  while (r > 0) {
    r -= saved.get(index).fitness;
    index++;
  }
  index--;
  bird b = saved.get(index);
  bird child = new bird(b.brain);
  child.mutate();
  return child;
}

void calculateFitness(){
  float sum = 0;
  for (bird b : saved){
    sum += b.score;
  }

  for (bird b : saved){
    b.fitness = b.score/sum;
  }
}

here matrix.java

class Matrix{
  int rows, cols;
  float[][] values;

  Matrix(int rows, int cols){
    this.rows = rows;
    this.cols = cols;
    values = new float[this.rows][this.cols];
  }

  Matrix(){
    rows = 1;
    cols = 1;
    values = new float[rows][cols];
  }

  Matrix copy(){
    Matrix result = new Matrix(rows, cols);
    for (int i = 0; i < rows; i++) {
      for (int j = 0; j < cols; j++) {
        result.values[i][j] = values[i][j];
      }
    }
    return result;
  }

  static String[][] stringify(Matrix a){
    String[][] result = new String[a.rows][a.cols];
    for (int i = 0; i < a.rows; i++){
      for (int j = 0; j < a.cols; j++){
        result[i][j] = i+" " + j+" " + a.values[i][j]+" ";
      }
    }
    return result;
  }

  void multiply(float n){
    for (int i = 0; i < rows; i++){
      for (int j = 0; j < cols; j++){
        values[i][j] *= n;
      }
    }
  }

  void add(float n){
    for (int i = 0; i < rows; i++){
      for (int j = 0; j < cols; j++){
        values[i][j] += n;
      }
    }
  }

  static Matrix random(int rows, int cols){
    Matrix result = new Matrix(rows, cols);
    result.randomize();
    return result;
  }

  void randomize(){
    for (int i = 0; i < rows; i++){
      for (int j = 0; j < cols; j++){
        values[i][j] = (float) Math.random() * 2 - 1;
      }
    }
  }

  static Matrix subtract(Matrix a, Matrix b){
    Matrix result = new Matrix(a.rows, a.cols);
    for (int i = 0; i < a.rows; i++){
      for (int j = 0; j < a.cols; j++){
        result.values[i][j] = a.values[i][j] - b.values[i][j];
      }
    }

    return result;
  }

  static Matrix FromArray(float[] arr){
    Matrix result = new Matrix(arr.length, 1);
    for (int i = 0; i < result.rows; i++){
      result.values[i][0] = arr[i];
    }
    return result;
  }

  float[] toArray(){
    float[] arr = new float[rows+cols];
    for (int i = 0; i < rows; i++){
      for (int j = 0; j < cols; j++){
        arr[i] = values[i][j];
      }
    }
    return arr;
  }

  void add(Matrix other){
    for (int i = 0; i < rows; i++){
      for (int j = 0; j < cols; j++){
        values[i][j] += other.values[i][j];
      }
    }
  }

  void multiply(Matrix other){
    for (int i = 0; i < rows; i++){
      for (int j = 0; j < cols; j++){
        values[i][j] *= other.values[i][j];
      }
    }
  }

  static Matrix transpose(Matrix a){
    Matrix result = new Matrix(a.cols, a.rows);
    for (int i = 0; i < a.rows; i++){
      for (int j = 0; j < a.cols; j++){
        result.values[j][i] = a.values[i][j];
      }
    }
    return result;
  }

  static Matrix Product(Matrix first, Matrix second){
    if (first.cols != second.rows){
      return null;
    } else{
      Matrix a = first;
      Matrix b = second;
      Matrix result = new Matrix(a.rows, b.cols);
      for (int i = 0; i < result.rows; i++){
        for (int j = 0; j < result.cols; j++){
          float sum = 0;
          for (int k = 0; k < a.cols; k++){
            sum += a.values[i][k] * b.values[k][j];
          }
          result.values[i][j] = sum;
        }
      }
      return result;
    }
  }
}

here neural network

float sigmoid(float x){
  return 1 / (1+(float)Math.exp(-x));
}

float dsigmoid(float y){
  return y * (1-y);
}

float tanh(float x){
  float y = (float) Math.tanh(x);
  return y;
}

float dtanh(float x) {
  float y = 1 / (pow((float) Math.cosh(x), 2));
  return y;
}

class NeuralNetwork{
  int 
    inputNodes, 
    hiddenNodes, 
    outputNodes;

  float LearningRate = .1;

  Matrix 
    IHWeights, 
    HOWeights, 
    Hbias, 
    Obias, 
    input, 
    hidden, 
    output;

  NeuralNetwork(NeuralNetwork copy){
    inputNodes = copy.inputNodes;
    hiddenNodes = copy.hiddenNodes;
    outputNodes = copy.outputNodes;

    IHWeights = copy.IHWeights.copy();
    HOWeights = copy.HOWeights.copy();
    Hbias = copy.Hbias.copy();
    Obias = copy.Obias.copy();
  }

  NeuralNetwork(int input, int hidden, int output){
    inputNodes = input;
    hiddenNodes = hidden;
    outputNodes = output;

    IHWeights = Matrix.random(hiddenNodes, inputNodes);
    HOWeights = Matrix.random(outputNodes, hiddenNodes);
    Hbias = Matrix.random(hiddenNodes, 1);
    Obias = Matrix.random(outputNodes, 1);
  }

  NeuralNetwork(int input, int hidden, int output, float lr){
    this(input, hidden, output);
    setLearingRate(lr);
  }

  NeuralNetwork copy(){
    return new NeuralNetwork(this);
  }


  float mut(float val, float rate){
    if (random(1) > rate){
      return val + randomGaussian() * .1;
    } else{
      return val;
    }
  }

  void mutate(float rate){
    for (int i = 0; i < IHWeights.rows; i++){
      for (int j = 0; j < IHWeights.cols; j++){
        float val = IHWeights.values[i][j];
        IHWeights.values[i][j] = mut(val, rate);
      }
    }
    
    for (int i = 0; i < HOWeights.rows; i++){
      for (int j = 0; j < HOWeights.cols; j++){
        float val = HOWeights.values[i][j];
        HOWeights.values[i][j] = mut(val, rate);
      }
    }
    
    for (int i = 0; i < Hbias.rows; i++){
      for (int j = 0; j < Hbias.cols; j++){
        float val = Hbias.values[i][j];
        Hbias.values[i][j] = mut(val, rate);
      }
    }
    
    for (int i = 0; i < Obias.rows; i++){
      for (int j = 0; j < Obias.cols; j++){
        float val = Obias.values[i][j];
        Obias.values[i][j] = mut(val, rate);
      }
    }
  }

  void setLearingRate(float rate){
    LearningRate = rate;
  }

  float[] feedForward(float[] inputArray){
    input = Matrix.FromArray(inputArray);

    //generating hidden inputs
    hidden = Matrix.Product(IHWeights, input);
    hidden.add(Hbias);

    //activation function for hidden nodes!
    for (int i = 0; i < hidden.rows; i++){
      for (int j = 0; j < hidden.cols; j++){
        float val = hidden.values[i][j];
        hidden.values[i][j] = sigmoid(val);
      }
    }

    //generating hidden output
    output = Matrix.Product(HOWeights, hidden);
    output.add(Obias);

    //activation function for ouput nodes!
    for (int i = 0; i < output.rows; i++){
      for (int j = 0; j < output.cols; j++){
        float val = output.values[i][j];
        output.values[i][j] = sigmoid(val);
      }
    }

    //generating the output array
    return output.toArray();
  }

  void train(float[] inputArray, float[] targetArray){
    feedForward(inputArray);

    Matrix targets = Matrix.FromArray(targetArray);
    Matrix outputErrors = Matrix.subtract(targets, output);

    //java version of matrix map function
    Matrix gradient = output.copy();
    for (int i = 0; i < gradient.rows; i++){
      for (int j = 0; j < gradient.cols; j++){
        float val = gradient.values[i][j];
        gradient.values[i][j] = dsigmoid(val);
      }
    }

    gradient.multiply(outputErrors);  //elementWise
    gradient.multiply(LearningRate);  //Scalar

    Matrix hiddenT = Matrix.transpose(hidden);
    Matrix DHOWeights = Matrix.Product(gradient, hiddenT);

    HOWeights.add(DHOWeights);

    Obias.add(gradient);

    Matrix HOWeightsT = Matrix.transpose(HOWeights);
    Matrix hiddenErrors = Matrix.Product(HOWeightsT, outputErrors);

    //java version of matrix map function
    Matrix hiddenGradient = hidden.copy();
    for (int i = 0; i < hiddenGradient.rows; i++){
      for (int j = 0; j < hiddenGradient.cols; j++){
        float val = hiddenGradient.values[i][j];
        hiddenGradient.values[i][j] = dsigmoid(val);
      }
    }

    hiddenGradient.multiply(hiddenErrors);
    hiddenGradient.multiply(LearningRate);

    Matrix inputT = Matrix.transpose(input);
    Matrix DIHWeights = Matrix.Product(hiddenGradient, inputT);

    IHWeights.add(DIHWeights);

    Hbias.add(hiddenGradient);
  }
}

here pipe

class pipe{

  float top;
  float bottom;
  float x;
  float w;
  float speed;
  float spacing;

  pipe(){
    spacing = 125;
    top = random(height/ 6, .75 * height);
    bottom = height - (top + spacing);
    w = 80;
    x = width;
    speed = 6;
  }

  void show(){
    fill(255);
    rectMode(CORNER);
    rect(x, 0, w, top);
    rect(x, height-bottom, w, bottom);
  }

  void update(){
    x -= speed;
  }

  boolean offscreen(){
    return x < -w;
  }

  boolean hit(bird b){
    if (b.pos.y < top+b.r || b.pos.y+b.r > height-bottom){
      if (b.pos.x+b.r > x && b.pos.x < (x + w)+b.r)
        return true;
    }
    return false;
  }
}

here bird

class bird{
  PVector pos, vel, acc;
  PVector gravity, jump;
  float r = 16;
  float d = r * 2;
  boolean alive = true;
  float[] inputs = new float[5];
  float score = 0;
  float fitness = 0;
  NeuralNetwork brain;

  bird(){
    pos = new PVector(64, height/2);
    vel = new PVector();
    gravity = new PVector(0, .8);
    jump = new PVector(0, 16);
    score = 0;
    fitness = 0;
    brain = new NeuralNetwork(5, 64, 2);
  }

  bird(NeuralNetwork b){
    pos = new PVector(64, height/2);
    vel = new PVector();
    gravity = new PVector(0, .8);
    jump = new PVector(0, -12);
    score = 0;
    fitness = 0;
    brain = b.copy();
  }

  void mutate(){
    brain.mutate(.01);
  }

  void think(ArrayList<pipe> pipe){
    pipe closest = null;
    float recordD = Float.POSITIVE_INFINITY;
    for (int i = 0; i < pipe.size(); i++){
      pipe p = pipe.get(i);
      float d = (p.x+p.w) - pos.x;
      if (d < recordD && d > 0){
        closest = pipe.get(i);
        recordD = d;
      }
    }


    inputs[0] = pos.y / height;
    inputs[1] = vel.y / 10;
    inputs[2] = closest.top / height;  
    inputs[3] = closest.bottom / width;
    inputs[4] = closest.x / width;
    float[] guess = brain.feedForward(inputs);
    if (guess[0] > guess[1]){
      jump();
    }
  }

  void show(){
    stroke(255);
    fill(255, 100);
    circle(pos.x, pos.y, d);
  }

  void update(){
    score++;
    vel.add(gravity);
    pos.add(vel);
  }

  void jump(){
    vel.add(jump);
  }

  boolean dead(){
    return (pos.y+r > height || pos.y < r);
  }
}

so can anyone help me save the bird to a file?

1 Like

i’ve done this before.
the “brain” is a bunch of matrices. in order to save it to a file (csv table), firstly, you have to convert the matrix to 1-dimension array for each Matrix and insert all of the arrays as rows to a table. then save it to csv file.
another time you want to recover the brain, you have to do it backward, means convert all the arrays to matrices then load to the brain.

this is the reference about saving and load table: https://processing.org/reference/saveTable_.html

for matrix to 1-dimension array conversion, heres the code,

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;
  }

and from 1-dimension to matrix, heres the code

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];
      }
    }
  }
1 Like

TY, I know how to load tables. So um … would I place the float [] toArray in the press ‘s’ or in its own function?

sorry, im not sure what do you mean. take a look at this complete code for saving and loading “similar brain”.
(from CodeBullet: Asteroid AI)

//converts the weights matrices to a single table 
  //used for storing the snakes brain in a file
  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;
  }


  //takes in table as parameter and overwrites the matricies data for this neural network
  //used to load snakes from file
  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 matricies and set them as the layer matricies
    whi.fromArray(whiArr);
    whh.fromArray(whhArr);
    woh.fromArray(wohArr);
  }

the part for save and load brain

 void savePlayer(int playerNo, int score, int popID, boolean bestO) {
    //save the players top score and its population id 
    Table playerStats = new Table();
    playerStats.addColumn("Top Score");
    playerStats.addColumn("PopulationID");
    TableRow tr = playerStats.addRow();
    tr.setFloat(0, score);
    tr.setInt(1, popID);

    saveTable(playerStats, "data/playerStats" + playerNo+ ".csv");

    //save players brain
    saveTable(brain.NetToTable(), "data/player" + playerNo+ ".csv");
  }
  //---------------------------------------------------------------------------------------------------------------------------------------------------------  

  //return the player saved in the parameter posiition
  Player loadPlayer(int playerNo) {
    Table t;
    Player load = new Player();
    t = loadTable("data/player" + playerNo + ".csv");
    load.brain.TableToNet(t);
    return load;
  }
1 Like

wait it looks like you just saved the top score and the id. I’m looking to save the brain of the bird. How it thinks. All the numbers in its head. TY for replying & what I meant was i was planning on hitting ‘s’ to save the bird. Then ‘l’ to load the bird & place it into the population.

oh sorry, i forgot to highlight. thats the complete codes for saving including high score and brain.

this is the part when saving the brain.
reference to the whole game: https://github.com/Code-Bullet/AsteroidsAI

1 Like

ty that is helpful on the topic of ai brain can you place a boolean in the brain as one of the inputs?

yes you can input boolean value, just replace 1 for true and 0 false

TY, I wanted it to like see but then after couldn’t figure out how people got there ai to see in different directions I went to what I knew and made booleans to say if there was anything in the way. I’ll try adding the saveTable stuff into the code.

based my experiences. if you want say if there was anything in the way, the best way to do it is giving the distance from the player to the object instead of just giving boolean value. the concept is the player has sight and seeing in a limited angle of view. good luck!

I’m making the enemy loop through all the walls and see if anything is within the spot i’m checking. If not the boolean is false, but if there is something the boolean is true. Then it feeds that intel into the inputs & guesses what to do. I guess it kinda like it only knows if anything is within the spots around it, but still not as i want. But I gotta start somewhere making my first game played by an ai.

Nice project!
some of difficult parts are determine how the player seeing and the fitness function. if something not suitable, the player wont evolve

ty, you are being very helpful. I’ll try and let you know how it goes. Some of mine are just staying in one place what should I do? I was thinking have a timer to check if they moved. Any ideas?

1 Like

So far my idea of using a timer didn’t work. I got like 20 that stop moving or move back and forth in place. So far I got my nn up and running but no enemy has gotten pass the first row. They do good first few generations then they just decide to run into the wall over 80 gen. So far I don’t need any towers in my tower defense game the enemies kill themselves. Here a picture of the course I’m trying to get them to run. Is it too hard?

hmm… can i see the codes?

Yea sure, I think I fixed it by setting a personal timer instead of global… I went with your idea of just letting them know where all the blocks are. Ever since I changed to letting it know the dist to every block it seems to use more memory.
here is sketch

int s = 20;
int hw;
int Total = 250;
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;
TableRow wallRow;
int map = 0;
int col;

void setup(){
  size(580,580);
  for (int i = 0; i < 5; i++){
    bests[i] = 0;
    beste[i] = 0;
  }
  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());
  }
  ea = new EndArea(26,25);
}

void draw(){
  background(0);
  textSize(20);
  text("Gen: " + gen, 1 * s, 6 * s);
  text("Pop: " + population.size(), 1 * s, 7 * s);
  for (Wall w: wall){
    w.show();
  }
  ea.show();
  if (population.size() == 0){
    nextGeneration();
  }
  for (Enemy e: population){
    e.show();
    e.check();
    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);
    }
  }
}

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{
  int x,y;
  int r = 12;
  float score = 0;
  float fitness = 0;
  int nx,ny;
  boolean collide = false;
  boolean won = false;
  boolean up,down,left,right,failed;
  int timer = 100;
  int nummove = 0;
  
  float[] inputs = new float[274];
  NeuralNetwork brain;
  
  Enemy(){
    x = 2 * s;
    y = 2 * s;
    nx = this.x;
    ny = this.y;
    brain = new NeuralNetwork(274, 94, 4);
  }
  Enemy(NeuralNetwork b){
    x = 2 * s;
    y = 2 * s;
    nx = this.x;
    ny = this.y;
    brain = b.copy();
  }
  
  void mutate(){
    brain.mutate(0.1);
  }
  
  void think(){
    inputs[0] = x;
    inputs[1] = y;
    inputs[2] = ea.x;
    inputs[3] = ea.y;
    for (int i = 0; i < wall.size(); i++){
      Wall w = wall.get(i);
      float d = dist(w.x,w.y,x,y);
      inputs[4 + i] = d;
    }
    float[] guess = brain.feedForward(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,x,y);
      if (d < s){
        failed = true;
      }
      else {
        if (y > ny + (s * 2)){
          fitness *= 2;
        }
        nx = x;
        ny = y;
        timer = 100;
      }
    }
    score += 1;
    if (failed == true){fill(0,255,0);}
    if (failed == false){fill(255,0,0);}
    rect(x,y,s,s);
  }
  
  void check(){
    for (int i = 0; i < wall.size(); i++){
      Wall w = wall.get(i);
      float d = dist(w.x,w.y,x,y);
      if (d < s){
        collide = true;
      }
    }// wall
    if (x >= ea.x && x < ea.x + ea.w && y >= ea.y && y < ea.y + ea.h){
      won = true;
      score = score * 2;
    }
  }// check
  
  void move(int xspd, int yspd){
    if (won == false){
      x += xspd;
      y += yspd;
    }
    xspd = 0;
    yspd = 0;
    left = false;
    right = false;
    up = false;
    down = false;
  }
}

here GA, i want the 5 best of the gen

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

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;
}

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;
    }
    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.java

class Matrix{
  int rows, cols;
  float[][] values;

  Matrix(int rows, int cols){
    this.rows = rows;
    this.cols = cols;
    values = new float[this.rows][this.cols];
  }

  Matrix(){
    rows = 1;
    cols = 1;
    values = new float[rows][cols];
  }

  Matrix copy(){
    Matrix result = new Matrix(rows, cols);
    for (int i = 0; i < rows; i++) {
      for (int j = 0; j < cols; j++) {
        result.values[i][j] = values[i][j];
      }
    }
    return result;
  }

  static String[][] stringify(Matrix a){
    String[][] result = new String[a.rows][a.cols];
    for (int i = 0; i < a.rows; i++){
      for (int j = 0; j < a.cols; j++){
        result[i][j] = i+" " + j+" " + a.values[i][j]+" ";
      }
    }
    return result;
  }

  void multiply(float n){
    for (int i = 0; i < rows; i++){
      for (int j = 0; j < cols; j++){
        values[i][j] *= n;
      }
    }
  }

  void add(float n){
    for (int i = 0; i < rows; i++){
      for (int j = 0; j < cols; j++){
        values[i][j] += n;
      }
    }
  }

  static Matrix random(int rows, int cols){
    Matrix result = new Matrix(rows, cols);
    result.randomize();
    return result;
  }

  void randomize(){
    for (int i = 0; i < rows; i++){
      for (int j = 0; j < cols; j++){
        values[i][j] = (float) Math.random() * 2 - 1;
      }
    }
  }

  static Matrix subtract(Matrix a, Matrix b){
    Matrix result = new Matrix(a.rows, a.cols);
    for (int i = 0; i < a.rows; i++){
      for (int j = 0; j < a.cols; j++){
        result.values[i][j] = a.values[i][j] - b.values[i][j];
      }
    }

    return result;
  }

  static Matrix FromArray(float[] arr){
    Matrix result = new Matrix(arr.length, 1);
    for (int i = 0; i < result.rows; i++){
      result.values[i][0] = arr[i];
    }
    return result;
  }

  float[] toArray(){
    float[] arr = new float[rows+cols];
    for (int i = 0; i < rows; i++){
      for (int j = 0; j < cols; j++){
        arr[i] = values[i][j];
      }
    }
    return arr;
  }

  void add(Matrix other){
    for (int i = 0; i < rows; i++){
      for (int j = 0; j < cols; j++){
        values[i][j] += other.values[i][j];
      }
    }
  }

  void multiply(Matrix other){
    for (int i = 0; i < rows; i++){
      for (int j = 0; j < cols; j++){
        values[i][j] *= other.values[i][j];
      }
    }
  }

  static Matrix transpose(Matrix a){
    Matrix result = new Matrix(a.cols, a.rows);
    for (int i = 0; i < a.rows; i++){
      for (int j = 0; j < a.cols; j++){
        result.values[j][i] = a.values[i][j];
      }
    }
    return result;
  }

  static Matrix Product(Matrix first, Matrix second){
    if (first.cols != second.rows){
      return null;
    } else{
      Matrix a = first;
      Matrix b = second;
      Matrix result = new Matrix(a.rows, b.cols);
      for (int i = 0; i < result.rows; i++){
        for (int j = 0; j < result.cols; j++){
          float sum = 0;
          for (int k = 0; k < a.cols; k++){
            sum += a.values[i][k] * b.values[k][j];
          }
          result.values[i][j] = sum;
        }
      }
      return result;
    }
  }
}

here NN

float sigmoid(float x){
  return 1 / (1+(float)Math.exp(-x));
}

float dsigmoid(float y){
  return y * (1-y);
}

float tanh(float x){
  float y = (float) Math.tanh(x);
  return y;
}

float dtanh(float x) {
  float y = 1 / (pow((float) Math.cosh(x), 2));
  return y;
}

class NeuralNetwork{
  int 
    inputNodes, 
    hiddenNodes, 
    outputNodes;

  float LearningRate = .1;

  Matrix 
    IHWeights, 
    HOWeights, 
    Hbias, 
    Obias, 
    input, 
    hidden, 
    output;

  NeuralNetwork(NeuralNetwork copy){
    inputNodes = copy.inputNodes;
    hiddenNodes = copy.hiddenNodes;
    outputNodes = copy.outputNodes;

    IHWeights = copy.IHWeights.copy();
    HOWeights = copy.HOWeights.copy();
    Hbias = copy.Hbias.copy();
    Obias = copy.Obias.copy();
  }

  NeuralNetwork(int input, int hidden, int output){
    inputNodes = input;
    hiddenNodes = hidden;
    outputNodes = output;

    IHWeights = Matrix.random(hiddenNodes, inputNodes);
    HOWeights = Matrix.random(outputNodes, hiddenNodes);
    Hbias = Matrix.random(hiddenNodes, 1);
    Obias = Matrix.random(outputNodes, 1);
  }

  NeuralNetwork(int input, int hidden, int output, float lr){
    this(input, hidden, output);
    setLearingRate(lr);
  }

  NeuralNetwork copy(){
    return new NeuralNetwork(this);
  }


  float mut(float val, float rate){
    if (random(1) > rate){
      return val + randomGaussian() * .1;
    } else{
      return val;
    }
  }

  void mutate(float rate){
    for (int i = 0; i < IHWeights.rows; i++){
      for (int j = 0; j < IHWeights.cols; j++){
        float val = IHWeights.values[i][j];
        IHWeights.values[i][j] = mut(val, rate);
      }
    }
    
    for (int i = 0; i < HOWeights.rows; i++){
      for (int j = 0; j < HOWeights.cols; j++){
        float val = HOWeights.values[i][j];
        HOWeights.values[i][j] = mut(val, rate);
      }
    }
    
    for (int i = 0; i < Hbias.rows; i++){
      for (int j = 0; j < Hbias.cols; j++){
        float val = Hbias.values[i][j];
        Hbias.values[i][j] = mut(val, rate);
      }
    }
    
    for (int i = 0; i < Obias.rows; i++){
      for (int j = 0; j < Obias.cols; j++){
        float val = Obias.values[i][j];
        Obias.values[i][j] = mut(val, rate);
      }
    }
  }

  void setLearingRate(float rate){
    LearningRate = rate;
  }

  float[] feedForward(float[] inputArray){
    input = Matrix.FromArray(inputArray);

    //generating hidden inputs
    hidden = Matrix.Product(IHWeights, input);
    hidden.add(Hbias);

    //activation function for hidden nodes!
    for (int i = 0; i < hidden.rows; i++){
      for (int j = 0; j < hidden.cols; j++){
        float val = hidden.values[i][j];
        hidden.values[i][j] = sigmoid(val);
      }
    }

    //generating hidden output
    output = Matrix.Product(HOWeights, hidden);
    output.add(Obias);

    //activation function for ouput nodes!
    for (int i = 0; i < output.rows; i++){
      for (int j = 0; j < output.cols; j++){
        float val = output.values[i][j];
        output.values[i][j] = sigmoid(val);
      }
    }

    //generating the output array
    return output.toArray();
  }

  void train(float[] inputArray, float[] targetArray){
    feedForward(inputArray);

    Matrix targets = Matrix.FromArray(targetArray);
    Matrix outputErrors = Matrix.subtract(targets, output);

    //java version of matrix map function
    Matrix gradient = output.copy();
    for (int i = 0; i < gradient.rows; i++){
      for (int j = 0; j < gradient.cols; j++){
        float val = gradient.values[i][j];
        gradient.values[i][j] = dsigmoid(val);
      }
    }

    gradient.multiply(outputErrors);  //elementWise
    gradient.multiply(LearningRate);  //Scalar

    Matrix hiddenT = Matrix.transpose(hidden);
    Matrix DHOWeights = Matrix.Product(gradient, hiddenT);

    HOWeights.add(DHOWeights);

    Obias.add(gradient);

    Matrix HOWeightsT = Matrix.transpose(HOWeights);
    Matrix hiddenErrors = Matrix.Product(HOWeightsT, outputErrors);

    //java version of matrix map function
    Matrix hiddenGradient = hidden.copy();
    for (int i = 0; i < hiddenGradient.rows; i++){
      for (int j = 0; j < hiddenGradient.cols; j++){
        float val = hiddenGradient.values[i][j];
        hiddenGradient.values[i][j] = dsigmoid(val);
      }
    }

    hiddenGradient.multiply(hiddenErrors);
    hiddenGradient.multiply(LearningRate);

    Matrix inputT = Matrix.transpose(input);
    Matrix DIHWeights = Matrix.Product(hiddenGradient, inputT);

    IHWeights.add(DIHWeights);

    Hbias.add(hiddenGradient);
  }
}

here walls

class Wall{
  int x,y;
  Wall(int x, int y){
    this.x = x * s;
    this.y = y * s;
  }
  
  void show(){
    fill(150,75,0);
    rect(x,y,s,s);
  }
}
1 Like

put the player like in the real life. it sees the environment with a field of view.
Pengertian-Field-of-View-Equivalent-Focal-Length-dan-Angle-of-View-03
so all the objects within that range, will be feed to the brain.
this is how the visualisation

this way will work better than just feeding the distances to each block

by CodeBullet:AsteroidAI

1 Like

so would I then check range? like x < range then get the x?
I changed think to this.

void think(){
    inputs[0] = x;
    inputs[1] = y;
    inputs[2] = dea = dist(ea.x,ea.y,x,y);
    for (int i = wall.size()-1; i >= 0; i--){
      Wall w = wall.get(i);
      if (w.y == y + s && w.x >= x && w.x < x + s){ddown = y;}
      if (w.y == y - s && w.x >= x && w.x < x + s){dup = y;}
      if (w.x == x + s && w.y >= y && w.y < y + s){dright = x;}
      if (w.x == x - s && w.y >= y && w.y < y + s){dleft = x;}
    }
    inputs[3] = ddown;
    inputs[4] = dup;
    inputs[5] = dleft;
    inputs[6] = dright;
    float[] guess = brain.feedForward(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);}
  }

you have to loop through in certain direction until it found a block or a wall. and feed it the normalized distance to the wall or block to the inputs

btw, i cannot run the codes. maybe the problem with the ide

dont forget to normalize all of the inputs before feeding it