wowlab_engine_rng/stochastic/
threshold.rs1#[derive(Clone, Copy, Debug)]
3pub struct ThresholdTracker {
4 pub increment_max: f64,
5 pub accumulated: f64,
6 pub roll_over: bool,
7}
8
9pub const fn roll_threshold(tracker: &mut ThresholdTracker, increment: f64) -> bool {
11 if tracker.increment_max <= 0.0 {
12 return false;
13 }
14
15 tracker.accumulated += increment;
16
17 if tracker.accumulated >= 1.0 {
18 tracker.accumulated = if tracker.roll_over {
19 tracker.accumulated - 1.0
20 } else {
21 0.0
22 };
23
24 return true;
25 }
26
27 false
28}
29
30#[cfg(test)]
31mod tests {
32 use googletest::prelude::*;
33
34 use super::*;
35
36 #[gtest]
37 fn disabled_tracker_does_not_mutate() -> Result<()> {
38 let mut tracker = ThresholdTracker {
39 increment_max: 0.0,
40 accumulated: 0.75,
41 roll_over: false,
42 };
43
44 verify_that!(roll_threshold(&mut tracker, 0.5), eq(false))?;
45
46 verify_that!(tracker.accumulated, near(0.75, f64::EPSILON))
47 }
48
49 #[gtest]
50 fn failed_roll_accumulates_increment() -> Result<()> {
51 let mut tracker = ThresholdTracker {
52 increment_max: 0.5,
53 accumulated: 0.25,
54 roll_over: false,
55 };
56
57 verify_that!(roll_threshold(&mut tracker, 0.5), eq(false))?;
58
59 verify_that!(tracker.accumulated, near(0.75, f64::EPSILON))
60 }
61
62 #[gtest]
63 fn successful_roll_resets_without_rollover() -> Result<()> {
64 let mut tracker = ThresholdTracker {
65 increment_max: 0.5,
66 accumulated: 0.75,
67 roll_over: false,
68 };
69
70 verify_that!(roll_threshold(&mut tracker, 0.5), eq(true))?;
71
72 verify_that!(tracker.accumulated, near(0.0, f64::EPSILON))
73 }
74
75 #[gtest]
76 fn successful_roll_preserves_remainder_with_rollover() -> Result<()> {
77 let mut tracker = ThresholdTracker {
78 increment_max: 0.5,
79 accumulated: 0.75,
80 roll_over: true,
81 };
82
83 verify_that!(roll_threshold(&mut tracker, 0.5), eq(true))?;
84
85 verify_that!(tracker.accumulated, near(0.25, f64::EPSILON))
86 }
87}