Perhaps another way to shuffle lerped colors in an array?

Watching a D Shiffman tutorial on probability prompted me to try this.

I want to shuffle a colorList array of lerped colors. Search turned up to use IntList and shuffle. But in setup for loop I thought to replace
k++;
with
k = int (random (listColors.length));

This actually seems to work sometimes. But is inconsistent.
I’m curious if anyone knows why this would sometimes indeed shuffle the colors?
Basically what’s going on under the hood.
And is there anything I could adjust for a consistent shuffle following this line of thought? Or do I indeed have to use IntList and shuffle?
///////////////////////

/* ???How to shuffle lerped colors in an array??? */

int num = 6;
int x = 20, y = x;
int w = 360/num, h = 360;

float step = 1.0f/(num-1); // **must use a float number to return a float number**

Cell [] cells = new Cell [num];

color from = color(random(255), random(255), random(255)); 
color to = color(random(255), random(255), random(255));

color [] listColors = new color [num];


void setup() {
  size (400, 400);

  for (int k = 0; k < listColors.length; k++) { // for loop to generate an array color [] listColors of random colors
    listColors[k] = lerpColor (from, to, k*step);

    println(listColors);
  }

  int k = 0;

  for (int i = 0; i < num; i++) {
    cells[i] = new Cell(x+i*w, y, w, h, listColors[k]);
    k = int (random (listColors.length)); // trying to shuffle the listColors 
                                          // after they have been lerped, 
                                          // this sometimes works but more often not 
  }
}

void draw() {

  background (51);

  for (int i = 0; i < num; i++) {
    cells[i].display();
  }
}

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

class Cell {
  float x, y, w, h;
  color clr;

  Cell ( 
    float tempX, float tempY, 
    float tempW, float tempH, color tempClr) {

    x = tempX;
    y = tempY;
    w = tempW;
    h = tempH;
    clr = tempClr;
  }
  void display() {
    
    stroke(255); 
    fill(clr);
    rect(x, y, w, h);
  }
}

Version below uses IntList and shuffle for the solution: This appears to be working so I guess I have this set up correctly?

int num = 9;
int x = 20, y = x;
int w = 360/num, h = 360;

float step = 1.0f/(num-1); // **must use a float number to return a float number**

Cell [] cells = new Cell [num];

color from = color(random(255), random(255), random(255)); 
color to = color(random(255), random(255), random(255));

color [] listColors = new color [num];

IntList inventory = new IntList ();


void setup() {
  size (400, 400);

  for (int k = 0; k < listColors.length; k++) { // for loop to generate an array color [] listColors of random colors
    listColors[k] = lerpColor (from, to, k*step);

    println(listColors);
  }

  inventory.append(listColors);
  inventory.shuffle();
  int[] shuffledInventory = inventory.array();
  println(shuffledInventory);


  int k = 0;

  for (int i = 0; i < num; i++) {
    cells[i] = new Cell(x+i*w, y, w, h, shuffledInventory[k]);
    k++;
  }
}


void draw() {

  background (51);

  for (int i = 0; i < num; i++) {
    cells[i].display();
  }
}
2 Likes

Remark

This line should be before the line where you use k. Now this is only important the first time the loop runs.

To your question

Now using random here is inconsistent because there is no check which colors are already used. So some could be used three times some only 0 times.

You could pick from a list and shorten it to avoid duplicate colors. So when you use a color remove it from the list and shorten the list.

Intlist

But that’s why shuffle an intlist and use its content as an index for the colors array (!) is so elegant. Not fully sure if you understood the idea, can you show us an example?

The index of the Intlist is just incremented by 1 every time; the result of the Intlist at position index is then used for the color list as an index

Chrisir

3 Likes

Hello! Thank you for your clarifications above.

Do you mean show the code I used to implement the shuffle an IntList and use its content idea?
If so, this is how I used it. And have commented next to the relevant lines what I think is going on at each step.
Am I on track?

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

/* !!!!!!These lerped colors have been shuffled using *IntList and shuffle* !!!!!!*/

int num = 9;
int x = 20, y = x;
int w = 360/num, h = 360;

float step = 1.0f/(num-1); // **must use a float number to return a float number**

Cell [] cells = new Cell [num];

color from = color(random(255), random(255), random(255)); 
color to = color(random(255), random(255), random(255));

color [] listColors = new color [num];

IntList inventory = new IntList (); // stores the shuffled list of indexes


void setup() {
  size (400, 400);

  for (int k = 0; k < listColors.length; k++) { // for loop to generate an array color [] listColors of random colors
    listColors[k] = lerpColor (from, to, k*step);

    println(listColors);
  }

  inventory.append(listColors); // targets the index of listColors
  inventory.shuffle(); // randomly shuffles the index of listColors
  int[] shuffledInventory = inventory.array(); 
  // directs the shuffled index 
  // as an array to 
  // IntList inventory = new IntList();
  // in variables section above setup()
  println(shuffledInventory);

  int k = 0;

  for (int i = 0; i < num; i++) {
    cells[i] = new Cell(x+i*w, y, w, h, shuffledInventory[k]);
    k++;
  }
}

void draw() {

  background (51);

  for (int i = 0; i < num; i++) {
    cells[i].display();
  }
}

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

class Cell {
  float x, y, w, h;
  color clr;

  Cell ( 
    float tempX, float tempY, 
    float tempW, float tempH, color tempClr) {

    x = tempX;
    y = tempY;
    w = tempW;
    h = tempH;
    clr = tempClr;
  }
  void display() {
    
    stroke(255); 
    fill(clr);
    rect(x, y, w, h);
  }
}
1 Like

Ah, very elegant… more elegant than my suggestion…

1 Like

Second part of reply to your comment:

Regarding the placement and viability of use:

I moved that line as you suggested but am not sure if it’s what you meant. And then I would still need to pick from list and shorten?

Even if I can’t get this to shuffle as desired I think I can apply this thinking to code where I want an inconsistent or unexpected result. :grinning:

1 Like

Beginner’s luck…
:slightly_smiling_face:

1 Like

Maybe you can say color[] shuffledInventory = inventory.array();

Then the type is color, so it’s more clear

Also a lot of variables that are before setup () could be inside setup() . It’s better to make the scope of variables as small as possible. So with this we reduce the scope from global to local.

1 Like

Following your suggestion,
changed int[] shuffledInventory = inventory.array();
to color[] shuffledInventory = inventory.array();
I like the clarity of that. Previous version felt like a nebulous connection to the listColors.

And moved down:

into setup.

As you can probably see in my code to date, I haven’t really tackled the global vs local variables topic. But know it’s something I need to become more cognizant of going forward. I do appreciate your pointing that out!!
And Thank you again!

1 Like

you can simplify

  • by using a function that returns the colors

  • also by using the inventory directly

  • also very short list of global vars / arrays; most are local!

/* !!!!!!These lerped colors have been shuffled using *IntList and shuffle* !!!!!!*/

// global array 
Cell [] cells = new Cell [9];

void setup() {
  size (400, 400);

  color[] shuffledInventory = getColorListShuffled(); 

  int x = 20, y = x;
  int w = 360/cells.length, h = 360;

  for (int i = 0; i < cells.length; i++) {
    cells[i] = new Cell(x+i*w, y, 
      w, h, 
      shuffledInventory[i]);
  }//for
}//func

void draw() {
  background (51);

  for (int i = 0; i < cells.length; i++) {
    cells[i].display();
  }//for
}//func 

//-----------------------------------------------------------------------------------------
// Tools 

color[] getColorListShuffled() {

  // for the command lerpColor: 
  color from = color(random(255), random(255), random(255)); 
  color to = color(random(255), random(255), random(255));
  float step = 1.0f / (cells.length-1); // **must use a float number to return a float number**

  IntList inventory = new IntList(cells.length); // stores list of colors

  // for loop to generate an IntList of random colors
  for (int k = 0; k < cells.length; k++) {
    inventory.set(k, lerpColor (from, to, k*step));
  }
  inventory.shuffle(); // randomly shuffles the list inventory

  // directs the shuffled inventory 
  // as an array to 
  return inventory.array();
}

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

class Cell {
  float x, y, w, h;
  color clr;

  Cell ( 
    float tempX, float tempY, 
    float tempW, float tempH, color tempClr) {

    x = tempX;
    y = tempY;
    w = tempW;
    h = tempH;
    clr = tempClr;
  }
  void display() {

    stroke(255); 
    fill(clr);
    rect(x, y, w, h);
  }
  //
}//class
//
2 Likes

