diff --git a/src/main.rs b/src/main.rs index ab4d792..661df3c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,5 @@ -extern crate ncurses; extern crate downcast_rs; +extern crate ncurses; use ncurses::*; use rand::seq::SliceRandom; @@ -76,42 +76,27 @@ impl World { } } -use downcast_rs::{Downcast, impl_downcast}; +use downcast_rs::{impl_downcast, Downcast}; trait Entity: AI + Renderable + Downcast {} impl_downcast!(Entity); -struct Colony { - ants: HashMap>, - id_counter: u32, -} - -impl Colony { - fn new() -> Colony { - Colony { - ants: HashMap::new(), - id_counter: 0, - } - } - - fn add_entity(&mut self, e: T) { - self.ants.insert(self.id_counter, Box::new(e)); - self.id_counter += 1; - } -} - trait AI { - fn step(&mut self, id: u32, b: &Board, w: &World) -> BoardCommand; + fn step(&mut self, b: &Board, w: &World) -> BoardCommand; fn get_position(&self) -> Point; } struct Ant { pos: Point, + id: u32, } impl Ant { - fn new(x: i32, y: i32) -> Ant { - Ant { pos: Point(x, y) } + fn new(x: i32, y: i32, id: u32) -> Ant { + Ant { + pos: Point(x, y), + id, + } } } @@ -126,6 +111,7 @@ impl Renderable for Ant { struct Queen { pos: Point, egg_count: u8, + id: u32, } impl Renderable for Queen { @@ -141,10 +127,11 @@ trait Renderable { } impl Queen { - fn new(x: i32, y: i32) -> Queen { + fn new(x: i32, y: i32, id: u32) -> Queen { Queen { pos: Point(x, y), egg_count: 0, + id, } } } @@ -153,7 +140,8 @@ impl Queen { struct Egg { pos: Point, counter: u8, - queen_id: u32 + queen_id: u32, + id: u32, } impl Renderable for Egg { @@ -163,22 +151,23 @@ impl Renderable for Egg { } impl Egg { - fn new(x: i32, y: i32, queen_id: u32) -> Egg { + fn new(x: i32, y: i32, id: u32, queen_id: u32) -> Egg { Egg { pos: Point(x, y), counter: 10, - queen_id + id, + queen_id, } } } impl AI for Egg { - fn step(&mut self, id: u32, b: &Board, w: &World) -> BoardCommand { + fn step(&mut self, b: &Board, w: &World) -> BoardCommand { if self.counter > 0 { self.counter -= 1; return BoardCommand::Noop; } else { - BoardCommand::Hatch(id, self.queen_id) + BoardCommand::Hatch(self.id, self.queen_id) } } @@ -199,7 +188,7 @@ impl AI for Ant { self.pos.clone() } // return the next move for this ant - fn step(&mut self, id: u32, b: &Board, w: &World) -> BoardCommand { + fn step(&mut self, b: &Board, w: &World) -> BoardCommand { let valid = w.get_valid_movements(&self.pos, b); let mut rng = thread_rng(); @@ -226,7 +215,7 @@ impl AI for Queen { fn get_position(&self) -> Point { self.pos.clone() } - fn step(&mut self, id: u32, b: &Board, w: &World) -> BoardCommand { + fn step(&mut self, b: &Board, w: &World) -> BoardCommand { let valid: Vec = w.get_valid_movements(&self.pos, b); let mut rng = thread_rng(); @@ -240,7 +229,7 @@ impl AI for Queen { // choose between laying an egg and moving if self.egg_count < 3 { self.egg_count += 1; - return BoardCommand::LayEgg(pos, id); + return BoardCommand::LayEgg(pos, self.id); } else { self.pos = pos; return BoardCommand::Noop; @@ -252,12 +241,12 @@ impl AI for Queen { } } -fn render(c: &Colony, w: &World, b: &Board) { +fn render(e: &Entities, w: &World, b: &Board) { for c in w.cleared.iter() { mvprintw(c.1 + b.center.1, c.0 + b.center.0, "x"); } - for a in c.ants.values() { + for a in e.data.values() { let pos = a.get_position(); mvprintw(pos.1 + b.center.1, pos.0 + b.center.0, a.render()); } @@ -281,8 +270,12 @@ mod tests { } } -fn simulate(c: &mut Colony, w: &mut World, b: &mut Board) { - let cmds: Vec = c.ants.iter_mut().map(|(id, a)| a.step(*id, b, &w)).collect(); +fn simulate(e: &mut Entities, w: &mut World, b: &mut Board) { + let cmds: Vec = e + .data + .values_mut() + .map(|a| a.step(b, &w)) + .collect(); for cmd in cmds { match cmd { @@ -290,22 +283,60 @@ fn simulate(c: &mut Colony, w: &mut World, b: &mut Board) { w.clear(pos); } BoardCommand::LayEgg(pos, id) => { - c.add_entity(Egg::new(pos.0, pos.1, id)); + e.add_egg(pos.0, pos.1, id); } BoardCommand::Hatch(egg_id, queen_id) => { - let egg = c.ants.remove(&egg_id); + let egg = e.data.remove(&egg_id); let pos = egg.unwrap().get_position(); - let q = c.ants.get_mut(&queen_id).unwrap(); + let q = e.data.get_mut(&queen_id).unwrap(); let queen: &mut Queen = q.downcast_mut::().unwrap(); queen.egg_count -= 1; - c.add_entity(Ant::new(pos.0, pos.1)); + e.add_ant(pos.0, pos.1); } BoardCommand::Noop => {} } } w.occupied.clear(); - let _ = c.ants.values().map(|p| w.occupied.insert(p.get_position())); + let _ = e.data.values().map(|p| w.occupied.insert(p.get_position())); +} + +struct Entities { + data: HashMap>, + id_counter: u32, +} + +impl Entities { + fn new() -> Entities { + Entities { + id_counter: 0, + data: HashMap::new(), + } + } + + fn add_ant(&mut self, x: i32, y: i32) -> u32 { + let a = Ant::new(x, y, self.id_counter); + let id = a.id; + self.data.insert(a.id, Box::new(a)); + self.id_counter += 1; + id + } + + fn add_queen(&mut self, x: i32, y: i32) -> u32 { + let q = Queen::new(x, y, self.id_counter); + let id = q.id; + self.data.insert(q.id, Box::new(q)); + self.id_counter += 1; + id + } + + fn add_egg(&mut self, x: i32, y: i32, queen_id: u32) -> u32 { + let e = Egg::new(x, y, self.id_counter, queen_id); + let id = e.id; + self.data.insert(e.id, Box::new(e)); + self.id_counter += 1; + id + } } fn main() { @@ -321,13 +352,16 @@ fn main() { // might move all of contents of board into world + // TODO: rename board to screen -> will keep track of where we are looking at in the world + // TODO: create entity factory to build new entities, will make it easier to have multiple + // colonies because no ids will ever overlap + // TODO: fix renderable to render different colors + let mut board = Board::new(max_x, max_y); let mut world = World::new(); - - let q = Queen::new(0,0); - let mut colony = Colony::new(); - colony.add_entity(q); + let mut entities = Entities::new(); + entities.add_queen(0,0); for i in -3..3 { for j in -3..3 { @@ -337,8 +371,8 @@ fn main() { loop { // TODO: add way to break out of the loop by hitting a random key - simulate(&mut colony, &mut world, &mut board); - render(&colony, &world, &board); + simulate(&mut entities, &mut world, &mut board); + render(&entities, &world, &board); sleep(time::Duration::from_millis(100)); refresh(); }