Creating a function that returns an ArrayList of manipulated objects

Hello!!

I have been trying to figure out the syntax to create a method that will subdivide a GridCell object.

The GridCells display in the main program in a 2-D grid.
In the main program I want to be able to loop thru the grid, select a GridCell, and divide that cell into 4 new smaller cells.
I have picked up some info via Coding Train, stack overflow, and myriad other sites. However reaching a point in the code below.

I have read/watched content that discusses passing a reference vs passing a value, in addition to methods that return arrayLists. I think this will somehow affect how to write the syntax but am not sure how to integrate this into the code.

Additionally, since a function can only return a single value/reference—and I need to return 4 separate values/referneces—I have placed 4 functions (one for each value to be returned) into a function that would return an ArrayLIst of the 4 values returned. Is this a valid approach?

The syntax(and maybe even the logic) below is probably laughably wrong…but hopefully it illustrates the intent.

Any guidance is gratefully appreciated.
:nerd_face:

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

class GridCell{
// variables & constructor of a simple GridCell w/ x, y, w, h coordinates...

void display(){
// rect(x, y, w, h);
}

//** here is the question: **
//** I know this syntax is not correct **
public ArrayList subdivide (Arraylist GridCell smCell) {

    GridCell topLeft() {
      return new GridCell(smCell.x, smCell.y, w/2, h/2);
    }
    GridCell topRight() {
      return new GridCell(smCell.x+w/2, smCell.y, w/2, h/2);
    }
    GridCell lowerLeft() {
      return new GridCell(smCell.x, smCell.y+h/2, w/2, h/2);
    }
    GridCell lowerRight() {
      return new GridCell(smCell.x+w/2, smCell.y+h/2, w/2, h/2);
    }
    return ArrayList GridCell smCell;
  }
1 Like

Hi @debxyz,

Nice question! :wink:

This is almost right but as you wrote, your syntax is not correct. The idea is to have a method that returns a list of 4 cells by subdividing the current cell.

You can do the following:

import java.util.List;

class GridCell {
  int x, y, w, h;
  
  GridCell(int x, int y, int w, int h) {
    this.x = x;
    this.y = y;
    this.w = w;
    this.h = h;
  }
  
  List<GridCell> subdivide() {
    List<GridCell> cells = new ArrayList();
    
    cells.add(new GridCell(x, y, w / 2, h / 2));
    cells.add(new GridCell(x + w / 2, y, w / 2, h / 2));
    cells.add(new GridCell(x, y + h / 2, w / 2, h / 2));
    cells.add(new GridCell(x + w / 2, y + h / 2, w / 2, h / 2));
    
    return cells;
  }
  
  String toString() {
    return "(" + x + ", " + y + ", " + w + ", " + h + ")";
  }
}

GridCell cell = new GridCell(50, 50, 200, 200);
println(cell.subdivide());

Some notes here:

  • Noticed how I used the List generic class instead of ArrayList. Since ArrayList is a class inheriting from List, it’s always preferable to use the most generic type when returning values or using them. (see: java - Depend on abstractions. Do not depend on concrete classes - Stack Overflow)

