63 lines
1.8 KiB
Rust
63 lines
1.8 KiB
Rust
use time::{Date, Month, OffsetDateTime};
|
|
|
|
/// The start of the COVID-19 lockdowns
|
|
///
|
|
/// This is used as an epoch in order to convert from a given date to an integer seed. This is
|
|
/// specified as part of the algorithm for randomly selecting from a weighted list.
|
|
pub const COVID_EPOCH: Date = match Date::from_calendar_date(2020, Month::January, 26) {
|
|
Ok(d) => d,
|
|
Err(_) => Date::MIN, // This never runs, but we can't unwrap, so this is what we're stuck with
|
|
};
|
|
|
|
/// A state to use as an initial state before seeding
|
|
///
|
|
/// Think of this as a ::new() method for a pcg64 generator. Subsiquent calls should be
|
|
/// made to the [`pcg64_seed()`] methods or the [`seed_with_date()`]/[`seed_with_today()`]
|
|
/// methods
|
|
pub const INITIAL_STATE: u128 = 1312_1312_1312;
|
|
|
|
pub fn pcg64(state: &mut u128) -> u64 {
|
|
let mut x = *state;
|
|
pcg64_iterstate(state);
|
|
let count = (x >> (128 - 6)) as u32; // Highest 6 bits
|
|
x ^= x >> 35;
|
|
((x >> 58) as u64).rotate_right(count)
|
|
}
|
|
|
|
fn pcg64_iterstate(state: &mut u128) {
|
|
const MULTIPLIER: u128 = 0xde92a69f6e2f9f25fd0d90f576075fbd;
|
|
const INCREMENT: u128 = 621;
|
|
*state = state.wrapping_mul(MULTIPLIER).wrapping_add(INCREMENT);
|
|
}
|
|
|
|
pub fn pcg64_seed(state: &mut u128, bytes: &[u8]) {
|
|
for byte in bytes {
|
|
*state = (*state ^ *byte as u128).rotate_right(8);
|
|
}
|
|
pcg64_iterstate(state);
|
|
}
|
|
|
|
/// Seed the generator with a given [`Date`] object
|
|
pub fn seed_with_date(state: &mut u128, date: Date) {
|
|
pcg64_seed(
|
|
state,
|
|
&(
|
|
(date - COVID_EPOCH)
|
|
.whole_days()
|
|
as u32
|
|
).to_le_bytes()
|
|
)
|
|
}
|
|
|
|
/// Seed the generator with the [`Date`] object representing today's date
|
|
///
|
|
/// Uses the system's local time, or falls back to UTC
|
|
pub fn seed_with_today(state: &mut u128) {
|
|
seed_with_date(
|
|
state,
|
|
OffsetDateTime::now_local()
|
|
.unwrap_or_else(|_| OffsetDateTime::now_utc())
|
|
.date()
|
|
)
|
|
}
|