math/rand: add choice_bit_set

This commit is contained in:
Laytan Laats
2024-10-26 13:50:28 +02:00
parent 831558a7c2
commit 10c2f8dbeb
2 changed files with 50 additions and 13 deletions
+49
View File
@@ -687,3 +687,52 @@ choice_enum :: proc($T: typeid, gen := context.random_generator) -> T where intr
return T(choice(values))
}
}
/*
Returns a random *set* bit from the provided `bit_set`.
Inputs:
- set: The `bit_set` to choose a random set bit from
Returns:
- res: The randomly selected bit, or the zero value if `not_empty` is `false`
- not_empty: Whether the bit_set was not empty and thus `res` is actually a random set bit
Example:
import "core:math/rand"
import "core:fmt"
choice_bit_set_example :: proc() {
Flags :: enum {
A,
B = 10,
C,
}
fmt.println(rand.choice_bit_set(bit_set[Flags]{}))
fmt.println(rand.choice_bit_set(bit_set[Flags]{.B}))
fmt.println(rand.choice_bit_set(bit_set[Flags]{.B, .C}))
fmt.println(rand.choice_bit_set(bit_set[0..<15]{5, 1, 4}))
}
Possible Output:
A false
B true
C true
5 true
*/
@(require_results)
choice_bit_set :: proc(set: $T/bit_set[$E], gen := context.random_generator) -> (res: E, not_empty: bool) {
total_set := card(set)
if total_set == 0 {
return {}, false
}
core_set := transmute(intrinsics.type_bit_set_underlying_type(T))set
for target := int_max(total_set, gen); target > 0; target -= 1 {
core_set &= core_set - 1
}
return E(intrinsics.count_trailing_zeros(core_set)), true
}