Remove/clear objects from an arrayList

Hello all; I am having trouble removing points from my canvas. The points, actually ellipses, are held in an arraylist. I have written the code so that once the mouse is pressed, the points should disappear and start over. The problem is, they do not remove. The problem is on lines 218-221 and the class is at the bottom of the code, around line 400. Thanks. import org.gicentre.utils.stat.*; //import graph library

//import g4p_controls.*;

ArrayList<Ball> balls = new ArrayList(); // arraylist for ball objects
ArrayList<Point> points = new ArrayList();
float gcorX, gcorY; // goal coords
int timeIter = 300; //time step- internal clock

float bscore; //best score

String[] str_a;   //one copy of scorelist (use to copies to determine best and worst)
String[] str_b;   //one copy of scorelist (use to copies to determine best and worst)
float[] scores;   //scorelist
final int pop = 10; //population size- final bc it shouldnt be changed in the program
int cur_sub;      //current iteration- OLD METHOD, but still in just in case
public int gen_num = 0; //count generation number
int countDone; // count how many balls in the population finished their run in that generation
float diameter = 30;
float globmin = 1000; //base var
float [] generations; // array of generations
int total = points.size();

//GWindow window;

Ball globalBall = new Ball(-1, "0"); // starter/ global best ball


//public void windowDraw(PApplet app, GWinData data) {

//  app.background(0);
//  //app.point((gen_num*2), min(scores));

//  } 


//public void windowMouse(PApplet app, GWinData data, MouseEvent event) {
//}

//public void windowKey(PApplet app, GWinData data, KeyEvent event) {
//}

void setup() {
  size(800, 800);
  background(0);

  generations = new float[gen_num]; // init generations with size

  //window =  GWindow.getWindow(this, "Graph", 100, 50, 500, 500, JAVA2D);

  //window.addDrawHandler(this, "windowDraw");
  //window.addMouseHandler(this, "windowMouse");
  //window.addKeyHandler(this, "windowKey");

  bscore = dist(0, 0, width, height); // calc score
  gcorX= random(width);
  gcorY= random(height);

  ellipseMode(CENTER);

  //begin init scorestrings
  str_a = new String[pop];
  str_b = new String[pop];
  scores = new float[pop];
  for (int j = 0; j<pop; j++) {
    str_a[j] = starterString();
    scores[j] = 0;
  }
  //end init scorestrings

  //for every done ball, add a new one/replace it
  cur_sub = -1;
  countDone = 0;
  for ( int i=0; i < pop; i++ ) balls.add( new Ball( i, str_a[i] ) );
}


//begin init of starter string( Initial) so that the mutation has a place to begin

String starterString() {
  String mut = "" + char( '0' + int( random(4) ) ); //  + "00000000" ;
  return( mut );
}

//end init

//begin init instructions and strings of values- cr and hr refer to the textlines explaining each movement. r is a placeholder string so that the strings return a value to it based on the results of the cr loop

String hr( String cr ) {
  String r = "";
  for ( int t = 0; t < cr.length(); t++) {
    if ( cr.charAt(t) == '0' ) r+= 'N';
    if ( cr.charAt(t) == '1' ) r+= 'L';
    if ( cr.charAt(t) == '2' ) r+= 'R';
    if ( cr.charAt(t) == '3' ) r+= 'A';
  }
  return( r );
}

//end init instructions and cr/hr

