added entity factory, id inside structs

master
Rostyslav Hnatyshyn 9 months ago
parent d6b93daf7a
commit 2fd7c9c9d5
  1. 130
      src/main.rs

@ -1,5 +1,5 @@
extern crate ncurses;
extern crate downcast_rs; extern crate downcast_rs;
extern crate ncurses;
use ncurses::*; use ncurses::*;
use rand::seq::SliceRandom; 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 {} trait Entity: AI + Renderable + Downcast {}
impl_downcast!(Entity); 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 { 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; fn get_position(&self) -> Point;
} }
struct Ant { struct Ant {
pos: Point, pos: Point,
id: u32,
} }
impl Ant { impl Ant {
fn new(x: i32, y: i32) -> Ant { fn new(x: i32, y: i32, id: u32) -> Ant {
Ant { pos: Point(x, y) } Ant {
pos: Point(x, y),
id,
}
} }
} }
@ -126,6 +111,7 @@ impl Renderable for Ant {
struct Queen { struct Queen {
pos: Point, pos: Point,
egg_count: u8, egg_count: u8,
id: u32,
} }
impl Renderable for Queen { impl Renderable for Queen {
@ -141,10 +127,11 @@ trait Renderable {
} }
impl Queen { impl Queen {
fn new(x: i32, y: i32) -> Queen { fn new(x: i32, y: i32, id: u32) -> Queen {
Queen { Queen {
pos: Point(x, y), pos: Point(x, y),
egg_count: 0, egg_count: 0,
id,
} }
} }
} }
@ -153,7 +140,8 @@ impl Queen {
struct Egg { struct Egg {
pos: Point, pos: Point,
counter: u8, counter: u8,
queen_id: u32 queen_id: u32,
id: u32,
} }
impl Renderable for Egg { impl Renderable for Egg {
@ -163,22 +151,23 @@ impl Renderable for Egg {
} }
impl 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 { Egg {
pos: Point(x, y), pos: Point(x, y),
counter: 10, counter: 10,
queen_id id,
queen_id,
} }
} }
} }
impl AI for Egg { 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 { if self.counter > 0 {
self.counter -= 1; self.counter -= 1;
return BoardCommand::Noop; return BoardCommand::Noop;
} else { } 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() self.pos.clone()
} }
// return the next move for this ant // 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 valid = w.get_valid_movements(&self.pos, b);
let mut rng = thread_rng(); let mut rng = thread_rng();
@ -226,7 +215,7 @@ impl AI for Queen {
fn get_position(&self) -> Point { fn get_position(&self) -> Point {
self.pos.clone() 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 valid: Vec<Point> = w.get_valid_movements(&self.pos, b);
let mut rng = thread_rng(); let mut rng = thread_rng();
@ -240,7 +229,7 @@ impl AI for Queen {
// choose between laying an egg and moving // choose between laying an egg and moving
if self.egg_count < 3 { if self.egg_count < 3 {
self.egg_count += 1; self.egg_count += 1;
return BoardCommand::LayEgg(pos, id); return BoardCommand::LayEgg(pos, self.id);
} else { } else {
self.pos = pos; self.pos = pos;
return BoardCommand::Noop; 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() { for c in w.cleared.iter() {
mvprintw(c.1 + b.center.1, c.0 + b.center.0, "x"); 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(); let pos = a.get_position();
mvprintw(pos.1 + b.center.1, pos.0 + b.center.0, a.render()); 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) { fn simulate(e: &mut Entities, w: &mut World, b: &mut Board) {
let cmds: Vec<BoardCommand> = c.ants.iter_mut().map(|(id, a)| a.step(*id, b, &w)).collect(); let cmds: Vec<BoardCommand> = e
.data
.values_mut()
.map(|a| a.step(b, &w))
.collect();
for cmd in cmds { for cmd in cmds {
match cmd { match cmd {
@ -290,22 +283,60 @@ fn simulate(c: &mut Colony, w: &mut World, b: &mut Board) {
w.clear(pos); w.clear(pos);
} }
BoardCommand::LayEgg(pos, id) => { 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) => { 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 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(); let queen: &mut Queen = q.downcast_mut::<Queen>().unwrap();
queen.egg_count -= 1; queen.egg_count -= 1;
c.add_entity(Ant::new(pos.0, pos.1)); e.add_ant(pos.0, pos.1);
} }
BoardCommand::Noop => {} BoardCommand::Noop => {}
} }
} }
w.occupied.clear(); 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() { fn main() {
@ -321,13 +352,16 @@ fn main() {
// might move all of contents of board into world // 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 board = Board::new(max_x, max_y);
let mut world = World::new(); let mut world = World::new();
let q = Queen::new(0,0);
let mut colony = Colony::new(); let mut entities = Entities::new();
colony.add_entity(q); entities.add_queen(0,0);
for i in -3..3 { for i in -3..3 {
for j in -3..3 { for j in -3..3 {
@ -337,8 +371,8 @@ fn main() {
loop { loop {
// TODO: add way to break out of the loop by hitting a random key // TODO: add way to break out of the loop by hitting a random key
simulate(&mut colony, &mut world, &mut board); simulate(&mut entities, &mut world, &mut board);
render(&colony, &world, &board); render(&entities, &world, &board);
sleep(time::Duration::from_millis(100)); sleep(time::Duration::from_millis(100));
refresh(); refresh();
} }

Loading…
Cancel
Save