Updating ArrayList with additional instances of object

Hello!
I’ve think I’ve made some progress but…

The goal is to:

  • loop through an ArrayList which displays as a grid, – completed
  • randomly select a few of the cells, – completed
  • subdivide the selected into 4 smaller cells, – completed
  • add the new cells to the ArrayList – problem area
  • display the new grid that has the larger and smaller GridCells – problem area

I guess the main problem is I’m not clear on how to access and then integrate the smaller cells into the main ArrayList.

Any guidance is greatly appreciated!
:nerd_face:

//////////////////////////////////////////////////////////////////////////////////////////
Current version of code as follows:

import java.util.List;
List<GridCell>cell = new ArrayList<GridCell>();

void setup() {
  size (600, 600);
  background(255);
  noLoop();

  for (int x = 0; x < width; x+= 100) {
    for (int y = 0; y < height; y+= 100) {
      cell.add(new GridCell(x, y, 100, 100));
    }
  }
}

void draw() {

  for (GridCell c : cell) {
    c.display();
  }
  subdivideCells();
}


void subdivideCells() {
  List<GridCell>fourCells = new ArrayList<GridCell>();
  
  for (int i = 0; i < cell.size(); i++) {
    if (random(1)<0.5)
       cell.get(i).subdivide();  
    cell.add(fourCells); //***this is wrong but I don't know why
  }
}
/////////////////////////////////////////////////////////////////////
class GridCell {
  int x, y, w, h;

  GridCell(int x_, int y_, int w_, int h_) {
    x = x_;
    y = y_;
    w = w_;
    h = h_;
  }

  void display() {
    stroke(0);
    strokeWeight(2);
    rect(x, y, w, h);
  }

  List<GridCell>subdivide() {
    List<GridCell> newCells = new ArrayList();

    newCells.add(new GridCell(x, y, w/2, h/2));
    newCells.add(new GridCell(x+w/2, y, w/2, h/2));
    newCells.add(new GridCell(x, y+h/2, w/2, h/2));
    newCells.add(new GridCell(x+w/2, y+h/2, w/2, h/2));
    
    return newCells;
  }
}

Firstly, here a block with {…} should start because you already have TWO lines that are dependent upon the if clause not only one.

Second: the function returns a new arraylist. You need to receive this arraylist from the function (like List<GridCell> newCells = ...subdivide...). This is where you call the function. Then for loop over the new small arraylist and add the items to the main arraylist. This is all inside said {…}

Hello @Chrisir !
Thank you for the quick reply!
I made 2 changes based on your response, but
See below:

void subdivideCells() {

  for (int i = 0; i < cell.size(); i++) {
    
    List<GridCell>fourCells = new ArrayList<GridCell>(); // move the List to here?

    if (random(1)<0.5) { //added the missing {...}
      cell.get(i).subdivide();  
      cell.add(fourCells);
    }
  }
}

This is the part where I’m most confused. I can’t figure out what I’m supposed to be connecting and in what order…but will look at this some more…
:thinking:

1 Like

I am talking about this line:

cell.get(i).subdivide();

just put the List....= before it

Then for loop over the result list

I think this is getting closer?
But consistent error message on the last line…

