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 worldgen_random;
18pub mod xoroshiro;
20
21#[enum_dispatch]
23#[expect(missing_docs, reason = "method names are self-explanatory")]
24pub trait Random {
25 #[must_use]
26 fn fork(&mut self) -> Self;
27
28 fn next_i32(&mut self) -> i32;
29
30 fn next_i32_bounded(&mut self, bound: i32) -> i32;
31
32 fn next_i32_between(&mut self, min: i32, max: i32) -> i32 {
33 self.next_i32_bounded(max - min + 1) + min
34 }
35
36 fn next_i32_between_exclusive(&mut self, min: i32, max: i32) -> i32 {
37 min + self.next_i32_bounded(max - min)
38 }
39
40 fn next_i64(&mut self) -> i64;
41
42 fn next_f32(&mut self) -> f32;
43
44 fn next_f64(&mut self) -> f64;
45
46 fn next_bool(&mut self) -> bool;
47
48 fn next_gaussian(&mut self) -> f64;
49
50 fn triangle(&mut self, min: f64, max: f64) -> f64 {
51 min + max * (self.next_f64() - self.next_f64())
52 }
53
54 fn triangle_f32(&mut self, min: f32, max: f32) -> f32 {
55 min + max * (self.next_f32() - self.next_f32())
56 }
57
58 fn next_positional(&mut self) -> RandomSplitter;
59
60 fn consume_count(&mut self, count: i32) {
61 for _ in 0..count {
62 self.next_i32();
63 }
64 }
65}
66
67#[enum_dispatch]
69#[expect(missing_docs, reason = "method names are self-explanatory")]
70pub trait PositionalRandom {
71 fn at(&self, x: i32, y: i32, z: i32) -> RandomSource;
72
73 fn with_hash_of(&self, hash: &NameHash) -> RandomSource;
74
75 fn with_seed(&self, seed: u64) -> RandomSource;
76}
77
78#[enum_dispatch(Random)]
80pub enum RandomSource {
81 Xoroshiro(Xoroshiro),
83 Legacy(LegacyRandom),
85}
86
87#[derive(Clone)]
89#[enum_dispatch(PositionalRandom)]
90pub enum RandomSplitter {
91 Xoroshiro(XoroshiroSplitter),
93 Legacy(LegacyRandomSplitter),
95}
96
97#[must_use]
99pub fn get_seed(x: i32, y: i32, z: i32) -> i64 {
100 let l = i64::from(x.wrapping_mul(3_129_871))
101 ^ (i64::from(z).wrapping_mul(116_129_781_i64))
102 ^ i64::from(y);
103 let l = l
104 .wrapping_mul(l)
105 .wrapping_mul(42_317_861_i64)
106 .wrapping_add(l.wrapping_mul(11));
107 l >> 16
108}