cleared up gfx + ph storage

sideways
Rostyslav Hnatyshyn 9 months ago
parent 823b5d39b8
commit 0b13c7bfa3
  1. 21
      src/lib/ai.rs
  2. 9
      src/lib/entity.rs
  3. 4
      src/lib/point.rs
  4. 33
      src/lib/screen.rs
  5. 62
      src/lib/world.rs
  6. 4
      src/main.rs
  7. 3
      tests/ai_test.rs
  8. 3
      tests/entity_test.rs

@ -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,
@ -97,7 +84,7 @@ 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() {
@ -127,7 +114,6 @@ 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;
@ -136,7 +122,6 @@ impl AI for Queen {
self.pos = pos; self.pos = pos;
} }
} }
}
BoardCommand::Noop BoardCommand::Noop
} }
} }

@ -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,15 +57,11 @@ 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();

@ -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);

@ -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),

@ -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) {
let cx = center.0;
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 { pub fn get_pheremone(&self, pos: &Point) -> &Pheremone {
self.cleared.contains_key(pos) &self.pheremones[((pos.0 as usize) * self.width) + (pos.1 as usize)]
} }
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();
} }
} }

@ -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 {

@ -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();

Loading…
Cancel
Save