|
@ -1,5 +1,5 @@ |
|
|
use crate::agent::{Agent, AgentId, Direction, Move, Position, WorldView};
|
|
|
use crate::agent::{Agent, AgentId, Direction, Move, Position, WorldView};
|
|
|
use std::collections::HashMap;
|
|
|
|
|
|
|
|
|
use std::collections::hash_map::{Entry, HashMap};
|
|
|
|
|
|
|
|
|
pub struct ActualWorld {
|
|
|
pub struct ActualWorld {
|
|
|
size: Position,
|
|
|
size: Position,
|
|
@ -10,6 +10,28 @@ pub struct ActualWorld { |
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
impl ActualWorld {
|
|
|
impl ActualWorld {
|
|
|
|
|
|
/// Agents receive incrementing ids starting with 0
|
|
|
|
|
|
/// The last agent is 'It'
|
|
|
|
|
|
pub fn new(size: Position, input_agents: Vec<(Position, Box<dyn Agent>)>) -> Self {
|
|
|
|
|
|
let agent_count = input_agents.len();
|
|
|
|
|
|
assert!(agent_count > 0);
|
|
|
|
|
|
let mut id = 0;
|
|
|
|
|
|
let mut agent_positions = HashMap::with_capacity(agent_count);
|
|
|
|
|
|
let mut agents = HashMap::with_capacity(agent_count);
|
|
|
|
|
|
for (pos, agent) in input_agents.into_iter() {
|
|
|
|
|
|
agent_positions.insert(id, pos);
|
|
|
|
|
|
agents.insert(id, agent);
|
|
|
|
|
|
id += 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
Self {
|
|
|
|
|
|
size,
|
|
|
|
|
|
tagged_by: None,
|
|
|
|
|
|
tagged: id - 1,
|
|
|
|
|
|
agents,
|
|
|
|
|
|
agent_positions,
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
pub fn do_step(&mut self) {
|
|
|
pub fn do_step(&mut self) {
|
|
|
let moves: Vec<_> = self
|
|
|
let moves: Vec<_> = self
|
|
|
.agents
|
|
|
.agents
|
|
@ -19,11 +41,14 @@ impl ActualWorld { |
|
|
(
|
|
|
(
|
|
|
*id,
|
|
|
*id,
|
|
|
agent.next_move(WorldView {
|
|
|
agent.next_move(WorldView {
|
|
|
self_tagged: *id == self.tagged,
|
|
|
|
|
|
|
|
|
self_id: *id,
|
|
|
|
|
|
tagged_by: self.tagged_by,
|
|
|
|
|
|
tagged: self.tagged,
|
|
|
bounds_distance: (pos.y, self.size.x - pos.x, self.size.y - pos.y, pos.x),
|
|
|
bounds_distance: (pos.y, self.size.x - pos.x, self.size.y - pos.y, pos.x),
|
|
|
other_agents: self
|
|
|
other_agents: self
|
|
|
.agent_positions
|
|
|
.agent_positions
|
|
|
.iter()
|
|
|
.iter()
|
|
|
|
|
|
.filter(|(other_id, _)| id != *other_id)
|
|
|
.map(|(id, other_pos)| {
|
|
|
.map(|(id, other_pos)| {
|
|
|
(
|
|
|
(
|
|
|
Direction {
|
|
|
Direction {
|
|
@ -43,15 +68,21 @@ impl ActualWorld { |
|
|
Move::Noop => {}
|
|
|
Move::Noop => {}
|
|
|
Move::TryTag(other_id) => {
|
|
|
Move::TryTag(other_id) => {
|
|
|
// FIXME check distance
|
|
|
// FIXME check distance
|
|
|
// FIXME check tagged_by
|
|
|
|
|
|
self.agents.get_mut(&other_id).unwrap().get_tagged(other_id);
|
|
|
|
|
|
// FIXME update tagged
|
|
|
|
|
|
// FIXME update tagged_by
|
|
|
|
|
|
|
|
|
assert_eq!(self.tagged, id);
|
|
|
|
|
|
assert_ne!(self.tagged_by, Some(other_id));
|
|
|
|
|
|
assert!(
|
|
|
|
|
|
self.agents.contains_key(&other_id),
|
|
|
|
|
|
"Trying to tag a nonexisting agent"
|
|
|
|
|
|
);
|
|
|
|
|
|
self.tagged = other_id;
|
|
|
|
|
|
self.tagged_by = Some(id);
|
|
|
}
|
|
|
}
|
|
|
Move::TryMove(dir) => {
|
|
|
Move::TryMove(dir) => {
|
|
|
// FIXME check out of bounds
|
|
|
// FIXME check out of bounds
|
|
|
// FIXME matches!
|
|
|
|
|
|
self.agent_positions.entry(id).and_modify(|e| {
|
|
|
|
|
|
|
|
|
// FIXME check speed
|
|
|
|
|
|
let entry = self.agent_positions.entry(id);
|
|
|
|
|
|
assert!(matches!(entry, Entry::Occupied(_)));
|
|
|
|
|
|
entry.and_modify(|e| {
|
|
|
e.x += dir.x;
|
|
|
e.x += dir.x;
|
|
|
e.y += dir.y;
|
|
|
e.y += dir.y;
|
|
|
});
|
|
|
});
|
|
@ -60,3 +91,46 @@ impl ActualWorld { |
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
|
|
mod test {
|
|
|
|
|
|
use crate::agent::{Move, NullAgent, Position, ScriptedAgent};
|
|
|
|
|
|
use crate::world::ActualWorld;
|
|
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
|
#[should_panic]
|
|
|
|
|
|
fn empty() {
|
|
|
|
|
|
ActualWorld::new(Position { x: 0, y: 0 }, vec![]);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
|
fn trivial() {
|
|
|
|
|
|
let mut world = ActualWorld::new(
|
|
|
|
|
|
Position { x: 0, y: 0 },
|
|
|
|
|
|
vec![(Position { x: 0, y: 0 }, Box::new(NullAgent))],
|
|
|
|
|
|
);
|
|
|
|
|
|
world.do_step();
|
|
|
|
|
|
assert_eq!(world.tagged, 0);
|
|
|
|
|
|
assert_eq!(world.tagged_by, None);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
|
fn scripted_tagging() {
|
|
|
|
|
|
let mut world = ActualWorld::new(
|
|
|
|
|
|
Position { x: 0, y: 0 },
|
|
|
|
|
|
vec![
|
|
|
|
|
|
(
|
|
|
|
|
|
Position { x: 0, y: 0 },
|
|
|
|
|
|
Box::new(ScriptedAgent::new(vec![Move::Noop])),
|
|
|
|
|
|
),
|
|
|
|
|
|
(
|
|
|
|
|
|
Position { x: 0, y: 0 },
|
|
|
|
|
|
Box::new(ScriptedAgent::new(vec![Move::TryTag(0)])),
|
|
|
|
|
|
),
|
|
|
|
|
|
],
|
|
|
|
|
|
);
|
|
|
|
|
|
world.do_step();
|
|
|
|
|
|
assert_eq!(world.tagged, 0);
|
|
|
|
|
|
assert_eq!(world.tagged_by, Some(1));
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|