From 0b13c7bfa396f8e9d08954f73ad86081bfc05cb9 Mon Sep 17 00:00:00 2001 From: Rostyslav Hnatyshyn Date: Mon, 8 Jan 2024 21:22:59 -0700 Subject: [PATCH] cleared up gfx + ph storage --- src/lib/ai.rs | 41 ++++++++++------------------- src/lib/entity.rs | 15 +++++------ src/lib/point.rs | 4 --- src/lib/screen.rs | 33 +++-------------------- src/lib/world.rs | 62 +++++++++++++++----------------------------- src/main.rs | 4 +-- tests/ai_test.rs | 3 +-- tests/entity_test.rs | 3 ++- 8 files changed, 49 insertions(+), 116 deletions(-) diff --git a/src/lib/ai.rs b/src/lib/ai.rs index c4a5c0f..a00a393 100644 --- a/src/lib/ai.rs +++ b/src/lib/ai.rs @@ -32,7 +32,7 @@ impl AI for Ant { self.cw(); self.cw(); self.goal = AIGoal::Return; - } + } BoardCommand::Noop } AIGoal::Return => { @@ -44,7 +44,7 @@ impl AI for Ant { self.cw(); self.cw(); self.goal = AIGoal::Seek; - return BoardCommand::SpawnAnt + return BoardCommand::SpawnAnt; } else { BoardCommand::Noop } @@ -53,26 +53,13 @@ impl AI for Ant { } fn step(&mut self, b: &Screen, w: &mut World) -> BoardCommand { - let valid = vec![ (self.dir, self.dir.relative_point(&self.pos)), (self.dir.ccw(), self.dir.ccw().relative_point(&self.pos)), (self.dir.cw(), self.dir.cw().relative_point(&self.pos)), ]; - let ph: Vec = valid - .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: Vec = valid.iter().map(|(_, pnt)| w.get_pheremone(pnt).clone()).collect(); let ph_fn = match self.goal { AIGoal::Seek => |ph: &Pheremone| ph.food, @@ -80,7 +67,7 @@ impl AI for Ant { }; let r: f32 = rand::random(); - + let mut dir = &valid[0].0; if r < 0.2 || ph.len() == 0 { let mut rng = thread_rng(); @@ -95,14 +82,14 @@ impl AI for Ant { } } } - + if dir == &self.dir { - self.forward(w,b); + self.forward(b); } else if dir == &self.dir.cw() { self.cw(); } else if dir == &self.dir.ccw() { self.ccw(); - } + } BoardCommand::Noop } } @@ -127,14 +114,12 @@ impl AI for Queen { if !choice.is_none() { let pos = choice.unwrap(); - if w.is_cleared(&pos) { - // choose between laying an egg and moving - if self.egg_count < 3 { - self.egg_count += 1; - return BoardCommand::LayEgg(pos, self.id); - } else { - self.pos = pos; - } + // choose between laying an egg and moving + if self.egg_count < 3 { + self.egg_count += 1; + return BoardCommand::LayEgg(pos, self.id); + } else { + self.pos = pos; } } BoardCommand::Noop diff --git a/src/lib/entity.rs b/src/lib/entity.rs index e85199c..7733123 100644 --- a/src/lib/entity.rs +++ b/src/lib/entity.rs @@ -16,6 +16,7 @@ pub trait Entity: AI + Downcast { fn set_id(&mut self, id: u32); } + macro_rules! impl_entity { ($t: ident) => { 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); - if b.is_in_bounds(&target) { - if w.is_cleared(&self.pos) { - self.history.insert(self.pos); - self.pos = target; - } else { - w.clear(target); - } + if s.is_in_bounds(&target) { + self.history.insert(self.pos); + self.pos = target; } else { self.cw(); self.cw(); } } - + pub fn ccw(&mut self) { self.dir = self.dir.ccw(); } diff --git a/src/lib/point.rs b/src/lib/point.rs index 6607232..d0383b3 100644 --- a/src/lib/point.rs +++ b/src/lib/point.rs @@ -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)] pub struct Point(pub i32, pub i32); diff --git a/src/lib/screen.rs b/src/lib/screen.rs index ea2e630..96b5309 100644 --- a/src/lib/screen.rs +++ b/src/lib/screen.rs @@ -1,13 +1,12 @@ use crate::lib::point::Point; +use ncurses::*; pub struct Screen { pub center: Point, - max_x: i32, - max_y: i32, + pub max_x: i32, + pub max_y: i32, } -use ncurses::*; - pub fn init_screen() -> Screen { initscr(); @@ -34,7 +33,7 @@ impl Screen { } 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 { @@ -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 { - Dig(Point), LayEgg(Point, u32), SpawnFood(Point), Hatch(u32, u32), diff --git a/src/lib/world.rs b/src/lib/world.rs index ba88115..7ef04c5 100644 --- a/src/lib/world.rs +++ b/src/lib/world.rs @@ -2,12 +2,16 @@ use crate::lib::ai::AIGoal; use crate::lib::entity::{Ant, Egg, Entities, Food, Queen}; use crate::lib::point::Point; use crate::lib::screen::{BoardCommand, Screen}; -use std::collections::{HashMap, HashSet}; +use std::collections::HashSet; + +use ncurses::*; #[derive(Clone)] pub struct World { - pub cleared: HashMap, + pub pheremones: Vec, pub food: HashSet, + pub home: HashSet, + width: usize, } #[derive(Clone, PartialEq, PartialOrd, Debug)] @@ -32,42 +36,29 @@ impl Pheremone { } 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 = vec![Pheremone::new(); (x+1) as usize * (y+1) as usize]; + World { - cleared: HashMap::new(), + pheremones: ph, 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) { - self.cleared.insert(pos, Pheremone::new()); - } - - 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 get_mut_pheremone(&mut self, pos: &Point) -> &mut Pheremone { + &mut self.pheremones[((pos.0 as usize) * self.width) + (pos.1 as usize)] } - pub fn is_cleared(&self, pos: &Point) -> bool { - self.cleared.contains_key(pos) + pub fn get_pheremone(&self, pos: &Point) -> &Pheremone { + &self.pheremones[((pos.0 as usize) * self.width) + (pos.1 as usize)] } pub fn drop_pheremone(&mut self, pos: &Point, state: &AIGoal) { - let op = self.cleared.get_mut(&pos); - - let ph = match op { - Some(p) => p, - None => { - self.cleared.insert(*pos, Pheremone::new()); - self.cleared.get_mut(pos).unwrap() - } - }; + let ph = self.get_mut_pheremone(pos); match state { AIGoal::Seek => ph.home += 1, @@ -77,10 +68,7 @@ impl World { } pub fn render(e: &Entities, w: &World, b: &Screen) { - for c in w.cleared.keys() { - b.render(c, "x"); - } - + erase(); for a in e.data.values() { 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); e.add_entity(&ant); } - BoardCommand::Dig(pos) => { - w.clear(pos); - } BoardCommand::LayEgg(pos, id) => { let egg = Egg::new(pos.0, pos.1, id); 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 if step % 60 == 0 { - for ph in w.cleared.values_mut() { + for ph in w.pheremones.iter_mut() { ph.decay(); } } diff --git a/src/main.rs b/src/main.rs index f6935c4..8c8dc34 100644 --- a/src/main.rs +++ b/src/main.rs @@ -21,7 +21,7 @@ use lib::world::{render, simulate, World}; fn main() { 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(); @@ -37,7 +37,7 @@ fn main() { 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; loop { diff --git a/tests/ai_test.rs b/tests/ai_test.rs index 00ea159..900c2ed 100644 --- a/tests/ai_test.rs +++ b/tests/ai_test.rs @@ -13,9 +13,8 @@ use std::time; #[test] fn test_reach_astar() { 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 a = Ant::new(0, 0); diff --git a/tests/entity_test.rs b/tests/entity_test.rs index 825511e..a78207d 100644 --- a/tests/entity_test.rs +++ b/tests/entity_test.rs @@ -1,6 +1,7 @@ use antf::lib::screen::init_screen; use antf::lib::world::{World, simulate, render}; use antf::lib::entity::{Entities, FoodGenerator}; +use antf::lib::point::Point; use ncurses::*; use std::thread::sleep; @@ -9,7 +10,7 @@ use std::time; #[test] fn test_foodgen() { 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 fg = FoodGenerator::new();