godotengine / godot-proposals

Godot Improvement Proposals (GIPs)
MIT License
1.07k stars 69 forks source link

Add randb() function to return a random boolean #8721

Open WiseNoodle opened 6 months ago

WiseNoodle commented 6 months ago

Describe the project you are working on

Add a function called "randb()" that you can call anywhere to return a random boolean. This would go hand-in-hand with randi() and randf().

Describe the problem or limitation you are having in your project

I do not have a quick and easy single tab-press way to return a random boolean.

Describe the feature / enhancement and how it helps to overcome the problem or limitation

This simply returns a random boolean the same way randi() returns a random integer.

Describe how your proposal will work, with code, pseudo-code, mock-ups, and/or diagrams

Usage

var random_bool = randb()

Implementation

I have already built and compiled a forked branch using the same implementation as randi() or randf() like so:

_FORCE_INLINE_ bool randb() { return (rand() & 0x1) == 0x1; }

If this enhancement will not be used often, can it be worked around with a few lines of script?

It can be worked around using randf()>0.5 but can be annoying when used often.

Is there a reason why this should be core and not an add-on in the asset library?

This could be made into an add-on to keep the engine lean however, I feel it should be a core component since it completes the set of tools for random generation and as many have said before; one-liner addons are counterproductive.

SplatTab commented 6 months ago

It may seem useless because you could just do randf()> 0.5 or randi_range(0, 1), but I can think of a lot of cases where you just want a random 1(true) or 0(false) value and this is a nice shorthand way of getting just that and if there's already pick_random on arrays which just gets a random value the size of the array so why not have this..

Here's a couple use case examples:

LazyGamesDev commented 6 months ago

I am working on a project where you have a coin flip. Although this can be done with randi_range(), like @SplatTab said. Having this feature would reduce on code, making things simpler and cleaner.

if randb(): Heads() else: Tails()

DuGringo commented 6 months ago

It's just a nice shortcut that helps readability, specially if you are new. I like it.

LimestaX commented 6 months ago

I think this goes hand in hand with inline IF statements and lambda functions maybe we add a bias too?

ranb( float bias = .5 ), where bias can just say the % (0-1 inclusive) of the time we return true it would be insanely useful for state machines and random behavior

func chop_tree(luck) :
    if randb(luck):
        drop_wood(1)
    else:
        drop_wood(2)

It adds some functionality with testing variables, I think this is a very useful tool, could also be used in a plethora of games and utilities.

LimestaX commented 6 months ago

It may seem useless because you could just do randf()> 0.5 or randi_range(0, 1),

if that's the current format, and not to mention just checking if statements against 0,1 , it's much cleaner and faster to have a boolean check built into the random function, and with the ability to add bias I think it cleans things up even further

WiseNoodle commented 6 months ago

I think this goes hand in hand with inline IF statements and lambda functions maybe we add a bias too?

ranb( float bias = .5 ), where bias can just say the % (0-1 inclusive) of the time we return true it would be insanely useful for state machines and random behavior

func chop_tree(luck) :
    if randb(luck):
        drop_wood(1)
    else:
        drop_wood(2)

It adds some functionality with testing variables, I think this is a very useful tool, could also be used in a plethora of games and utilities.

I like the idea of adding a chance argument to it. Adding a separate function for "rand_chance()" would be redundant since it still returns a bool just at a configurable percentage. I can look into adding that. It all depends on what the people want.

SplatTab commented 6 months ago

I think this goes hand in hand with inline IF statements and lambda functions maybe we add a bias too? ranb( float bias = .5 ), where bias can just say the % (0-1 inclusive) of the time we return true it would be insanely useful for state machines and random behavior

func chop_tree(luck) :
    if randb(luck):
        drop_wood(1)
    else:
        drop_wood(2)

It adds some functionality with testing variables, I think this is a very useful tool, could also be used in a plethora of games and utilities.

I like the idea of adding a chance argument to it. Adding a separate function for "rand_chance()" would be redundant since it still returns a bool just at a configurable percentage. I can look into adding that. It all depends on what the people want.

I see no downside since the bias would be optional

for example:

randb(0.3) and randf() > 0.3

It would be a shorter way to write the code and you could still do just: randb() for a random 50% Boolean true or false

Chaosus commented 6 months ago

IMO, the following function which returns boolean with probability looks more useful for a game developer:

func chance(probability : int) -> bool:
    return true if (randi() % 100) < probability else false

func _ready():
    for i in range(100):
        chance(75) # Generates true with a 75% probability
SplatTab commented 6 months ago

IMO, the following function which returns boolean with probability looks more useful for a game developer:

func chance(probability : int) -> bool:
  return true if (randi() % 100) < probability else false

func _ready():
  for i in range(100):
      chance(75) # Generates true with a 75% probability

Well this is the same thing as with a float you could do randb(.75) for a 75% chance the default probability or bias should be .5 however

WiseNoodle commented 6 months ago

I believe it would be best to move it into a separate function such as randb_chance() since this is purely for a 50/50 chance. You can achieve the same effect with the bias using randf() and a few operators.

AThousandShips commented 6 months ago

I think having a dedicated 50/50 method doesn't make sense on its own, it's so extremely trivial to work around and just write your own method, like so:

func randb() -> bool:
    return randi() & 0x01

That's it

However providing a Bernoulli distribution function, i.e. a "x% chance of true" is much more complicated to implement correctly and handling bias correctly so it should be implemented instead IMO, the coin toss code is so trivial it's not worth to add in core IMO

WiseNoodle commented 6 months ago

I'd be happy to implement it and make a new branch/pr! Thank you all for the input; it's incredibly valuable feedback; I don't want to create something no one wants to use.

LimestaX commented 6 months ago

I think whatever is the most optimized, I'm not sure if it would be faster to have a separate overloading function, your current one is very efficient as is. I think internally running integers might lead to some bias one way or the other, and it doesn't lend itself to very odd percentages, I think a float input would be ideal and keeping it a float internally will just be cohesive.

On Tue, Dec 26, 2023, 6:50 PM WiseNoodle @.***> wrote:

I'd be happy to implement it and make a new branch/pr! Thank you all for the input; it's incredibly valuable feedback; I don't want to create something no one wants to use.

— Reply to this email directly, view it on GitHub https://github.com/godotengine/godot-proposals/issues/8721#issuecomment-1869826714, or unsubscribe https://github.com/notifications/unsubscribe-auth/AKYWUIQVYX2WWZQM5SXEA7DYLNPDRAVCNFSM6AAAAABBBIPRSWVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTQNRZHAZDMNZRGQ . You are receiving this because you commented.Message ID: @.***>