comfy_core/
random.rs

1use crate::*;
2
3use std::sync::atomic::{AtomicU64, Ordering};
4
5// Most code in this module comes from macroquad's rand module, with some additions/tweaks.
6
7const DEFAULT_INC: u64 = 1442695040888963407;
8const MULTIPLIER: u64 = 6364136223846793005;
9
10static STATE: AtomicU64 = AtomicU64::new(0);
11
12/// Seeds the pseudo-random number generator used by rand()
13/// with the value seed.
14pub fn srand(seed: u64) {
15    STATE.store(0, Ordering::Relaxed);
16    rand();
17    let oldstate = STATE.load(Ordering::Relaxed);
18    STATE.store(oldstate.wrapping_add(seed), Ordering::Relaxed);
19    rand();
20}
21
22/// returns a pseudo-random number in the range of 0 to u32::MAX.
23pub fn rand() -> u32 {
24    let oldstate: u64 = STATE.load(Ordering::Relaxed);
25    STATE.store(
26        oldstate.wrapping_mul(MULTIPLIER).wrapping_add(DEFAULT_INC),
27        Ordering::Relaxed,
28    );
29    let xorshifted: u32 = (((oldstate >> 18) ^ oldstate) >> 27) as u32;
30    let rot: u32 = (oldstate >> 59) as u32;
31    xorshifted.rotate_right(rot)
32}
33
34pub trait RandomRange {
35    fn gen_range(low: Self, high: Self) -> Self;
36}
37
38macro_rules! impl_random_range{
39    ($($ty:ty),*,)=>{
40      $(
41        impl RandomRange for $ty{
42          #[inline]
43          fn gen_range(low: Self, high: Self) -> Self {
44            let r = rand() as f64 / (u32::MAX as f64 + 1.0);
45            let r = low as f64 + (high as f64 - low as f64) * r;
46            r as Self
47          }
48        }
49      )*
50    }
51  }
52impl_random_range!(
53    f32, f64, u8, u16, u32, u64, usize, i8, i16, i32, i64, isize,
54);
55
56pub fn gen_range<T>(low: T, high: T) -> T
57where T: RandomRange {
58    T::gen_range(low, high)
59}
60
61pub struct VecChooseIter<'a, T> {
62    source: &'a Vec<T>,
63    indices: std::vec::IntoIter<usize>,
64}
65
66impl<'a, T> Iterator for VecChooseIter<'a, T> {
67    type Item = &'a T;
68
69    fn next(&mut self) -> Option<&'a T> {
70        self.indices.next().map(|ix| &self.source[ix])
71    }
72}
73
74pub trait ChooseRandom<T> {
75    fn shuffle(&mut self);
76    fn choose(&self) -> Option<&T>;
77    fn choose_mut(&mut self) -> Option<&mut T>;
78    fn choose_multiple(&self, _amount: usize) -> VecChooseIter<T>;
79}
80
81impl<T> ChooseRandom<T> for Vec<T> {
82    fn shuffle(&mut self) {
83        let mut fy = FisherYates::default();
84
85        fy.shuffle(self);
86    }
87
88    fn choose(&self) -> Option<&T> {
89        let ix = gen_range(0, self.len());
90        self.get(ix)
91    }
92
93    fn choose_mut(&mut self) -> Option<&mut T> {
94        let ix = gen_range(0, self.len());
95        self.get_mut(ix)
96    }
97
98    fn choose_multiple(&self, amount: usize) -> VecChooseIter<T> {
99        let mut indices =
100            (0..self.len()).enumerate().map(|(i, _)| i).collect::<Vec<usize>>();
101
102        indices.shuffle();
103        indices.resize(amount, 0);
104
105        VecChooseIter { source: self, indices: indices.into_iter() }
106    }
107}
108
109/// Implementation of Fisher-Yates algorithm.
110/// This is modified version of <https://github.com/adambudziak/shuffle/blob/master/src/fy.rs>
111#[derive(Debug, Default)]
112pub struct FisherYates {
113    buffer: [u8; std::mem::size_of::<usize>()],
114}
115
116impl FisherYates {
117    pub fn shuffle<T>(&mut self, data: &mut [T]) {
118        for i in 1..data.len() {
119            let j = self.gen_range(i);
120            data.swap(i, j);
121        }
122    }
123}
124
125impl FisherYates {
126    fn gen_range(&mut self, top: usize) -> usize {
127        const USIZE_BYTES: usize = std::mem::size_of::<usize>();
128        let bit_width = USIZE_BYTES * 8 - top.leading_zeros() as usize;
129        let byte_count = (bit_width - 1) / 8 + 1;
130        loop {
131            for i in 0..byte_count {
132                self.buffer[i] = gen_range(0, 255);
133            }
134            let result = usize::from_le_bytes(self.buffer);
135            let result = result & ((1 << bit_width) - 1);
136            if result < top {
137                break result;
138            }
139        }
140    }
141}
142
143// pub fn random(min: f32, max: f32) -> f32 {
144//     // rand::random::<f32>().abs() * (max - min) + min
145//     gen_range(min, max)
146// }
147
148pub fn random_i32(min: i32, max: i32) -> i32 {
149    // rand::thread_rng().gen_range(min..max)
150    gen_range(min, max)
151}
152
153pub fn random_usize(min: usize, max: usize) -> usize {
154    // rand::thread_rng().gen_range(min..max)
155    gen_range(min, max)
156}
157
158pub fn flip_coin(p: f32) -> bool {
159    toss_coin(p)
160}
161
162pub fn coin_toss(p: f32) -> bool {
163    toss_coin(p)
164}
165
166pub fn toss_coin(p: f32) -> bool {
167    gen_range(0.0, 1.0) < p
168}
169
170pub fn random_angle() -> f32 {
171    gen_range(0.0, 2.0 * PI)
172}
173
174pub fn random_range(min: f32, max: f32) -> f32 {
175    gen_range(min, max)
176}
177
178pub fn random_dir() -> Vec2 {
179    let angle = gen_range(0.0, std::f32::consts::PI * 2.0);
180
181    Vec2::new(angle.cos(), angle.sin())
182}
183
184pub fn random_vec(min: f32, max: f32) -> Vec2 {
185    random_dir() * gen_range(min, max)
186}
187
188pub fn random_offset(radius: f32) -> Vec2 {
189    random_dir() * gen_range(0.0, radius)
190}
191
192pub fn random_circle(radius: f32) -> Vec2 {
193    random_offset(radius)
194}
195
196pub fn random_box(center: Vec2, size: Vec2) -> Vec2 {
197    center +
198        vec2(
199            gen_range(-size.x, size.x) / 2.0,
200            gen_range(-size.y, size.y) / 2.0,
201        )
202}
203
204pub fn random_around(position: Vec2, min: f32, max: f32) -> Vec2 {
205    position + random_vec(min, max)
206}
207
208pub fn random() -> f32 {
209    gen_range(0.0, 1.0)
210}
211
212#[test]
213fn crash_poop_gen_range() {
214    let things = vec![1, 2, 3];
215
216    let mut i: usize = 0;
217
218    for _ in 0..1000000000usize {
219        i += 1;
220        if things.choose().is_none() {
221            panic!("EXITING AFTER {} ITERATIONS", i);
222        }
223    }
224}