-
Notifications
You must be signed in to change notification settings - Fork 6
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
array_random (weighed) #13
Comments
Hmmm... I think there are a bunch of different functionalities to be had here, and they might be better split up instead of getting into overloads overload. One potential derived function would be So something like function choose_weight_index(_weights) {
var _weights_sum = 0;
for (var i = 0; i < argument_count; i++) {
_weights_sum += argument[i];
}
var _value = random(_weights_sum);
for (var i = 0; i < argument_count; i++) {
if (_value < argument[i])
return i;
else
_value -= argument[i];
}
} Then, for an array based variant, it could be something like Then another derived function could be I don't yet use arrays here, because I don't want to encourage creating new arrays too much, and array literals create a new array every time the code is run. Still, if someone wants to match up the items array with weights, they might use something like Then, for weightless choosing, we would instead apply the function Dragonite mentioned on GMC: function array_random_element(array) {
return array[irandom(array_length(array) - 1)];
} Except I guess I would call it Quite a few design decisions to be had here for sure, but in general I think some extra functions for randomly picking elements (especially picking elements from arrays) would be quite welcome. ^^ |
I suggest I know you said you don't want too many new arrays going around, but I think I'd prefer if a function like choose_weight_index took an array of weights as an argument, instead of a bunch of reals. Passing more than a couple numbers in as arguments would be pretty clumsy, and for many of the proposed use cases I can see myself wanting to pick from dozens or hundreds of options, not just three or four. |
Made a separate issue #26 focusing on the uniform array_get_random/array_pop_random or whatever else we call them. This feature will stay open for discussion and voting about more advanced array randomisation features (mostly the weighed choice). |
There's also this implementation: https://yal.cc/gamemaker-weighted-choose/ |
Description
This is a function I wrote a long time ago for one of my first games, and ended up dropping it on nearly every project I make. It lets you pick an element at random from an array. It can either return the value or the index, and you can specify weights if you do not want a uniform selection. The weights can also be specified with arbitrary numbers, and the function will normalize those weights to add up to 100%. Finally, all arguments are optional, so if you don't specify anything it is equivalent to
choose(0,1)
, if you only specify the array it will select an element at random uniformly (i.e. equal weights) and if you only specify a weights array it will assume the array is a consecutive index array ([0,1, 2, ...]) up to the size of the weights array.Uses
A lot, but it's super useful for dropping random loot, procedural generation of levels, procedural generation of enemy waves depending on level difficulty, etc. Check the write-up I made on random number generation if needed here. Page 3 specifically talks about this.
Examples
Say we have a possible items drop array for a monster loot or treasure chest (I'll specify them a strings for exemplification purposes, probably these would be structs or object references on an actual game):
self.items = ["Coins", "Shield", "Sword", "Gem"];
Then:
var _item = array_random(self.items, [0.4, 0.3, 0.2, 0.1], false);
- Returns a random item from theitems
array (which should have four items). The first item is weighed at 40% chance, the second at 30% and so on.var _item = array_random(self.items, [40, 30, 20, 10], false);
- Exactly the same as before. The function will normalize the weights. This allows to think on loot chances as proportional to one another (for example, something with weight 66 will have double chance than something with weight 33, regardless of what the total sum of weights are).var _item_idx = array_random(self.items, [0.4, 0.3, 0.2, 0.1], true);
- Same as before, but returns the index of the selected item instead.var _item_idx = array_random(self.items);
- Returns a random item from theitems
array, with equal weights. Equivalent toself.items[irandom(array_length(self.items-1))]
.Also:
var _item_idx = array_random(,[0.4, 0.3, 0.2, 0.1])
- Returns a random number from [0, 1, 2, 3], with the specified weights.var _item_idx = array_random()
- Returns a random number from [0, 1], uniformly. Equivalent tochoose(0,1)
.Current code
The current code works good. I'm sure we can clean it up a little and make it a bit more robust to be included in this package, but it's a good start.
The text was updated successfully, but these errors were encountered: