works but ants overwrite eachother
This commit is contained in:
+85
-79
@@ -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) {
|
fn add_entity<T: Entity + 'static>(&mut self, pos: &Point, e: T) {
|
||||||
self.ants.push(Box::new(Ant::new(x, y)));
|
self.ants.insert(*pos, Box::new(e));
|
||||||
}
|
|
||||||
|
|
||||||
fn add_entity<T: AI + 'static>(&mut self, e: T) {
|
|
||||||
self.ants.push(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 Queen {
|
impl Renderable for Queen {
|
||||||
fn new(x: i32, y: i32) -> Queen {
|
fn render(&self) -> &str {
|
||||||
Queen {
|
"q"
|
||||||
pos: Point(x, y),
|
|
||||||
egg_count: 0,
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
trait Renderable {
|
||||||
|
fn render(&self) -> &str {
|
||||||
|
"z"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Queen {
|
||||||
|
fn new() -> Queen {
|
||||||
|
Queen { egg_count: 0 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct Egg {
|
struct Egg {
|
||||||
pos: Point,
|
|
||||||
counter: u8,
|
counter: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Egg {
|
impl Renderable for Egg {
|
||||||
fn new(x: i32, y: i32) -> Egg {
|
fn render(&self) -> &str {
|
||||||
Egg {
|
"e"
|
||||||
pos: Point(x, y),
|
|
||||||
counter: 10,
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Egg {
|
||||||
|
fn new() -> Egg {
|
||||||
|
Egg { 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
|
||||||
|
|||||||
Reference in New Issue
Block a user