| 
					
					
					
				 | 
				@ -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));
 | 
			
		
		
	
		
			
				 | 
				 | 
				 | 
				 | 
				 | 
				  }
 | 
			
		
		
	
		
			
				 | 
				 | 
				 | 
				 | 
				 | 
				}
 |