#![allow(clippy::type_complexity)]
use rand::rngs::StdRng;
use rand::{RngCore, SeedableRng};
use rustsim_core::{
event_queue::{EventContext, EventQueueModel},
prelude::*,
};
mod support;
use support::NothingSpace;
#[derive(Debug, Clone)]
struct ReplayAgent {
id: AgentId,
value: u64,
}
impl Agent for ReplayAgent {
fn id(&self) -> AgentId {
self.id
}
}
type ReplayModel =
StandardModel<NothingSpace, ReplayAgent, VecStore<ReplayAgent>, (), StdRng, Randomly>;
fn replay_step(
agent: &mut ReplayAgent,
ctx: &mut StepContext<'_, NothingSpace, ReplayAgent, (), StdRng, Randomly>,
) {
let draw = (ctx.rng().next_u32() % 1000) as u64;
agent.value = agent.value.wrapping_mul(31).wrapping_add(draw);
}
fn run_standard_replay(seed: u64) -> Vec<(AgentId, u64)> {
let mut store = VecStore::new();
for id in 1..=6 {
store.insert(ReplayAgent { id, value: id * 10 });
}
let mut model = ReplayModel::new(
store,
NothingSpace,
Randomly::new(),
(),
StdRng::seed_from_u64(seed),
Some(Box::new(replay_step)),
None,
true,
);
model.step_n(12);
(1..=6)
.map(|id| (id, model.agent(id).unwrap().value))
.collect()
}
#[test]
fn standard_model_replay_is_deterministic_with_fixed_seed() {
let run1 = run_standard_replay(42);
let run2 = run_standard_replay(42);
assert_eq!(run1, run2);
}
#[derive(Debug, Clone)]
struct ReplayEventAgent {
id: AgentId,
remaining: u32,
}
impl Agent for ReplayEventAgent {
fn id(&self) -> AgentId {
self.id
}
}
type EventLog = Vec<(AgentId, u32, u32)>;
type ReplayEventModel = EventQueueModel<
NothingSpace,
ReplayEventAgent,
HashMapStore<ReplayEventAgent>,
EventLog,
StdRng,
>;
fn replay_event_action(
agent: &mut ReplayEventAgent,
ctx: &mut EventContext<'_, NothingSpace, ReplayEventAgent, EventLog, StdRng>,
) {
let draw = ctx.rng().next_u32();
let time = ctx.time() as u32;
ctx.properties_mut().push((agent.id, time, draw));
agent.remaining -= 1;
if agent.remaining > 0 {
ctx.add_event(agent.id, 0, 1.0);
}
}
fn run_event_replay(seed: u64) -> EventLog {
let mut store = HashMapStore::new();
store.insert(ReplayEventAgent {
id: 1,
remaining: 3,
});
store.insert(ReplayEventAgent {
id: 2,
remaining: 3,
});
let actions: Vec<
fn(
&mut ReplayEventAgent,
&mut EventContext<'_, NothingSpace, ReplayEventAgent, EventLog, StdRng>,
),
> = vec![replay_event_action];
let mut model = ReplayEventModel::new(
store,
NothingSpace,
Vec::new(),
StdRng::seed_from_u64(seed),
actions,
);
model.add_event(1, 0, 1.0);
model.add_event(2, 0, 1.0);
model.run_events(6);
model.properties().clone()
}
#[test]
fn event_queue_replay_is_deterministic_with_equal_time_events() {
let run1 = run_event_replay(7);
let run2 = run_event_replay(7);
assert_eq!(run1, run2);
}