Setting a weight/probability on a list of objects ina datalist, then choosing an object at random b

As listed in title; thats what im trying to achieve; currently it half works but the getrandomchunk spits out values above the number of chunkprefabs currently; that number gets higher and higher as game clones and reuses chunks

Im not sure how to fix that part;

Also as seen at top e "despawn distance etc would like to be able to set probability there next to where the chunk prefab elements are set in unity inspector; anyone know how?

https://hatebin.com/vqckhcqldg

I can’t quite tell what exactly you need but if you mean a weighted random pick, you need a list that contains both the probability and the payload.

Then you traverse that list starting from a random value between 0 and 1, and you subtract each item’s probability from this value until that would make it below zero. At this point you select this item’s payload and that’s your result.

Depending on your actual distribution and number of items, you might want to pre-sort the list, where the items descend based on probability. This vastly improves the number of iterations needed.

To make such a list, you can introduce a struct

public struct WeightedItem<T> {
 
  public float Weight { get; private set; }
  public T Payload { get; private set; }

  public WeightedItem(float weight, T payload) {
    Weight = weight;
    Payload = payload;
  }

}
List<WeightedItem<GameObject>> list = new();

The algorithm looks like this (ripped out of my libraries)

public bool TryChoose(out int index) {
  index = -1;

  if(list is null || list.Count == 0)
    return false;

  var value = Random.value;

  if(list.Count == 1 || value == 0f) {
    index = 0;

  } else if(value == 1f) {
    index = list.Count - 1;

  } else {
    int i = 0;

    while(true) {
      var p = probabilityOf(list[i].Weight);
      if(value < p) break;
      value -= p;
      i++;
    }

    index = i;
  }

  return true;
}

// a convenience that simply gets you the payload with no intermediate steps
public T Choose() {
  if(!TryChoose(out var index)) throw new KeyNotFoundException();
  return list[index].payload;
}

The main trick here is that probabilityOf function, which needs to cache the total sum of weights to be able not to waste time computing this sum over and over again.

It is essentially computing a probability from the supplied weight in such a way that it compares it to the total weight. Practically

float probabilityOf(float weight) {
  var sum = 0f;
  for(int i = 0; i < list.Count; i++) sum += list[i].Weight;
  return weight / sum;
}

So ideally, when you make your list, you have also saved this sum.

Regarding sorting, I made my sorting work like bubble sort, because I maintain the sorted order on adding, but you can do a quick sort instead (which is significantly better, especially with larger item counts).

To do this, you first make a comparator like this (this code assumes T was already defined, in my code the whole thing is generic, but in this example we used GameObject)

static int descending_weight(WeightedItem<T> a, WeightedItem<T> b)
      => b.weight.CompareTo(a.weight);

Then, before you actually try to select anything, you do

list.Sort(descending_weight);

What do you mean by payload, ID?

This is the list with the probability;

 public class ChunkPrefabData
    {
        public GameObject originalChunkPrefab;
        public float additionalVariable;

        public ChunkPrefabData(GameObject chunkPrefab, float variable)
        {
            originalChunkPrefab = chunkPrefab;
            additionalVariable = variable;
        }

      
    }

And where i set probability

 chunkPrefabDataList.Add(new ChunkPrefabData(chunkPrefab[0], 0.3f));
        chunkPrefabDataList.Add(new ChunkPrefabData(chunkPrefab[1], 0.3f));
        chunkPrefabDataList.Add(new ChunkPrefabData(chunkPrefab[2], 0.1f));
        chunkPrefabDataList.Add(new ChunkPrefabData(chunkPrefab[3], 0.3f));

Isnt my script already doing that for probability? almost; as it has errors right now it returns number over the list amount

Anyone can help with applying to the code I have already?