-
Notifications
You must be signed in to change notification settings - Fork 16
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
adding Random.choices() #178
Conversation
core/math/random.cpp
Outdated
@@ -126,6 +227,7 @@ void Random::_bind_methods() { | |||
|
|||
ClassDB::bind_method(D_METHOD("range", "from", "to"), &Random::range); | |||
ClassDB::bind_method(D_METHOD("choice", "from"), &Random::choice); | |||
ClassDB::bind_method(D_METHOD("choices", "from", "count", "weights"), &Random::choices, DEFVAL(1), DEFVAL(Variant()), DEFVAL(false)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing bind argument:
ClassDB::bind_method(D_METHOD("choices", "from", "count", "weights"), &Random::choices, DEFVAL(1), DEFVAL(Variant()), DEFVAL(false)); | |
ClassDB::bind_method(D_METHOD("choices", "from", "count", "weights", "cumulative"), &Random::choices, DEFVAL(1), DEFVAL(Variant()), DEFVAL(false)); |
core/math/random.h
Outdated
@@ -25,6 +25,7 @@ class Random : public RandomNumberGenerator { | |||
|
|||
Variant range(const Variant &p_from, const Variant &p_to); | |||
Variant choice(const Variant &p_sequence); | |||
Variant choices(const Variant &p_sequence, int count, const Array &p_weights, bool is_cumulative); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Prepend p_
for parameters (Godot naming convention).
Also, given that the code could be used in C++ as well, it's better to provide default arguments in the method signature as well.
The following suggestion applies both ideas:
Variant choices(const Variant &p_sequence, int count, const Array &p_weights, bool is_cumulative); | |
Variant choices(const Variant &p_sequence, int p_count = 1, const Array &p_weights = Variant(), bool p_cumulative = false); |
Don't forget to do the same to cpp
file.
core/math/random.cpp
Outdated
Array cumulative_weights; | ||
Array weights; | ||
Array indices; | ||
Array weighted_choices; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If weights/indices can only be integers, I think you could use PoolIntArray
instead (both here and as input). If you pass Array
, Godot will do the conversion to PoolIntArray
automatically. I think this will actually simplify validation down the road.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How do I convert an Array
to PoolIntArray
? I would need it for getting dict.values()
.
It says no suitable user-defined conversion from 'Array' to 'PoolIntArray' exists
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm yeah, looks like Godot doesn't provide such conversion. I'd just initialize in a loop.
Variant Random::choices(const Variant &p_from, int count, const PoolIntArray &p_weights, bool is_cumulative) {
int sum = 0;
PoolIntArray cumulative_weights;
PoolIntArray weights;
PoolIntArray indices;
PoolIntArray weighted_choices;
if((p_from.get_type() == Variant::DICTIONARY) && p_weights.empty()){
Dictionary dict = p_from;
Array w = dict.values();
for (int i = 0; i < w.size(); ++i) {
weights.push_back(w[i]);
}
} else {
weights = p_weights;
}
There will be other missing functions like back()
, you'd have to access the last element manually.
core/math/random.cpp
Outdated
weighted_choices.push_back(str.substr((randi() % str.size()), 1)); | ||
} | ||
} else { | ||
ERR_FAIL_COND_V_MSG(str.size() != weights.size(), Variant(), "Size of weights does not match."); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that size()
and length()
are different in String
. size()
includes null character, while length()
doesn't. Not sure whether this logic matters here though. But if it does, you'd likely need to use str.length()
instead.
core/math/random.cpp
Outdated
@@ -95,6 +95,112 @@ Variant Random::choice(const Variant &p_from) { | |||
return Variant(); | |||
} | |||
|
|||
Variant Random::choices(const Variant &p_from, int p_count, const PoolIntArray &p_weights, bool p_is_cumulative) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Variant Random::choices(const Variant &p_from, int p_count, const PoolIntArray &p_weights, bool p_is_cumulative) { | |
Array Random::choices(const Variant &p_from, int p_count, const PoolIntArray &p_weights, bool p_is_cumulative) { |
core/math/random.cpp
Outdated
if(int(weights[i]) < 0) { | ||
ERR_FAIL_V_MSG(Array(), "Weights must be positive integers."); | ||
} else { | ||
sum += (int)weights[i]; | ||
cumulative_weights.push_back(sum); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think casting is no longer necessary.
if(int(weights[i]) < 0) { | |
ERR_FAIL_V_MSG(Array(), "Weights must be positive integers."); | |
} else { | |
sum += (int)weights[i]; | |
cumulative_weights.push_back(sum); | |
} | |
if(weights[i] < 0) { | |
ERR_FAIL_V_MSG(Array(), "Weights must be positive integers."); | |
} else { | |
sum += weights[i]; | |
cumulative_weights.push_back(sum); | |
} |
core/math/random.cpp
Outdated
while (left < right) | ||
{ | ||
int mid = (left + right) / 2; | ||
if(int(cumulative_weights[mid]) < random_number) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as above.
if(int(cumulative_weights[mid]) < random_number) { | |
if(cumulative_weights[mid] < random_number) { |
Is returning an |
Well, I think Therefore, having the method return an |
Thanks and congrats for your first contribution! |
Thanks, I learnt a lot. |
Nice! I like the cummulative bool approach. I'm still here just migrated all my data to a brand new account (with the same name) :) |
One of the features approved in #7