This is very interesting. Thank you!! I am glad for the guidance in brevity and simplifiction of code. I think I understand. But this weekend will have a chance to comb through line for line to make sure I understand all parts. I may have a follow up question or two…
Deborah

1 Like

It’s nice how a function can return an array of colors

Hello! I went through the code and have commented next to the relevant areas in the added function color [] getColorListShuffled() to note what I think is going on at each step. Any oversights of note?
Thank you!

// Function

color[] getColorListShuffled() {

  // local variables for the command lerpColor: 
  color from = color(random(255), random(255), random(255)); 
  color to = color(random(255), random(255), random(255));
  float step = 1.0f / (cells.length-1); // **must use a float number to return a float number**

  IntList inventory = new IntList(cells.length); // stores list of colors

  // for loop to generate an IntList of random colors
  for (int k = 0; k < cells.length; k++) {
    inventory.set(k, lerpColor (from, to, k*step)); 
    // sets up the list of colors (not shuffled at this point)
  }
  inventory.shuffle(); // this step randomly shuffles the list inventory 

  // directs the shuffled inventory 
  // as an array to 
  return inventory.array();
}
1 Like

Most of the comments are not new at the moment (but have been there in my version).

My additional comments

I would like to comment on

  • the function header: color[] getColorListShuffled() { : Here you can see that the return type of the function is a color array: color[]. Often we see functions that don’t return anything, then the return type is void (empty) like in void draw. Here it is color[] .

  • Accordingly, in the last line we see return inventory.array();, so we return in fact an array of colors. The function must return this type because we promised this in the function header. (The trick here is that color in processing is the same as type int, so we can return an array of type int (when the function header says array of type color[])).

  • One comment reads // for loop to generate an IntList of random colors - well, the for-loop generates lerped colors; they are not random. They get shuffled (randomly) after the for-loop.

  • From an architectural perspective (architecture of a program / Sketch): The use of the function getColorListShuffled() is good because it’s a modularisation of the code. It makes setup() shorter and places a section of it with a precise purpose in a new module (function) which name (getColorListShuffled) reflects that purpose. That’s good architecture when you look at the sketch as a whole. As an exercise you could transform the part of setup() that makes the grid into a new function too. What would be its name?
    The function getColorListShuffled is a module that can be copied and used in other sketches. This is also a good sign: re-usability. And the function has no dependencies (it doesn’t use global variables or so), which is also good and makes it possible to use it in another Sketch.

The last comment

The last comment

  // directs the shuffled inventory 
  // as an array to

should better be:

  // returns (as the result of the function) the shuffled inventory 
  // as an array (of int but treated as an array of color)
3 Likes

I forgot to ask this question in previous post:

inventory.set (k, lerpColor (from, to, k*step));

// ??Confirming that the purpose of .set is to attach the k index to each next iteration of lerped Color??

I see now how my comment on this isn’t clear. At this point in sketch I’m referring to the color from and color to local variables which are randomly generated. (The random shuffle which happens after the for loop.)

I agree, this is clearer!

Scroll down to see revised code with:

  • a function to make a colorList array (not shuffled)
  • a function to make the grid

This returns error message mixing active and static.
The colorList function works, the grid function does not…
Even after reading about static in reference, no clarity.

/* !!!These lerped colors in order created with function called color [] getColorList AND function to create the grid!!!*/

// global array 
Cell [] cells = new Cell [6];

void setup() {
  size (400, 400);

  color[] listColors = getColorList();
  makeOneRowGrid (cells.length);

  //int x = 20, y = x;
  //int w = 360/cells.length, h = 360;

  //for (int i = 0; i < cells.length; i++) {
  //  cells[i] = new Cell(x+i*w, y, 
  //    w, h, 
  //    listColors[i]);
  //}//for
}//func

void draw() {
  background (51);

  for (int i = 0; i < cells.length; i++) {
    cells[i].display();
  }//for
}//func 

//-----------------------------------------------------------------------------------------
// Tools 

color[] getColorList() {

  // for the command lerpColor: 
  color from = color(random(255), random(255), random(255)); 
  color to = color(random(255), random(255), random(255));
  float step = 1.0f / (cells.length-1); // **must use a float number to return a float number**

  IntList inventory = new IntList(cells.length); // stores list of colors

  // for loop to generate an IntList of lerped colors in order
  for (int k = 0; k < cells.length; k++) {
    inventory.set(k, lerpColor (from, to, k*step));
  }
  return inventory.array();
}
makeOneRowGrid() {

  int x = 20, y = x;
  int w = 360/cells.length, h = 360;

  for (int i = 0; i < cells.length; i++) {
    cells[i] = new Cell(x+i*w, y, 
      w, h, 
      listColors[i]);
  }
}

Nope; global field cells is accessed 3 times inside getColorListShuffled() in order to access length. :warning:

For a better portability, the function’s signature gotta ask for that value as its parameter: :bulb:
color[] getColorListShuffled(final int size) {

Obviously, replace all cells.length w/ parameter size. :stuck_out_tongue:

2 Likes

Sorry but I’m not following what you mean. I’m fairly new to coding so am still sorting out things on a pretty basic level…
:slightly_smiling_face:

@Chrisir @GoToLoop
The first sketch is grid (only) made with a function.
The 2nd sketch is with grid function AND getColorList function.
///////////

/* !!!grid made with function !!!*/

// global array 
Cell [] cells = new Cell [6];

void setup() {
  size (400, 400);

  makeOneRowGrid ();
}//func

void draw() {
  background (51);

  for (int i = 0; i < cells.length; i++) {
    cells[i].display();
  }//for
}//func 

//-----------------------------------------------------------------------------------------
// Tools 


void makeOneRowGrid() {

  int x = 20, y = x;
  int w = 360/cells.length, h = 360;

  for (int i = 0; i < cells.length; i++) {
    cells[i] = new Cell(x+i*w, y, 
      w, h);
  }
}

/////////

class Cell {
  float x, y, w, h;
  //color clr;

  Cell ( 
    float tempX, float tempY, 
    float tempW, float tempH) {

    x = tempX;
    y = tempY;
    w = tempW;
    h = tempH;
    //clr = tempClr;
  }
  void display() {

    stroke(255); 
    fill(0);
    rect(x, y, w, h);
  }
  //
}//class

**Version BELOW integrates the getColorList function.

/* !!!grid made with function ADD listColors function !!!*/

// global array 
Cell [] cells = new Cell [6];

void setup() {
  size (400, 400);
  
  makeOneRowGrid ();
  color[] listColors = getColorList();
  
}//func

void draw() {
  background (51);

  for (int i = 0; i < cells.length; i++) {
    cells[i].display();
  }//for
}//func 

//-----------------------------------------------------------------------------------------
// Tools 


void makeOneRowGrid() {
  
  color[] listColors = getColorList();
  
  int x = 20, y = x;
  int w = 360/cells.length, h = 360;

  for (int i = 0; i < cells.length; i++) {
    cells[i] = new Cell(x+i*w, y, 
      w, h, listColors[i]);
  }
}
color[] getColorList() {

  // for the command lerpColor: 
  color from = color(random(255), random(255), random(255)); 
  color to = color(random(255), random(255), random(255));
  float step = 1.0f / (cells.length-1); // **must use a float number to return a float number**

  IntList inventory = new IntList(cells.length); // stores list of colors

  // for loop to generate an IntList of lerped colors in order
  for (int k = 0; k < cells.length; k++) {
    inventory.set(k, lerpColor (from, to, k*step));
  }
  // directs the shuffled inventory 
  // as an array to 
  return inventory.array();
}

CLASS ////////////////////

class Cell {
  float x, y, w, h;
  color clr;

  Cell ( 
    float tempX, float tempY, 
    float tempW, float tempH, color tempClr) {

    x = tempX;
    y = tempY;
    w = tempW;
    h = tempH;
    clr = tempClr;
  }
  void display() {

    stroke(255); 
    fill(clr);
    rect(x, y, w, h);
  }
  //
}//class

Well done!

you could also make makeOneRowGrid() that it returns a grid :slight_smile:

Cell [] makeOneRowGrid() { 
1 Like

:slight_smile: :grinning: :joy:

Err… set: a new lerped color is appended to the list at position k.