|
|
|
@ -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<u32, Box<dyn Entity>>, |
|
|
|
|
id_counter: u32, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
impl Colony { |
|
|
|
|
fn new() -> Colony { |
|
|
|
|
Colony { |
|
|
|
|
ants: HashMap::new(), |
|
|
|
|
id_counter: 0, |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fn add_entity<T: Entity + 'static>(&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<Point> = 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<BoardCommand> = 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<BoardCommand> = 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::<Queen>().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<u32, Box<dyn Entity>>, |
|
|
|
|
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(); |
|
|
|
|
} |
|
|
|
|