|
|
|
@ -2,12 +2,16 @@ use crate::lib::ai::AIGoal; |
|
|
|
|
use crate::lib::entity::{Ant, Egg, Entities, Food, Queen}; |
|
|
|
|
use crate::lib::point::Point; |
|
|
|
|
use crate::lib::screen::{BoardCommand, Screen}; |
|
|
|
|
use std::collections::{HashMap, HashSet}; |
|
|
|
|
use std::collections::HashSet; |
|
|
|
|
|
|
|
|
|
use ncurses::*; |
|
|
|
|
|
|
|
|
|
#[derive(Clone)] |
|
|
|
|
pub struct World { |
|
|
|
|
pub cleared: HashMap<Point, Pheremone>, |
|
|
|
|
pub pheremones: Vec<Pheremone>, |
|
|
|
|
pub food: HashSet<Point>, |
|
|
|
|
pub home: HashSet<Point>, |
|
|
|
|
width: usize, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#[derive(Clone, PartialEq, PartialOrd, Debug)] |
|
|
|
@ -32,42 +36,29 @@ impl Pheremone { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
impl World { |
|
|
|
|
pub fn new() -> World { |
|
|
|
|
pub fn new(grid_size: &Point) -> World { |
|
|
|
|
let x = grid_size.0; |
|
|
|
|
let y = grid_size.1; |
|
|
|
|
let ph: Vec<Pheremone> = vec![Pheremone::new(); (x+1) as usize * (y+1) as usize]; |
|
|
|
|
|
|
|
|
|
World { |
|
|
|
|
cleared: HashMap::new(), |
|
|
|
|
pheremones: ph, |
|
|
|
|
food: HashSet::new(), |
|
|
|
|
home: HashSet::new(), // should be a property per colony
|
|
|
|
|
width: (y as usize), // width of map for Pheremone calculation
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub fn clear(&mut self, pos: Point) { |
|
|
|
|
self.cleared.insert(pos, Pheremone::new()); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub fn create_chamber(&mut self, center: Point, radius: i32) { |
|
|
|
|
let cx = center.0; |
|
|
|
|
let cy = center.1; |
|
|
|
|
|
|
|
|
|
for i in cx - radius..cx + radius { |
|
|
|
|
for j in cy - radius..cy + radius { |
|
|
|
|
self.clear(Point(i, j)); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
pub fn get_mut_pheremone(&mut self, pos: &Point) -> &mut Pheremone { |
|
|
|
|
&mut self.pheremones[((pos.0 as usize) * self.width) + (pos.1 as usize)] |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub fn is_cleared(&self, pos: &Point) -> bool { |
|
|
|
|
self.cleared.contains_key(pos) |
|
|
|
|
pub fn get_pheremone(&self, pos: &Point) -> &Pheremone { |
|
|
|
|
&self.pheremones[((pos.0 as usize) * self.width) + (pos.1 as usize)] |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub fn drop_pheremone(&mut self, pos: &Point, state: &AIGoal) { |
|
|
|
|
let op = self.cleared.get_mut(&pos); |
|
|
|
|
|
|
|
|
|
let ph = match op { |
|
|
|
|
Some(p) => p, |
|
|
|
|
None => { |
|
|
|
|
self.cleared.insert(*pos, Pheremone::new()); |
|
|
|
|
self.cleared.get_mut(pos).unwrap() |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
let ph = self.get_mut_pheremone(pos); |
|
|
|
|
|
|
|
|
|
match state { |
|
|
|
|
AIGoal::Seek => ph.home += 1, |
|
|
|
@ -77,10 +68,7 @@ impl World { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub fn render(e: &Entities, w: &World, b: &Screen) { |
|
|
|
|
for c in w.cleared.keys() { |
|
|
|
|
b.render(c, "x"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
erase(); |
|
|
|
|
for a in e.data.values() { |
|
|
|
|
a.render(b); |
|
|
|
|
} |
|
|
|
@ -99,9 +87,6 @@ pub fn simulate(e: &mut Entities, w: &mut World, b: &mut Screen, step: u32) { |
|
|
|
|
let ant = Ant::new(b.center.0, b.center.1); |
|
|
|
|
e.add_entity(&ant); |
|
|
|
|
} |
|
|
|
|
BoardCommand::Dig(pos) => { |
|
|
|
|
w.clear(pos); |
|
|
|
|
} |
|
|
|
|
BoardCommand::LayEgg(pos, id) => { |
|
|
|
|
let egg = Egg::new(pos.0, pos.1, id); |
|
|
|
|
e.add_entity(&egg); |
|
|
|
@ -125,14 +110,9 @@ pub fn simulate(e: &mut Entities, w: &mut World, b: &mut Screen, step: u32) { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
for n in b.center.get_neighbors() { |
|
|
|
|
w.drop_pheremone(&n, &AIGoal::Return); |
|
|
|
|
} |
|
|
|
|
w.drop_pheremone(&b.center, &AIGoal::Return); |
|
|
|
|
|
|
|
|
|
// decay all pheremones by some amount
|
|
|
|
|
if step % 60 == 0 { |
|
|
|
|
for ph in w.cleared.values_mut() { |
|
|
|
|
for ph in w.pheremones.iter_mut() { |
|
|
|
|
ph.decay(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|