works but ants overwrite eachother

master
Rostyslav Hnatyshyn 9 months ago
parent 1b6dd4b9ad
commit 04f4a91c0e
  1. 164
      src/main.rs

@ -3,7 +3,7 @@ extern crate ncurses;
use ncurses::*; use ncurses::*;
use rand::seq::SliceRandom; use rand::seq::SliceRandom;
use rand::thread_rng; use rand::thread_rng;
use std::collections::HashSet; use std::collections::{HashMap, HashSet};
use std::thread::sleep; use std::thread::sleep;
use std::time; use std::time;
@ -50,112 +50,121 @@ impl Board {
#[derive(Clone)] #[derive(Clone)]
struct World { struct World {
cleared: HashSet<Point>, cleared: HashSet<Point>,
occupied: HashSet<Point>,
} }
impl World { impl World {
fn new() -> World { fn new() -> World {
World { World {
cleared: HashSet::new(), cleared: HashSet::new(),
occupied: HashSet::new(),
} }
} }
fn clear(&mut self, pos: Point) { fn clear(&mut self, pos: Point) {
self.cleared.insert(pos); self.cleared.insert(pos);
} }
fn get_valid_movements(&self, pos: &Point, b: &Board) -> Vec<Point> {
let moves = b.get_valid_movements(pos);
moves.iter().filter(|p| !self.occupied.contains(p)).map(|p| p.clone()).collect()
}
} }
trait Entity: AI + Renderable {}
struct Colony { struct Colony {
ants: Vec<Box<dyn AI>>, ants: HashMap<Point, Box<dyn Entity>>,
} }
impl Colony { impl Colony {
fn new() -> Colony { fn new() -> Colony {
Colony { ants: vec![] } Colony {
} ants: HashMap::new(),
}
fn add_ant(&mut self, x: i32, y: i32) {
self.ants.push(Box::new(Ant::new(x, y)));
} }
fn add_entity<T: AI + 'static>(&mut self, e: T) { fn add_entity<T: Entity + 'static>(&mut self, pos: &Point, e: T) {
self.ants.push(Box::new(e)); self.ants.insert(*pos, Box::new(e));
} }
} }
trait AI { trait AI {
fn step(&mut self, b: &Board, w: &World) -> BoardCommand; fn step(&mut self, pos: &Point, b: &Board, w: &World) -> BoardCommand;
fn get_position(&self) -> Point;
fn set_position(&mut self, p: Point);
} }
struct Ant { struct Ant {}
pos: Point,
}
impl Ant { impl Entity for Ant {}
fn new(x: i32, y: i32) -> Ant {
Ant { pos: Point(x, y) } impl Renderable for Ant {
fn render(&self) -> &str {
"o"
} }
} }
struct Queen { struct Queen {
pos: Point,
egg_count: u8, egg_count: u8,
} }
impl Renderable for Queen {
fn render(&self) -> &str {
"q"
}
}
trait Renderable {
fn render(&self) -> &str {
"z"
}
}
impl Queen { impl Queen {
fn new(x: i32, y: i32) -> Queen { fn new() -> Queen {
Queen { Queen { egg_count: 0 }
pos: Point(x, y),
egg_count: 0,
}
} }
} }
#[derive(Debug)] #[derive(Debug)]
struct Egg { struct Egg {
pos: Point,
counter: u8, counter: u8,
} }
impl Renderable for Egg {
fn render(&self) -> &str {
"e"
}
}
impl Egg { impl Egg {
fn new(x: i32, y: i32) -> Egg { fn new() -> Egg {
Egg { Egg { counter: 10 }
pos: Point(x, y),
counter: 10,
}
} }
} }
impl AI for Egg { impl AI for Egg {
fn step(&mut self, b: &Board, w: &World) -> BoardCommand { fn step(&mut self, p: &Point, 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 BoardCommand::Hatch(*p)
} }
} }
fn get_position(&self) -> Point {
self.pos.clone()
}
fn set_position(&mut self, p: Point) {
self.pos = p;
}
} }
enum BoardCommand<'a> { enum BoardCommand {
Move(Box<&'a mut dyn AI>, Point), Move(Point, Point),
Dig(Point), Dig(Point),
LayEgg(Point), LayEgg(Point),
Hatch, Hatch(Point),
Noop, Noop,
} }
impl AI for Ant { impl AI for Ant {
// return the next move for this ant // return the next move for this ant
fn step(&mut self, b: &Board, w: &World) -> BoardCommand { fn step(&mut self, p: &Point, b: &Board, w: &World) -> BoardCommand {
let valid = b.get_valid_movements(&self.pos); let valid = w.get_valid_movements(p, b);
let mut rng = thread_rng(); let mut rng = thread_rng();
let choice = valid.choose(&mut rng).cloned(); let choice = valid.choose(&mut rng).cloned();
@ -165,25 +174,20 @@ impl AI for Ant {
} else { } else {
let pos = choice.unwrap(); let pos = choice.unwrap();
if w.cleared.contains(&pos) { if w.cleared.contains(&pos) {
return BoardCommand::Move(Box::new(self), pos); return BoardCommand::Move(*p, pos);
} else { } else {
return BoardCommand::Dig(pos); return BoardCommand::Dig(pos);
} }
} }
} }
fn get_position(&self) -> Point {
self.pos.clone()
}
fn set_position(&mut self, p: Point) {
self.pos = p
}
} }
impl Entity for Queen {}
impl Entity for Egg {}
impl AI for Queen { impl AI for Queen {
fn step(&mut self, b: &Board, w: &World) -> BoardCommand { fn step(&mut self, p: &Point, b: &Board, w: &World) -> BoardCommand {
let valid = b.get_valid_movements(&self.pos); let valid: Vec<Point> = w.get_valid_movements(p, b);
let mut rng = thread_rng(); let mut rng = thread_rng();
let choice = valid.choose(&mut rng).cloned(); let choice = valid.choose(&mut rng).cloned();
@ -194,24 +198,16 @@ impl AI for Queen {
if w.cleared.contains(&pos) { if w.cleared.contains(&pos) {
// 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); return BoardCommand::LayEgg(pos);
} else { } else {
return BoardCommand::Move(Box::new(self), pos); return BoardCommand::Move(*p, pos);
} }
} else { } else {
return BoardCommand::Noop; return BoardCommand::Noop;
} }
} }
} }
fn get_position(&self) -> Point {
self.pos.clone()
}
fn set_position(&mut self, p: Point) {
self.pos = p
}
} }
fn render(c: &Colony, w: &World, b: &Board) { fn render(c: &Colony, w: &World, b: &Board) {
@ -219,9 +215,8 @@ fn render(c: &Colony, w: &World, b: &Board) {
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.iter() { for (pos, a) in c.ants.iter() {
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, "o");
} }
} }
@ -240,33 +235,39 @@ mod tests {
dbg!(board.is_in_bounds(&Point(0, 0))); dbg!(board.is_in_bounds(&Point(0, 0)));
dbg!(board.get_valid_movements(&Point(0, 0))); dbg!(board.get_valid_movements(&Point(0, 0)));
let mut ant = Ant { pos: Point(0, 0) };
} }
} }
use std::iter::zip;
fn simulate(c: &mut Colony, w: &mut World, b: &mut Board) { fn simulate(c: &mut Colony, w: &mut World, b: &mut Board) {
let world = w.clone(); let cmds: Vec<BoardCommand> = c
let cmds: Vec<BoardCommand> = c.ants.iter_mut().map(|a| a.step(b, &world)).collect(); .ants
.iter_mut()
.map(|(p, a)| {
a.step(&p, b, &w)
})
.collect();
for cmd in cmds { for cmd in cmds {
match cmd { match cmd {
BoardCommand::Move(a, pos) => { BoardCommand::Move(old_pos, pos) => {
a.set_position(pos); let a = c.ants.remove(&old_pos).unwrap();
c.ants.insert(pos, a);
} }
BoardCommand::Dig(pos) => { BoardCommand::Dig(pos) => {
w.clear(pos); w.clear(pos);
} }
BoardCommand::LayEgg(pos) => { BoardCommand::LayEgg(pos) => {
//c.add_entity(Egg::new(pos.0, pos.1)); c.add_entity(&pos, Egg::new());
}
BoardCommand::Hatch(pos) => {
c.ants.remove(&pos);
c.add_entity(&pos, Ant {});
} }
BoardCommand::Hatch => {}
BoardCommand::Noop => {} BoardCommand::Noop => {}
} }
} }
w.occupied.clear();
let _ = c.ants.keys().map(|p| w.occupied.insert(*p));
} }
fn main() { fn main() {
@ -286,8 +287,13 @@ fn main() {
let mut world = World::new(); let mut world = World::new();
let mut colony = Colony::new(); let mut colony = Colony::new();
colony.add_ant(0,0); for i in -3..3 {
for j in -3..3 {
world.clear(Point(i, j));
}
}
colony.add_entity(&Point(0, 0), Queen::new());
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

Loading…
Cancel
Save