use rand::rngs::StdRng;
use rand::SeedableRng;
use rustsim_core::{
interaction::{self, PositionedAgent, SpaceInteraction},
prelude::{Agent, ById, Fastest, HashMapStore, StandardModel},
types::AgentId,
};
mod support;
use support::{Grid2D, GridPos2};
#[derive(Debug, Clone)]
struct GridBot {
id: AgentId,
pos: GridPos2,
}
impl Agent for GridBot {
fn id(&self) -> AgentId {
self.id
}
}
impl PositionedAgent for GridBot {
type Position = GridPos2;
fn position(&self) -> &GridPos2 {
&self.pos
}
fn set_position(&mut self, pos: GridPos2) {
self.pos = pos;
}
}
type BotModel = StandardModel<Grid2D, GridBot, HashMapStore<GridBot>, (), StdRng, Fastest>;
#[test]
fn add_remove_move_via_interaction_api() {
let store = HashMapStore::new();
let grid = Grid2D::new(5, 5, false);
let mut model = BotModel::new(
store,
grid,
Fastest::new(),
(),
StdRng::seed_from_u64(0),
None,
None,
true,
);
let bot = GridBot {
id: model.next_id(),
pos: (1, 1),
};
interaction::add_agent(&mut model, bot).unwrap();
assert!(model.agent(1).is_some());
assert_eq!(*model.agent(1).unwrap().position(), (1, 1));
interaction::move_agent(&mut model, 1, (3, 3)).unwrap();
assert_eq!(*model.agent(1).unwrap().position(), (3, 3));
let ids = <Grid2D as SpaceInteraction<GridBot>>::nearby_ids(model.space(), &(3, 3), 0);
assert!(ids.contains(&1));
let old_ids = <Grid2D as SpaceInteraction<GridBot>>::nearby_ids(model.space(), &(1, 1), 0);
assert!(!old_ids.contains(&1));
let removed = interaction::remove_agent(&mut model, 1).unwrap();
assert!(removed.is_some());
assert!(model.agent(1).is_none());
}
#[test]
fn nearby_agents_finds_correct_set() {
let store = HashMapStore::new();
let grid = Grid2D::new(10, 10, false);
let mut model = BotModel::new(
store,
grid,
Fastest::new(),
(),
StdRng::seed_from_u64(0),
None,
None,
true,
);
let bots = vec![
GridBot { id: 1, pos: (5, 5) },
GridBot { id: 2, pos: (6, 5) },
GridBot { id: 3, pos: (0, 0) },
];
for bot in bots {
interaction::add_agent(&mut model, bot).unwrap();
}
let nearby = interaction::nearby_agents(&model, &(5, 5), 1);
let nearby_ids: Vec<AgentId> = nearby.iter().map(|a| a.id()).collect();
assert!(nearby_ids.contains(&1));
assert!(nearby_ids.contains(&2));
assert!(!nearby_ids.contains(&3));
}
#[test]
fn step_spatial_applies_deferred_actions_to_store_and_space() {
type SpatialModel = StandardModel<Grid2D, GridBot, HashMapStore<GridBot>, (), StdRng, ById>;
let store = HashMapStore::new();
let grid = Grid2D::new(10, 10, false);
let mut model = SpatialModel::new_with_agent_step(
store,
grid,
ById::new(),
(),
StdRng::seed_from_u64(1),
|agent, ctx| {
if agent.id == 1 {
ctx.defer_remove_agent(2);
ctx.defer_insert_agent(GridBot { id: 3, pos: (4, 4) });
}
},
true,
);
model
.insert_positioned_agent(GridBot { id: 1, pos: (1, 1) })
.unwrap();
model
.insert_positioned_agent(GridBot { id: 2, pos: (2, 2) })
.unwrap();
model.step_spatial().unwrap();
model.validate_space_index().unwrap();
assert!(model.agent(1).is_some());
assert!(model.agent(2).is_none());
assert!(model.agent(3).is_some());
let old_ids = <Grid2D as SpaceInteraction<GridBot>>::nearby_ids(model.space(), &(2, 2), 0);
assert!(!old_ids.contains(&2));
let new_ids = <Grid2D as SpaceInteraction<GridBot>>::nearby_ids(model.space(), &(4, 4), 0);
assert_eq!(new_ids, vec![3]);
}