sideways #1
+13
-28
@@ -32,7 +32,7 @@ impl AI for Ant {
|
|||||||
self.cw();
|
self.cw();
|
||||||
self.cw();
|
self.cw();
|
||||||
self.goal = AIGoal::Return;
|
self.goal = AIGoal::Return;
|
||||||
}
|
}
|
||||||
BoardCommand::Noop
|
BoardCommand::Noop
|
||||||
}
|
}
|
||||||
AIGoal::Return => {
|
AIGoal::Return => {
|
||||||
@@ -44,7 +44,7 @@ impl AI for Ant {
|
|||||||
self.cw();
|
self.cw();
|
||||||
self.cw();
|
self.cw();
|
||||||
self.goal = AIGoal::Seek;
|
self.goal = AIGoal::Seek;
|
||||||
return BoardCommand::SpawnAnt
|
return BoardCommand::SpawnAnt;
|
||||||
} else {
|
} else {
|
||||||
BoardCommand::Noop
|
BoardCommand::Noop
|
||||||
}
|
}
|
||||||
@@ -53,26 +53,13 @@ impl AI for Ant {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn step(&mut self, b: &Screen, w: &mut World) -> BoardCommand {
|
fn step(&mut self, b: &Screen, w: &mut World) -> BoardCommand {
|
||||||
|
|
||||||
let valid = vec![
|
let valid = vec![
|
||||||
(self.dir, self.dir.relative_point(&self.pos)),
|
(self.dir, self.dir.relative_point(&self.pos)),
|
||||||
(self.dir.ccw(), self.dir.ccw().relative_point(&self.pos)),
|
(self.dir.ccw(), self.dir.ccw().relative_point(&self.pos)),
|
||||||
(self.dir.cw(), self.dir.cw().relative_point(&self.pos)),
|
(self.dir.cw(), self.dir.cw().relative_point(&self.pos)),
|
||||||
];
|
];
|
||||||
|
|
||||||
let ph: Vec<Pheremone> = valid
|
let ph: Vec<Pheremone> = valid.iter().map(|(_, pnt)| w.get_pheremone(pnt).clone()).collect();
|
||||||
.iter()
|
|
||||||
.map(|(_, pnt)| {
|
|
||||||
let op = w.cleared.get(pnt);
|
|
||||||
match op {
|
|
||||||
Some(ph) => ph.clone(),
|
|
||||||
None => {
|
|
||||||
w.cleared.insert(pnt.clone(), Pheremone::new());
|
|
||||||
w.cleared.get(pnt).unwrap().clone()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
let ph_fn = match self.goal {
|
let ph_fn = match self.goal {
|
||||||
AIGoal::Seek => |ph: &Pheremone| ph.food,
|
AIGoal::Seek => |ph: &Pheremone| ph.food,
|
||||||
@@ -80,7 +67,7 @@ impl AI for Ant {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let r: f32 = rand::random();
|
let r: f32 = rand::random();
|
||||||
|
|
||||||
let mut dir = &valid[0].0;
|
let mut dir = &valid[0].0;
|
||||||
if r < 0.2 || ph.len() == 0 {
|
if r < 0.2 || ph.len() == 0 {
|
||||||
let mut rng = thread_rng();
|
let mut rng = thread_rng();
|
||||||
@@ -95,14 +82,14 @@ impl AI for Ant {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if dir == &self.dir {
|
if dir == &self.dir {
|
||||||
self.forward(w,b);
|
self.forward(b);
|
||||||
} else if dir == &self.dir.cw() {
|
} else if dir == &self.dir.cw() {
|
||||||
self.cw();
|
self.cw();
|
||||||
} else if dir == &self.dir.ccw() {
|
} else if dir == &self.dir.ccw() {
|
||||||
self.ccw();
|
self.ccw();
|
||||||
}
|
}
|
||||||
BoardCommand::Noop
|
BoardCommand::Noop
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -127,14 +114,12 @@ impl AI for Queen {
|
|||||||
|
|
||||||
if !choice.is_none() {
|
if !choice.is_none() {
|
||||||
let pos = choice.unwrap();
|
let pos = choice.unwrap();
|
||||||
if w.is_cleared(&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, self.id);
|
||||||
return BoardCommand::LayEgg(pos, self.id);
|
} else {
|
||||||
} else {
|
self.pos = pos;
|
||||||
self.pos = pos;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BoardCommand::Noop
|
BoardCommand::Noop
|
||||||
|
|||||||
+6
-9
@@ -16,6 +16,7 @@ pub trait Entity: AI + Downcast {
|
|||||||
fn set_id(&mut self, id: u32);
|
fn set_id(&mut self, id: u32);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
macro_rules! impl_entity {
|
macro_rules! impl_entity {
|
||||||
($t: ident) => {
|
($t: ident) => {
|
||||||
impl Entity for $t {
|
impl Entity for $t {
|
||||||
@@ -56,21 +57,17 @@ impl Ant {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn forward(&mut self, w: &mut World, b: &Screen) {
|
pub fn forward(&mut self, s: &Screen) {
|
||||||
let target = self.dir.relative_point(&self.pos);
|
let target = self.dir.relative_point(&self.pos);
|
||||||
if b.is_in_bounds(&target) {
|
if s.is_in_bounds(&target) {
|
||||||
if w.is_cleared(&self.pos) {
|
self.history.insert(self.pos);
|
||||||
self.history.insert(self.pos);
|
self.pos = target;
|
||||||
self.pos = target;
|
|
||||||
} else {
|
|
||||||
w.clear(target);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
self.cw();
|
self.cw();
|
||||||
self.cw();
|
self.cw();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ccw(&mut self) {
|
pub fn ccw(&mut self) {
|
||||||
self.dir = self.dir.ccw();
|
self.dir = self.dir.ccw();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,3 @@
|
|||||||
use crate::lib::screen::Screen;
|
|
||||||
use crate::lib::world::World;
|
|
||||||
use std::collections::{HashMap, HashSet};
|
|
||||||
|
|
||||||
#[derive(Hash, PartialEq, Eq, Clone, Debug, Copy)]
|
#[derive(Hash, PartialEq, Eq, Clone, Debug, Copy)]
|
||||||
pub struct Point(pub i32, pub i32);
|
pub struct Point(pub i32, pub i32);
|
||||||
|
|
||||||
|
|||||||
+4
-29
@@ -1,13 +1,12 @@
|
|||||||
use crate::lib::point::Point;
|
use crate::lib::point::Point;
|
||||||
|
use ncurses::*;
|
||||||
|
|
||||||
pub struct Screen {
|
pub struct Screen {
|
||||||
pub center: Point,
|
pub center: Point,
|
||||||
max_x: i32,
|
pub max_x: i32,
|
||||||
max_y: i32,
|
pub max_y: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
use ncurses::*;
|
|
||||||
|
|
||||||
pub fn init_screen() -> Screen {
|
pub fn init_screen() -> Screen {
|
||||||
initscr();
|
initscr();
|
||||||
|
|
||||||
@@ -34,7 +33,7 @@ impl Screen {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_in_bounds(&self, pos: &Point) -> bool {
|
pub fn is_in_bounds(&self, pos: &Point) -> bool {
|
||||||
(pos.0 >= 0 && pos.0 < self.max_x) && (pos.1 >= 0 && pos.1 < self.max_y)
|
(pos.0 > 0 && pos.0 < self.max_x) && (pos.1 > 0 && pos.1 < self.max_y)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_valid_movements(&self, pos: &Point) -> Vec<Point> {
|
pub fn get_valid_movements(&self, pos: &Point) -> Vec<Point> {
|
||||||
@@ -55,31 +54,7 @@ impl Screen {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*#[test]
|
|
||||||
fn test_in_bounds() {
|
|
||||||
let x = 20;
|
|
||||||
let y = 20;
|
|
||||||
let s = Screen::new(x, y);
|
|
||||||
|
|
||||||
assert!(&s.is_in_bounds(&Point(0, 0)));
|
|
||||||
assert!(!&s.is_in_bounds(&Point(21, 0)));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_get_valid_movements_board() {
|
|
||||||
let x = 20;
|
|
||||||
let y = 20;
|
|
||||||
let s = Screen::new(x, y);
|
|
||||||
|
|
||||||
let valid = s.get_valid_movements(&Point(0,0));
|
|
||||||
assert_eq!(valid, Point(0,0).get_neighbors());
|
|
||||||
|
|
||||||
let border = s.get_valid_movements(&Point(19,19));
|
|
||||||
assert!(border.len() == 2);
|
|
||||||
}*/
|
|
||||||
|
|
||||||
pub enum BoardCommand {
|
pub enum BoardCommand {
|
||||||
Dig(Point),
|
|
||||||
LayEgg(Point, u32),
|
LayEgg(Point, u32),
|
||||||
SpawnFood(Point),
|
SpawnFood(Point),
|
||||||
Hatch(u32, u32),
|
Hatch(u32, u32),
|
||||||
|
|||||||
+21
-41
@@ -2,12 +2,16 @@ use crate::lib::ai::AIGoal;
|
|||||||
use crate::lib::entity::{Ant, Egg, Entities, Food, Queen};
|
use crate::lib::entity::{Ant, Egg, Entities, Food, Queen};
|
||||||
use crate::lib::point::Point;
|
use crate::lib::point::Point;
|
||||||
use crate::lib::screen::{BoardCommand, Screen};
|
use crate::lib::screen::{BoardCommand, Screen};
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::HashSet;
|
||||||
|
|
||||||
|
use ncurses::*;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct World {
|
pub struct World {
|
||||||
pub cleared: HashMap<Point, Pheremone>,
|
pub pheremones: Vec<Pheremone>,
|
||||||
pub food: HashSet<Point>,
|
pub food: HashSet<Point>,
|
||||||
|
pub home: HashSet<Point>,
|
||||||
|
width: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, PartialOrd, Debug)]
|
#[derive(Clone, PartialEq, PartialOrd, Debug)]
|
||||||
@@ -32,42 +36,29 @@ impl Pheremone {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl World {
|
impl World {
|
||||||
pub fn new() -> World {
|
pub fn new(grid_size: &Point) -> World {
|
||||||
|
let x = grid_size.0;
|
||||||
|
let y = grid_size.1;
|
||||||
|
let ph: Vec<Pheremone> = vec![Pheremone::new(); (x+1) as usize * (y+1) as usize];
|
||||||
|
|
||||||
World {
|
World {
|
||||||
cleared: HashMap::new(),
|
pheremones: ph,
|
||||||
food: HashSet::new(),
|
food: HashSet::new(),
|
||||||
|
home: HashSet::new(), // should be a property per colony
|
||||||
|
width: (y as usize), // width of map for Pheremone calculation
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clear(&mut self, pos: Point) {
|
pub fn get_mut_pheremone(&mut self, pos: &Point) -> &mut Pheremone {
|
||||||
self.cleared.insert(pos, Pheremone::new());
|
&mut self.pheremones[((pos.0 as usize) * self.width) + (pos.1 as usize)]
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_chamber(&mut self, center: Point, radius: i32) {
|
pub fn get_pheremone(&self, pos: &Point) -> &Pheremone {
|
||||||
let cx = center.0;
|
&self.pheremones[((pos.0 as usize) * self.width) + (pos.1 as usize)]
|
||||||
let cy = center.1;
|
|
||||||
|
|
||||||
for i in cx - radius..cx + radius {
|
|
||||||
for j in cy - radius..cy + radius {
|
|
||||||
self.clear(Point(i, j));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_cleared(&self, pos: &Point) -> bool {
|
|
||||||
self.cleared.contains_key(pos)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn drop_pheremone(&mut self, pos: &Point, state: &AIGoal) {
|
pub fn drop_pheremone(&mut self, pos: &Point, state: &AIGoal) {
|
||||||
let op = self.cleared.get_mut(&pos);
|
let ph = self.get_mut_pheremone(pos);
|
||||||
|
|
||||||
let ph = match op {
|
|
||||||
Some(p) => p,
|
|
||||||
None => {
|
|
||||||
self.cleared.insert(*pos, Pheremone::new());
|
|
||||||
self.cleared.get_mut(pos).unwrap()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
match state {
|
match state {
|
||||||
AIGoal::Seek => ph.home += 1,
|
AIGoal::Seek => ph.home += 1,
|
||||||
@@ -77,10 +68,7 @@ impl World {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn render(e: &Entities, w: &World, b: &Screen) {
|
pub fn render(e: &Entities, w: &World, b: &Screen) {
|
||||||
for c in w.cleared.keys() {
|
erase();
|
||||||
b.render(c, "x");
|
|
||||||
}
|
|
||||||
|
|
||||||
for a in e.data.values() {
|
for a in e.data.values() {
|
||||||
a.render(b);
|
a.render(b);
|
||||||
}
|
}
|
||||||
@@ -99,9 +87,6 @@ pub fn simulate(e: &mut Entities, w: &mut World, b: &mut Screen, step: u32) {
|
|||||||
let ant = Ant::new(b.center.0, b.center.1);
|
let ant = Ant::new(b.center.0, b.center.1);
|
||||||
e.add_entity(&ant);
|
e.add_entity(&ant);
|
||||||
}
|
}
|
||||||
BoardCommand::Dig(pos) => {
|
|
||||||
w.clear(pos);
|
|
||||||
}
|
|
||||||
BoardCommand::LayEgg(pos, id) => {
|
BoardCommand::LayEgg(pos, id) => {
|
||||||
let egg = Egg::new(pos.0, pos.1, id);
|
let egg = Egg::new(pos.0, pos.1, id);
|
||||||
e.add_entity(&egg);
|
e.add_entity(&egg);
|
||||||
@@ -125,14 +110,9 @@ pub fn simulate(e: &mut Entities, w: &mut World, b: &mut Screen, step: u32) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for n in b.center.get_neighbors() {
|
|
||||||
w.drop_pheremone(&n, &AIGoal::Return);
|
|
||||||
}
|
|
||||||
w.drop_pheremone(&b.center, &AIGoal::Return);
|
|
||||||
|
|
||||||
// decay all pheremones by some amount
|
// decay all pheremones by some amount
|
||||||
if step % 60 == 0 {
|
if step % 60 == 0 {
|
||||||
for ph in w.cleared.values_mut() {
|
for ph in w.pheremones.iter_mut() {
|
||||||
ph.decay();
|
ph.decay();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -21,7 +21,7 @@ use lib::world::{render, simulate, World};
|
|||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut board = init_screen();
|
let mut board = init_screen();
|
||||||
let mut world = World::new();
|
let mut world = World::new(&Point(board.max_x, board.max_y));
|
||||||
|
|
||||||
let mut entities = Entities::new();
|
let mut entities = Entities::new();
|
||||||
|
|
||||||
@@ -37,7 +37,7 @@ fn main() {
|
|||||||
entities.add_entity(&a);
|
entities.add_entity(&a);
|
||||||
}
|
}
|
||||||
|
|
||||||
world.create_chamber(Point(board.center.0, board.center.1), 3);
|
//world.create_chamber(Point(board.center.0, board.center.1), 3);
|
||||||
|
|
||||||
let mut t = 0;
|
let mut t = 0;
|
||||||
loop {
|
loop {
|
||||||
|
|||||||
+1
-2
@@ -13,9 +13,8 @@ use std::time;
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_reach_astar() {
|
fn test_reach_astar() {
|
||||||
let mut board = init_screen(); //Screen::new(40,40);
|
let mut board = init_screen(); //Screen::new(40,40);
|
||||||
let mut world = World::new();
|
let mut world = World::new(&Point(board.max_x, board.max_y));
|
||||||
|
|
||||||
world.clear(Point(0, 0));
|
|
||||||
let mut entities = Entities::new();
|
let mut entities = Entities::new();
|
||||||
|
|
||||||
let a = Ant::new(0, 0);
|
let a = Ant::new(0, 0);
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
use antf::lib::screen::init_screen;
|
use antf::lib::screen::init_screen;
|
||||||
use antf::lib::world::{World, simulate, render};
|
use antf::lib::world::{World, simulate, render};
|
||||||
use antf::lib::entity::{Entities, FoodGenerator};
|
use antf::lib::entity::{Entities, FoodGenerator};
|
||||||
|
use antf::lib::point::Point;
|
||||||
|
|
||||||
use ncurses::*;
|
use ncurses::*;
|
||||||
use std::thread::sleep;
|
use std::thread::sleep;
|
||||||
@@ -9,7 +10,7 @@ use std::time;
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_foodgen() {
|
fn test_foodgen() {
|
||||||
let mut board = init_screen();
|
let mut board = init_screen();
|
||||||
let mut world = World::new();
|
let mut world = World::new(&Point(board.max_x, board.max_y));
|
||||||
|
|
||||||
let mut entities = Entities::new();
|
let mut entities = Entities::new();
|
||||||
let fg = FoodGenerator::new();
|
let fg = FoodGenerator::new();
|
||||||
|
|||||||
Reference in New Issue
Block a user