void draw() {
  background(0); //layer 2
  fill(255, 0, 0); //red
  //starting pad
  pushMatrix();
  stroke(255, 200);
  fill(0, 255, 0, 200);
  ellipse(width/2, height/2, 25, 25);
  popMatrix();
  //end starting pad


  String extra = ""; //message
  if ( bscore < 20 ) extra = "That's close enough! Click the mouse to move the goal."; //message

  //text inits and placements
  pushMatrix();
  fill(255, 0, 0);
  text("| Best ever: (" + hr(globalBall.genome) + ") = " + int(bscore) + " |", 50, 20 );
  popMatrix();

  pushMatrix();
  fill(255, 200);
  text("| key: A = accelerate, R = right, L = left, N = do nothing | ", 500, height-20);
  popMatrix();

  pushMatrix();
  fill(0, 0, 255);
  text(extra, 30, height -20);
  fill(#3FB73F);
  text("| Generation " + gen_num+ " |", 280, 20 );
 text("| minimum of gen:" + (min(scores))+ " |", 400, 20); //why does this get a NullPointer Exception? and why does it not plot the points? Frustrated. 
  text("| best:" + (bscore)+ " |", 600, 20);

  popMatrix();
  //end text inits and placements

  //globmin = min(globmin, min(scores));
  //text("globmin: " + globmin, 250, 34);


  //text for genome (hr/cr);
  for ( int tt=0; tt< pop; tt++) {
    fill (balls.get(tt).col);
    text( "(" + hr( balls.get(tt).genome ) + ")", 10, 48 + 14 * tt);
  }
  //text for genome (hr/cr);

  // If no ball, last ball is done, simulate next one.
  // If all balls done, simulate next generation.
  if ( countDone == pop ) { // balls.size() == 0 ) {
    while ( balls.size () > 0 ) balls.remove(0); 
    //cur_sub++;
    // If all balls in this generation simulated, create next generation.
    //if ( cur_sub == gen_size ) {
    countDone = 0; // cur_sub = 0;
    //println( "Making next generation..." );


    // Always keep the best one, and toss the worse.
    arrayCopy( str_a, str_b ); //copy for scrambling later
    int bestIndex = 0;
    int worstIndex = 0;
    for ( int j = 0; j < pop; j++ ) {
      if ( scores[bestIndex] > scores[j] ) {
        bestIndex = j;
      } //getting best score for index

      if ( scores[worstIndex] < scores[j] ) {
        worstIndex = j;
      }
      //getting worst score for index
    }  

    str_b[worstIndex] = str_b[bestIndex]; // Replace the worst with a copy of the best for breeding.

    // Scramble.
    for ( int j = 0; j < pop; j++ ) {
      str_a[j] = scramble( j, str_b[int(random(pop))], str_b[int(random(pop))] ); //scrambles initial a(stored in b) and replaces old a with new values
    }
    str_a[0] = str_b[bestIndex]; // Always keep the best.
    //Add all the balls to simulate.

    for ( int j = 0; j < pop; j++ ) {
      balls.add( new Ball( j, str_a[j] ) );
    }

    gen_num++; //increment generation counter

    //}
  }

  globalBall.render(); // draw best as red(see coloring above in beginning of draw)


  for ( int i=0; i < balls.size(); i++ ) balls.get(i).move(); //init move function for balls

  //begin goal init

  stroke(255);
  fill(255, 140);
  ellipse(gcorX, gcorY, diameter, diameter);

  //end goal init





  Point p = new Point(gen_num, (min(scores)+292.89));
points.add(p);

   for(Point pt: points){
pt.displaypt();
   }

   if(mousePressed ==true){
     for(int l = 0; l<total; l++){
     points.remove(l);
     }

   }






} // end draw

String scramble( int which, String a, String b ) { // begin switching random values with substring r as the intermediate
  String r;
  int pos = int(random(min(a.length(), b.length())));
  r = a.substring(0, pos) + b.substring(pos, b.length());

  // Mutation! //change or add a random value between position 0 and length of r
  if ( random(1) < .5 ) {
    pos = int(random(r.length()));
    if ( random(1) < .5 ) { 
      String mut = "" + char( '0' + int( random(4) ) );
      //println( "New Ball #" + which + ": Mutation! Adding a char: '" + mut + "' at position " + pos );
      r = r.substring(0, pos) + mut + r.substring(pos, r.length());
    } else {
      if ( r.length() > 0 ) {
        pos = int(random(r.length()-1));
        //println( "New Ball #" + which + ": Mutation! Losing the char at position " + pos );
        r = r.substring(0, pos) + r.substring(pos+1, r.length());
      }
    }
  }
  return( r ); //return the value to change the initial strings, reset w/change basically
}

//begin goal changing 
void mousePressed() {
  if (mouseButton == LEFT) {
    gcorX = random(width);
    gcorY = random(height);
    bscore = dist(0, 0, width, height);
    gen_num=0;
  }
}
//end goal changing


class Ball {
  float x, y, z, v; //position related
  color col; //color of balls
  int current_inst;//current instruction
  int inst_time;//time between instructions
  int[] instructions; //array of instructions
  boolean dis = false; //disable ball
  int num; //uuuhhhh... i forget
  String genome; //GENOME
  int checknum; //check number for genome val to ensure smooth transition

  boolean inst_a, inst_b, inst_c; //instructions

  Ball(int cknum, String input) {
    //x = width/2;
    //y = height-20;
    x = width/2;
    y = height/2;
    if (cknum == -1) {  
      x = -20;
      y = -20;
    }
    z =0;
    v = 0;

    col=color(random(40, 255), random(40, 255), random(40, 255), 200);
    inst_a = inst_b = inst_c = false; 
    checknum = cknum; //making sure the numbers are the same to avoid glitches
    current_inst = 0;
    checkString( input );
    inst_time = millis() + timeIter;
    dis = false; //not disabled
    genome = input; //read input (parse/checkstring) and input it into the genome
  }

  void checkString(String in) {    //parsing function
    instructions = new int[in.length()];
    for ( int j = 0; j < in.length(); j++ ) {
      instructions[j] = int( in.charAt(j) - '0' );
    }
    //reads each character in the input string and puts it into instructions to be enacted
  }

  //begin scoreReport- uses an array to store the scores of the generation so that a best and a worst can be calculated

  void scoreRep() {
    scores[checknum] = dist(x, y, gcorX, gcorY) + genome.length(); //uses the distance between the translated ball(at x, y) and the goal at the gcords. //also, just added a penalty for length of genome, to try and promote a more direct route
    if ( scores[checknum] < bscore ) { // if the score is not the best score, change the scores to be recalculated by the next generation
      bscore = scores[checknum];
      globalBall.x = x;
      globalBall.y = y;
      globalBall.z = z;
      globalBall.col = col;
      globalBall.genome = genome; //checks the best aspects and records the genome, moves the values for position
    }
    countDone++;
    //if ( scores[checknum] < 20 ) {
    //  gcorX = random(width);
    //  gcorY = random(height);
    //}
    //balls.remove(0);
  }

  void move() {
    if ( millis() > inst_time && !dis) { // if the millisecond function (internal clock) is greater than the instance time and not disabled, 
      inst_time = millis() + timeIter; //time between things
      if ( current_inst < instructions.length ) { //for every instruction in the instruction array 
        int i = instructions[current_inst++]; //i is used to represent the value of the instruction at the current instruction value
        switch( i ) { //switches between actions for instruction. For example, if the value "i" is 2, it would enact instruction case 2. it reads and enacts on the instructions based on their value and reads them in sequence based on their position in the array
        case 0:
          // Do nothing.
          break;
        case 1:
          inst_a = !inst_a;
          break;
        case 2:
          inst_b = !inst_b;
          break;
        case 3:
          inst_c = !inst_c;
          break;
        default:
          //println( "Bum instruction: " + i )//instruction does not exist
          break;
        }
      } else { // Terminate run.
        inst_a=inst_b=inst_c=false;
        v=0;
        dis = true; // disable is true, end run, set v to 0, set instructions to false, and statify the scoreReport
        scoreRep();
      }
    }
    // movement systems follow.
    z+=(inst_a?-.1:0)+(inst_b?.1:0); //conditional operator/ternary operator. I dont want to explain it here, it is a shorthand. Go here for more: http://stackoverflow.com/questions/798545/what-is-the-java-operator-called-and-what-does-it-do
    v+=(inst_c?.1:0); //conditional
    //x=(x+width+v*cos(z))%width;
    //y=(y+height+v*sin(z))%height;
    x=x+v*cos(z); //math for x based on angle of movement (v is basically serving as a hypotenuse here)
    y=y+v*sin(z); //math for y based on angle of movement (v is basically serving as a hypotenuse here)
    v*=.99;
    render(); //calls a display function
  }
  void render() {
    pushMatrix(); //layer 4
    translate(x, y); //move the thing by the x and y calculated in move
    rotate(z); //rotate by z
    noStroke();
    fill(col); //fill with color 

    if ( checknum==-1) fill(255, 0, 0); //if it is the best ball, color it red
    ellipseMode(CENTER); //put measurements in center
    ellipse(0, 0, 25, 25); //ball size
    stroke(0);//black edge

    noFill(); //triangle no fill
    triangle(-6, -5, 8, 0, -6, 5); //  triangle(-5, -8.66, 0, 10, 5, -8.66);
    popMatrix();
  }
}


class Point{
  float xpos, ypos;
  float size = 2;

  Point(float x, float y){

    xpos = x;
    ypos = y;
  }



  void displaypt(){
    pushMatrix();
    noStroke();
    fill(255, 0, 0, 100);
    ellipse(xpos, ypos, size, size);
    popMatrix();

  }
}

Answers

  • Easiest fix is doing the loop backwards. See posts over backwards tag:
    https://forum.Processing.org/two/discussions/tagged/backwards

  • edited August 2016

    I tried replacing the code with

      if (mousePressed ==true) {
        for (int l = total-1; l>= 0; l--) {
          points.remove(l);
        }
      }
    

    but it doesn't seem to have worked. Is there any complications with using enhanced loops?

  • Answer ✓

    If you wanna remove() all at once, just invoke clear():
    http://docs.Oracle.com/javase/8/docs/api/java/util/Collection.html#clear--

  • Answer ✓

    but it doesn't seem to have worked.

    What is that variable total? Use method size() instead:
    for (int i = points.size(); i-- != 0; points.remove(i));

    But as I've mentioned earlier, clear() gets the job done in this case. B-)

  • total is points.size(), just wanted it as a variable. Dunno why. I tried using clear, but it just clears the screen for a second and the points are still there when it ends. NEVERMIND though- your reverse loop (for (int i = points.size(); i-- != 0; points.remove(i));) worked just fine. Thanks for the help!

  • edited August 2016 Answer ✓

    ... but it just clears the screen for a second and the points are still there when it ends.

    In order to clear the canvas, we use background().
    I'm puzzled how clear() method failed and the backwards loop + remove() was successful! @-)

  • edited August 2016

    The clear cleared the whole screen only while the mouse was pressed- I might have used it incorrectly, as I just called clear(); in an if(mousePressed){ }. However, it works like a charm! and good to know about the background();. Thanks!

  • edited August 2016 Answer ✓

    Oh, you've called Processing's clear() function instead of Collection's clear() method: ^#(^

    1. https://processing.org/reference/clear_.html
    2. http://docs.Oracle.com/javase/8/docs/api/java/util/Collection.html#clear--

    In short, you shoulda called points.clear() in order to remove() all elements from that Collection.

Sign In or Register to comment.