You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
123 lines
3.3 KiB
123 lines
3.3 KiB
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::HashSet;
|
|
|
|
use ncurses::*;
|
|
|
|
#[derive(Clone)]
|
|
pub struct World {
|
|
pub pheremones: Vec<Pheremone>,
|
|
pub food: HashSet<Point>,
|
|
pub home: HashSet<Point>,
|
|
width: usize,
|
|
}
|
|
|
|
#[derive(Clone, PartialEq, PartialOrd, Debug)]
|
|
pub struct Pheremone {
|
|
pub home: u32,
|
|
pub food: u32,
|
|
}
|
|
|
|
impl Pheremone {
|
|
pub fn new() -> Pheremone {
|
|
Pheremone { home: 0, food: 0 }
|
|
}
|
|
|
|
pub fn decay(&mut self) {
|
|
if self.home > 0 {
|
|
self.home -= 1;
|
|
}
|
|
if self.food > 0 {
|
|
self.food -= 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
impl 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 {
|
|
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 get_mut_pheremone(&mut self, pos: &Point) -> &mut Pheremone {
|
|
&mut self.pheremones[((pos.0 as usize) * self.width) + (pos.1 as usize)]
|
|
}
|
|
|
|
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 ph = self.get_mut_pheremone(pos);
|
|
|
|
match state {
|
|
AIGoal::Seek => ph.home += 1,
|
|
AIGoal::Return => ph.food += 1,
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn render(e: &Entities, w: &World, b: &Screen) {
|
|
erase();
|
|
|
|
for h in w.home.iter() {
|
|
b.render(h, "x");
|
|
}
|
|
|
|
for a in e.data.values() {
|
|
a.render(b);
|
|
}
|
|
}
|
|
|
|
pub fn simulate(e: &mut Entities, w: &mut World, b: &mut Screen, step: u32) {
|
|
let plan_cmds: Vec<BoardCommand> = e.data.values_mut().map(|a| a.plan(b, w)).collect();
|
|
let mut cmds: Vec<BoardCommand> = e.data.values_mut().map(|a| a.step(b, w, step)).collect();
|
|
|
|
cmds.extend(plan_cmds);
|
|
|
|
for cmd in cmds {
|
|
match cmd {
|
|
BoardCommand::SpawnAnt => {
|
|
let ant = Ant::new(b.center.0, b.center.1);
|
|
e.add_entity(&ant);
|
|
}
|
|
BoardCommand::LayEgg(pos, id) => {
|
|
let egg = Egg::new(pos.0, pos.1, id);
|
|
e.add_entity(&egg);
|
|
}
|
|
BoardCommand::Hatch(egg_id, queen_id) => {
|
|
let egg = e.data.remove(&egg_id);
|
|
let pos = egg.unwrap().get_position();
|
|
|
|
let q = e.data.get_mut(&queen_id).unwrap();
|
|
let queen: &mut Queen = q.downcast_mut::<Queen>().unwrap();
|
|
queen.egg_count -= 1;
|
|
let ant = Ant::new(pos.0, pos.1);
|
|
e.add_entity(&ant);
|
|
}
|
|
BoardCommand::SpawnFood(pos) => {
|
|
let food = Food::new(pos.0, pos.1);
|
|
e.add_entity(&food);
|
|
w.food.insert(pos);
|
|
}
|
|
BoardCommand::Noop => {}
|
|
}
|
|
}
|
|
|
|
// decay all pheremones by some amount
|
|
if step % 600 == 0 {
|
|
for ph in w.pheremones.iter_mut() {
|
|
ph.decay();
|
|
}
|
|
}
|
|
}
|
|
|