How can I make some random things less common then others?

hey! So I’ve been working on a random profile picture generator as an exercise trying to get better with processing.

the character consists of 7 random attribute, and I want some attributes to be more common then others.

here’s how it works

//Setup Crown
float crownGenerator = random(1,7);
int newcrownGenerator = int(crownGenerator); //convert float to int

//Random Crown Generator
if(newcrownGenerator == 1) {
crown = loadImage(“1 black crown.PNG”);
}

  else if (newcrownGenerator == 2) {
  crown = loadImage("2 white crown.PNG"); 
 }
 
 else if (newcrownGenerator == 3) {
  crown = loadImage("3 chromatic black crown.PNG"); 
 }
 
      else if (newcrownGenerator == 4) {
  crown = loadImage("4 Shimmering ice.PNG"); 
 }
 
 else if (newcrownGenerator == 5) {
  crown = loadImage("5 clown mask.PNG"); 
 }
 
 else if (newcrownGenerator == 6) {
  crown = loadImage("5 clown mask.PNG"); 
 }
 
 else crown = loadImage("6 gold monarch.PNG");

So you can see I have a random number generator from 1 to 7, my first idea was to make it 1 to 70, then have some more common attributes be selected based on it landing on more numbers. like I wanted to do:

//Random Crown Generator
if(newcrownGenerator == (1-15)) {
crown = loadImage(“1 black crown.PNG”);
}

and that way any number landing on 1-15 would display the black crown, but clearly this syntax doesn’t work. I’ve tried a few different ways to do this and nothing works, I think I might have to do 2 conditions of the if statement something like (crown > 0) && (crown < 9) but I can’t seem to get the syntax worked out, if anyone can help me please let me know! also let me know if you guys need to see more of the code to make sense of it! thankyou so much!

just do :

if(newcrownGenerator>0 && newcrownGenerator<9){
crown = loadImage(“1 black crown.PNG”);
}

a very basic way is to have an array of indices in which the more an index appears the more likely it is to be chosen

void setup() {
 String[] items = new String[] { "a", "b", "c", "d", "e", "f" };
  
 int[] weights = new int[] { 0, 0, 1, 1, 1, 2, 3, 3, 3, 3, 3, 4, 4, 5, 5, 5, 5, 5, 5, 5, 6, 6 };
 
 int itemsToSelect = 4;
 for(int i = 0; i < itemsToSelect; i++) {
   //i am sure you can just pass the array into random and it will return one of its values - maybe i am misremembering
   int itemIndex = weights[(int)random(weights.length)];
   println("item " + i + ": " + items[itemIndex]);
 }
}

a cooler version i will leave for you to implement if the above isn’t enough. it’s in pseudo code but fairly easy to understand and a cool method. you can check it out here

edit: i remember where i first learnt that basic version. you can find it here it’s great when you don’t have so many items or if you mix it with a randomised weight generator function

i am sure there may be more elegant solutions but these are simple to grok and implement quickly

Based on the discussion so far I assume that you have a number of options which you want to pick randomly but with each option having a different probability of being chosen.

This sketch demonstrates one way of doing this but there are several other ways of doing the same thing, it really depends on exactly what you want to achieve.

// Assume we want to randomly pick from 4 different types e.g. A B C or D
// But assume we want 25% As, 50% Bs, 10% Cs and 15% D
int[] pc; // array to hold percentages

void setup() {
  // Start with an array showing these percentages
  pc = new int[] { 25, 50, 10, 15 };
  //   nbrTypes = pc.length; // 4
  // Now create cumulative percentiles
  for (int i = 1; i < pc.length; i++)
    pc[i] += pc[i-1]; 
  printArray(pc);
  // Remember the total for random selection
  int nbr = pc[pc.length-1];
  // Now select 100 random numbers
  for (int r = 0; r < 100; r++) {
    int rnd = (int) random(0, nbr);
    String s;
    if (rnd > pc[2])
      s = "D";
    else if (rnd > pc[1])
      s = "C";
    else if (rnd > pc[0])
      s = "B";
    else
      s = "A";
    if (r == 50) println(); // split ouptput over two lines
    print(s);
  }
  println();// move to new line after all output

  exit(); // Not using window so close it
}

Typical output

BCBBBBDDABDABBAAACBCABBDACBABBACDDBDBDDABBBACBBBBD
DABBABDABBBBBBAABBABBBBBDBBBBBCBABABBCBDDDBBDAABBA

1 Like

Based on @hotfooted’s answer, you can avoid to repeat the indices to change the weight.

Instead, just have a array the same size of the one you want to pick things from and indicate the weight of each element there.

Then, you pick a random number between 0 and that total weight.

All you need to do after is to loop through the weights. if the random number is lower than the weight, then you pick the element. Otherwise, you substract the current weight to the random number and keep looping until your random number is lower than the weight.

EDIT:
With an example as well

// We want to pick values from the values array based on weights given in the weights array.
// In our exemple, it means that B and C will appears twice as much as A where D will appears 4 times as much as A and twice as much as B and C
void setup() {
  int[] weights;       // Weights of each element
  String[] values;     // Elements to pick randomly
  int totalWeight = 0; // Sum of all the weights of the weights array
  String result = "";  // String to showcase results

  values = new String[] {"A", "B", "C", "D"};
  weights = new int[] {1, 2, 2, 4};
  
  // Compute the total weights
  for (int i = 0; i < weights.length; i++) {
    totalWeight += weights[i];
  }
  
  // Pick a random element 100 times
  for (int i = 0; i < 100; i++) {
    
    // Pick a random number between 0 and the total weight number
    // For each element of the weight array, check if the random number is lower than the value
    // If that's the case, we can exit the loop => we have found the element to pick
    // If not, we substract the weight from the random number and compare that value with the next weight
    // And so on and so on
    int r = (int)random(totalWeight);
    int k;    
    for (k = 0; k < weights.length; k++) {
      if (r < weights[k]) {
        break;
      }
      r -= weights[k];
    }
    result += values[k];
  }
  
  println(result);
}

And the result:

CBBCDBCBBDAADDBCBCBBABDDBDADDBDABDDDDCDDDADCCBADDDBACCDABBDDACDDADCADDDDDACDCCCDCAAACCABCDDDDDCBDBBC
1 Like