  • The toString() method is a special method when implemented on classes that is used when an object is converted to String. For example when printing it with println()

Hope it helps!

2 Likes

Thank you @josephh !!
This does indeed help! :joy:
I wasn’t sure if I could use dot syntax within a class… For some reason thought I could implement only in a main program… Glad to see I wasn’t totally out in left field.

I sure did!!

Thank you again!!
:nerd_face:

1 Like

No idea if it’s even correct, but this is my attempt on furthering @josephh’s example: :crazy_face:

// Dividable GridCell (v1.0.5) (2022/Sep/17)

// https://Discourse.Processing.org/t/
// creating-a-function-that-returns-an-arraylist-of-manipulated-objects/38824/4

import java.util.List;
final List<Cell> cells = new ArrayList<Cell>();

int curSize;

void setup() {
  size(1200, 900);
  clear();
  noLoop();
  strokeWeight(4);

  cells.add(new Cell(50, 50, width - 100, height - 100));
}

void draw() {
  for (final Cell cell : cells) {
    stroke((color) random(#000000));
    fill((color) random(#000000));
    cell.display();
  }

  println(cells);
  println(cells.size(), ENTER);
  surface.setTitle("Frame: " + frameCount + "   -   Cells: " + cells.size());

  subdivideAllCells();
}

void mousePressed() {
  redraw();
}

void subdivideAllCells() {
  for (int i = 0, len = cells.size(); i < len; ++i)  if ((curSize -= 4) < 0)
    for (final Cell c : cells.get(i).subdivide())  cells.add(c);

  curSize = cells.size();
}

class Cell {
  int x, y, w, h;

  Cell(int xx, int yy, int ww, int hh) {
    x = xx;
    y = yy;
    w = ww;
    h = hh;
  }

  Cell display() {
    rect(x, y, w, h);
    return this;
  }

  Cell[] subdivide() {
    final int ww = w >> 1, hh = h >> 1;

    return new Cell[] {
      new Cell(x, y, ww, hh), // top-left
      new Cell(x + ww, y, ww, hh), // top-right
      new Cell(x, y + hh, ww, hh), // bottom=left
      new Cell(x + ww, y + hh, ww, hh) // bottom-right
    };
  }

  String toString() {
    return "(" + x + ", " + y + ", " + w + ", " + h + ")";
  }
}

P.S.: After adding variable curSize as a way to skip Cell objects which had already subdivide(), this ArrayList version now behaves very similar to the other I did relying instead on a LinkedHashSet.

3 Likes

A new approach using a LinkedHashSet container in order to avoid duplicate GridCell objects. :hash:

// Dividable GridCell II (v1.0.4) (2022/Sep/17)

// https://Discourse.Processing.org/t/
// creating-a-function-that-returns-an-arraylist-of-manipulated-objects/38824/5

import java.awt.Rectangle;

import java.util.Set;
import java.util.LinkedHashSet;
final Set<Cell> cells = new LinkedHashSet<Cell>();

import java.util.List;
final List<Cell> newBornCells = new ArrayList<Cell>();

int curSize;

void setup() {
  size(1200, 900);
  clear();
  noLoop();
  strokeWeight(4);

  cells.add(new Cell(50, 50, width - 100, height - 100));
}

void draw() {
  for (final Cell cell : cells)  cell.display();

  println(cells);
  println(cells.size(), ENTER);
  surface.setTitle("Frame: " + frameCount + "   -   Cells: " + cells.size());

  subdivideAllCells();
}

void mousePressed() {
  redraw();
}

void subdivideAllCells() {
  newBornCells.clear();

  for (final Cell cell : cells)  if ((curSize -= 4) < 0)
    for (final Cell c : cell.subdivide())  newBornCells.add(c);

  cells.addAll(newBornCells);
  curSize = cells.size();
}

class Cell extends Rectangle {
  color paint, border;

  Cell(int x, int y, int w, int h) {
    super(x, y, w, h);

    paint = color((color) random(#000000));
    border = color((color) random(#000000));
  }

  Cell display() {
    fill(paint);
    stroke(border);
    rect(x, y, width, height);
    return this;
  }

  Cell[] subdivide() {
    final int ww = width >> 1, hh = height >> 1;

    return new Cell[] {
      new Cell(x, y, ww, hh), // top-left
      new Cell(x + ww, y, ww, hh), // top-right
      new Cell(x, y + hh, ww, hh), // bottom=left
      new Cell(x + ww, y + hh, ww, hh) // bottom-right
    };
  }

  String toString() {
    return "(" + x + ", " + y + ", " + width + ", " + height + ")";
  }
}

In this new version class Cell extends Rectangle in order to inherit its equals() & hashCode() methods so container LinkedHashSet can tell apart 1 from the other based on their dimensions. :bulb:

2 Likes

@GoToLoop This is VERY interesting!!
First time to see bitwise shifting and I appreciate the introduction. :grinning:

Plus the:

is super cool!! I will spend some time studying this.
Thank you!!!
:nerd_face:

2 Likes

continued here Updating ArrayList with additional instances of object

3 Likes