void subdivideCells() {

  for (int i = 0; i < cell.size(); i++) {

    if (random(1)<0.5) {
      List<GridCell> newCells = cell.get(i).subdivide(); // Yes?? no error message here now
      //for (int i = 0; i < newCells.size(); i++) { //replaced regular for loop with for each to eliminate duplicate i variable
      for (GridCell g : newCells) {

        cell.add(newCells); //keep getting error message on this line
      }
    }
  }

cell.add(g);

Chrisir

Consider to remove the old cell after you divided it

Which is actually very complicated and should be avoided

1 Like

Thank you!!! That cleared the last error message.
Now the program hangs when I try to run it. Got some time out error messages so not sure what is happening. I’ll try again tomorrow.
Thank you again!!!
I greatly appreciate the help.
:nerd_face:

1 Like

When you think about it it’s actually kind of recursive

So just far too many cells are created

Call this in draw() only 4 times max

Or call it in setup 4 times

Yes, I had thought of trying that. :slight_smile:
Right now, am trying to get a better handle on manipulating arrayLists so probably won’t attempt removing old cells at this time (or maybe ever… :upside_down_face:

1 Like

Just occurred to me that might also be dangerous because we add cells, so that the size grows. Then the for loop
would never stop

I’ll look into this

1 Like

I looked into this, it’s more complicate than I thought it was

ArrayList<GridCell> cells = new ArrayList<GridCell>();

void setup() {
  size (600, 600);
  background(255);
  noLoop();

  // make grid
  for (int x = 0; x < width; x+= 100) {
    for (int y = 0; y < height; y+= 100) {
      cells.add(new GridCell(x, y, 100, 100));
    }
  }

  // divide cells 
  for (int i = 0; i < 16; i++) {
    subdivideCells();
  }
}

void draw() {
  // display grid 
  for (GridCell c : cells) {
    c.display();
  }
}

//-----------------------------------------------------------------------------------------------------
// Other function 

void subdivideCells() {

  // It is necessary to have a controlCounter and use this is in the for-loop since we change the size() of the ArrayList
  int controlCounter=0; 

  // It is necessary to store upperBound and use this is in the for-loop since we change the size() of the ArrayList
  int upperBound = cells.size(); 
  // println(cells.size() +"\n--------------------" ); 

  for (int i = 0; i < upperBound; i++) {
    if (random(1)<0.5) {
      // get this cell from the ArrayList
      GridCell parentCell = cells.get(i);
      // mark this parent cell as dead
      parentCell.isDead=true; 
      // get 4 sub rectangles "newCells" and add them to the main list "cells"
      ArrayList<GridCell> newCells = parentCell.subdivide();
      // replaced regular for loop with for each  
      for (GridCell currentNewCell : newCells) {
        cells.add(currentNewCell);
      }//for
    }//if

    controlCounter++;
    if (controlCounter>1784) {
      println("abort "+controlCounter);
      return;
    }//if
  }//for

  // remove dead cells (backward)
  for (int i = cells.size()-1; i > 0; i--) {
    if (cells.get(i).isDead) {
      cells.remove(i);
    }
  }
}//func 

/////////////////////////////////////////////////////////////////////

class GridCell {

  int x, y, 
    w, h;

  color colGridCell = color(random(255), random(255), random(255)); 

  boolean isDead=false;

  GridCell(int x_, int y_, int w_, int h_) {
    x = x_;
    y = y_;
    w = w_;
    h = h_;
  }

  void display() {
    stroke(0);
    // noStroke(); 
    // strokeWeight(2);
    fill(colGridCell); 
    rect(x, y, w, h);
  }

  ArrayList<GridCell>subdivide() {
    ArrayList<GridCell> newCells = new ArrayList();

    newCells.add(new GridCell(x, y, w/2, h/2));
    newCells.add(new GridCell(x+w/2, y, w/2, h/2));
    newCells.add(new GridCell(x, y+h/2, w/2, h/2));
    newCells.add(new GridCell(x+w/2, y+h/2, w/2, h/2));

    return newCells;
  }//method
  //
}//class
//

1 Like

@Chrisir Thank you so very much!!! This is greatly helpful!! :joy:

I understand all of the code and logic.

But one small question about the control counter.
Code runs the same with the controlCounters commented out.
Is this supposed to be linked to the cells.size()?
I’m probably overlooking something…

1 Like

I had the controlCounter to end the for loop early.

In my tests the image looked best when it was around 1700; when it was 17000 the image had to many black areas, probably due to the black outline stroke color of the rectangles

1 Like

Ok, that makes sense
Thank you again!
:nerd_face:

1 Like