1
votes

I have a script that I'm using to select a random item from an array with a weighted chance and, for the most part, it works well. The problem comes when the index gets to the last item in the array.

Here's my code:

string[] grades = { "D", "C", "B", "A", "S" };
int[] weights = { 80, 140, 170, 180, 181 };
// 80, 60, 30, 10, 1

int iterations = 100;

void Update() {
    if (iterations > 0) {
        string genGrade = grades[WeightedChance(weights)];
        print("Chance: " + chance + ", Grade: " + genGrade);
        iterations--;
    }
}

int WeightedChance(int[] weights) {
    float weightSum = weights[weights.Length - 1];

    float chance = Random.Range(0f, weightSum);

    for (int i = 0; i < weights.Length - 1; i++) {
        if (chance <= weights[i]) {
            return i;
        }
    }
    return -1;
}

From what I understand when i gets to the last item in the array it seems to skip over it and then run return -1, giving me "IndexOutOfRangeException". What I can't seem to understand is why exactly that's happening. chance generates a number between 0f and weightSum (or 181 in this case), both being inclusive as they're floats. Afterwards I check for each element in weights and see if the number generated by chance is less than or equal to each one. If all of that runs like I'm thinking it should, it should always be able to choose one of the weights, but something goes wrong when i reaches 4 (atleast that's what I'm guessing). I am new to all of this, so I apologize if I'm missing anything important or my code isn't correctly formatted.

4
Have you tried a breakpoint to follow the changes? In the left side of VS, you can place a red dot. Then click Attach to Unity then run the game. It will stop at the red dot, you can then use the control at the top to Jump into/skip and so on. Hovering over a variable will show its content. - Everts
@Everts I usually just use a bunch a print functions to see what's happening but that seems like a much better alternative so thanks for that, that's very helpful. - Genzou

4 Answers

1
votes

The error comes on this part:

 string genGrade = grades[WeightedChance(weights)];

When WeightedChance returns -1, you get grades[-1], which of course is out of range

1
votes

This line is not correct:

for (int i = 0; i < weights.Length - 1; i++) {

You should go till "weights.Length" not "weights.Length - 1".

You are not reaching last item.

0
votes

Try like this

void Update() {
if (iterations > 0) {
  int x= WeightedChance(weights);
   if(x>=0){
    string genGrade = grades[x];
    print("Chance: " + chance + ", Grade: " + genGrade);
    iterations--;
   }
}
}
0
votes

I think you have misunderstood the < operator in your for loop, this means that the value is "strictly less" than what you are comparing meaning that equality does not satisfy this condition.

In your case you are looping to weights.Length -1 which is, as you say, 4, but the condition in the for loop states that it should run until i is "strictly less" than 4 so i will reach a maximum value of 3, not checking for the last element 181.

To solve this issue you have 2 solutions:

  • Change the operator to <= (less than or equals) which would cover the case of i=4
  • Run the for loop up to Weight.Length without subtractions (as already suggested in other answers)