rosu_pp/util/random/
csharp.rs1use crate::util::hint::unlikely;
2
3pub struct Random {
5 prng: CompatPrng,
6}
7
8impl Random {
9 pub fn new(seed: i32) -> Self {
11 Self {
12 prng: CompatPrng::initialize(seed),
14 }
15 }
16
17 pub const fn next(&mut self) -> i32 {
19 self.prng.internal_sample()
20 }
21
22 pub fn next_max(&mut self, max: i32) -> i32 {
24 (self.prng.sample() * f64::from(max)) as i32
25 }
26}
27
28struct CompatPrng {
30 seed_array: [i32; 56],
31 inext: i32,
32 inextp: i32,
33}
34
35impl CompatPrng {
36 fn initialize(seed: i32) -> Self {
37 let mut seed_array = [0; 56];
38
39 let subtraction = if unlikely(seed == i32::MIN) {
40 i32::MAX
41 } else {
42 i32::abs(seed)
43 };
44
45 let mut mj = 161_803_398 - subtraction; seed_array[55] = mj;
47 let mut mk = 1;
48 let mut ii = 0;
49
50 for _ in 1..55 {
51 ii += 21;
53
54 if ii >= 55 {
55 ii -= 55;
56 }
57
58 seed_array[ii] = mk;
59 mk = mj - mk;
60 if mk < 0 {
61 mk += i32::MAX;
62 }
63
64 mj = seed_array[ii];
65 }
66
67 for _ in 1..5 {
68 for i in 1..56 {
69 let mut n = i + 30;
70
71 if n >= 55 {
72 n -= 55;
73 }
74
75 seed_array[i] = seed_array[i].wrapping_sub(seed_array[1 + n]);
76
77 if seed_array[i] < 0 {
78 seed_array[i] += i32::MAX;
79 }
80 }
81 }
82
83 Self {
84 seed_array,
85 inext: 0,
86 inextp: 21,
87 }
88 }
89
90 fn sample(&mut self) -> f64 {
91 f64::from(self.internal_sample()) * (1.0 / f64::from(i32::MAX))
92 }
93
94 const fn internal_sample(&mut self) -> i32 {
95 let mut loc_inext = self.inext;
96 loc_inext += 1;
97
98 if loc_inext >= 56 {
99 loc_inext = 1;
100 }
101
102 let mut loc_inextp = self.inextp;
103 loc_inextp += 1;
104
105 if loc_inextp >= 56 {
106 loc_inextp = 1;
107 }
108
109 let mut ret_val =
110 self.seed_array[loc_inext as usize] - self.seed_array[loc_inextp as usize];
111
112 if ret_val == i32::MAX {
113 ret_val -= 1;
114 }
115
116 if ret_val < 0 {
117 ret_val += i32::MAX;
118 }
119
120 self.seed_array[loc_inext as usize] = ret_val;
121 self.inext = loc_inext;
122 self.inextp = loc_inextp;
123
124 ret_val
125 }
126}