steel_utils/random/
mod.rs1use enum_dispatch::enum_dispatch;
3
4use crate::random::{
5 legacy_random::{LegacyRandom, LegacyRandomSplitter},
6 name_hash::NameHash,
7 xoroshiro::{Xoroshiro, XoroshiroSplitter},
8};
9
10pub mod gaussian;
12pub mod legacy_random;
14pub mod name_hash;
16pub mod weighted_random;
18pub mod worldgen_random;
20pub mod xoroshiro;
22
23#[enum_dispatch]
25#[expect(missing_docs, reason = "method names are self-explanatory")]
26pub trait Random {
27 #[must_use]
28 fn fork(&mut self) -> Self;
29
30 fn next_i32(&mut self) -> i32;
31
32 fn next_i32_bounded(&mut self, bound: i32) -> i32;
33
34 fn next_i32_between(&mut self, min: i32, max: i32) -> i32 {
35 self.next_i32_bounded(max - min + 1) + min
36 }
37
38 fn next_i32_between_exclusive(&mut self, min: i32, max: i32) -> i32 {
39 min + self.next_i32_bounded(max - min)
40 }
41
42 fn next_i64(&mut self) -> i64;
43
44 fn next_f32(&mut self) -> f32;
45
46 fn next_f64(&mut self) -> f64;
47
48 fn next_bool(&mut self) -> bool;
49
50 fn next_gaussian(&mut self) -> f64;
51
52 fn triangle(&mut self, min: f64, max: f64) -> f64 {
53 min + max * (self.next_f64() - self.next_f64())
54 }
55
56 fn triangle_f32(&mut self, min: f32, max: f32) -> f32 {
57 min + max * (self.next_f32() - self.next_f32())
58 }
59
60 fn next_positional(&mut self) -> RandomSplitter;
61
62 fn consume_count(&mut self, count: i32) {
63 for _ in 0..count {
64 self.next_i32();
65 }
66 }
67
68 fn shuffle<T>(&mut self, items: &mut [T]) {
70 let Ok(size) = i32::try_from(items.len()) else {
71 panic!("shuffle length {} exceeds Java's int range", items.len());
72 };
73 for remaining in (2..=size).rev() {
74 let swap_to = self.next_i32_bounded(remaining) as usize;
75 items.swap(remaining as usize - 1, swap_to);
76 }
77 }
78}
79
80#[enum_dispatch]
82#[expect(missing_docs, reason = "method names are self-explanatory")]
83pub trait PositionalRandom {
84 fn at(&self, x: i32, y: i32, z: i32) -> RandomSource;
85
86 fn with_hash_of(&self, hash: &NameHash) -> RandomSource;
87
88 fn with_seed(&self, seed: u64) -> RandomSource;
89}
90
91#[enum_dispatch(Random)]
93pub enum RandomSource {
94 Xoroshiro(Xoroshiro),
96 Legacy(LegacyRandom),
98}
99
100#[derive(Clone)]
102#[enum_dispatch(PositionalRandom)]
103pub enum RandomSplitter {
104 Xoroshiro(XoroshiroSplitter),
106 Legacy(LegacyRandomSplitter),
108}
109
110#[must_use]
112pub fn get_seed(x: i32, y: i32, z: i32) -> i64 {
113 let l = i64::from(x.wrapping_mul(3_129_871))
114 ^ (i64::from(z).wrapping_mul(116_129_781_i64))
115 ^ i64::from(y);
116 let l = l
117 .wrapping_mul(l)
118 .wrapping_mul(42_317_861_i64)
119 .wrapping_add(l.wrapping_mul(11));
120 l >> 16
121}