Skip to main content

wowlab_engine_rng/stochastic/
threshold.rs

1/// State for an accumulated-threshold proc.
2#[derive(Clone, Copy, Debug)]
3pub struct ThresholdTracker {
4    pub increment_max: f64,
5    pub accumulated: f64,
6    pub roll_over: bool,
7}
8
9/// Adds one trigger increment and reports whether the threshold proc occurred.
10pub 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}