From b660cdb2bf372ddb53f1bba795aa79c84e74c5a5 Mon Sep 17 00:00:00 2001 From: Rostyslav Hnatyshyn Date: Mon, 8 Jan 2024 21:50:21 -0700 Subject: [PATCH] code cleanup, fixed bug with food creating home ph --- src/lib/ai.rs | 51 +++++++++++++++++++++++++++++++++++++---------- src/lib/entity.rs | 46 +++++++++--------------------------------- src/lib/screen.rs | 9 --------- src/lib/world.rs | 4 ++-- src/main.rs | 5 ----- 5 files changed, 51 insertions(+), 64 deletions(-) diff --git a/src/lib/ai.rs b/src/lib/ai.rs index d880016..f13791e 100644 --- a/src/lib/ai.rs +++ b/src/lib/ai.rs @@ -1,13 +1,14 @@ -use crate::lib::entity::{Ant, Egg, Queen}; -use crate::lib::point::{Direction, Point}; +use crate::lib::entity::{Ant, Egg, Food, FoodGenerator, Queen}; +use crate::lib::point::Point; use crate::lib::screen::{BoardCommand, Screen}; use crate::lib::world::{Pheremone, World}; +use rand::Rng; use rand::prelude::SliceRandom; use rand::thread_rng; use std::iter::zip; pub trait AI { - fn step(&mut self, b: &Screen, w: &mut World) -> BoardCommand; + fn step(&mut self, b: &Screen, w: &mut World, step: u32) -> BoardCommand; fn plan(&mut self, b: &Screen, w: &mut World) -> BoardCommand { BoardCommand::Noop } @@ -29,8 +30,7 @@ impl AI for Ant { w.drop_pheremone(&p, &self.goal); } self.history.clear(); - self.cw(); - self.cw(); + self.about_face(); self.goal = AIGoal::Return; } BoardCommand::Noop @@ -41,8 +41,7 @@ impl AI for Ant { w.drop_pheremone(&p, &self.goal); } self.history.clear(); - self.cw(); - self.cw(); + self.about_face(); self.goal = AIGoal::Seek; return BoardCommand::SpawnAnt; } else { @@ -52,7 +51,7 @@ impl AI for Ant { } } - fn step(&mut self, b: &Screen, w: &mut World) -> BoardCommand { + fn step(&mut self, b: &Screen, w: &mut World, t: u32) -> BoardCommand { let valid = vec![ (self.dir, self.dir.relative_point(&self.pos)), (self.dir.ccw(), self.dir.ccw().relative_point(&self.pos)), @@ -72,7 +71,7 @@ impl AI for Ant { let r: f32 = rand::random(); let mut dir = &valid[0].0; - if r < 0.2 || ph.len() == 0 { + if r < 0.1 || ph.len() == 0 { let mut rng = thread_rng(); let choice = valid.choose(&mut rng).unwrap(); dir = &choice.0; @@ -97,8 +96,27 @@ impl AI for Ant { } } +impl AI for FoodGenerator { + fn step(&mut self, b: &Screen, w: &mut World, t: u32) -> BoardCommand { + // eventually might want to use poisson disk distrib instead + if t % 600 == 0 && self.counter < 10 { + // generate random coords, if valid, spawn + // if not, try again next step + let (min, max) = b.get_dimensions(); + + let mut rng = rand::thread_rng(); + let r_x = rng.gen_range(min.0..max.0 + 1); + let r_y = rng.gen_range(min.1..max.1 + 1); + + self.counter += 1; + return BoardCommand::SpawnFood(Point(r_x, r_y)); + } + BoardCommand::Noop + } +} + impl AI for Egg { - fn step(&mut self, b: &Screen, w: &mut World) -> BoardCommand { + fn step(&mut self, b: &Screen, w: &mut World, t: u32) -> BoardCommand { if self.counter > 0 { self.counter -= 1; return BoardCommand::Noop; @@ -109,7 +127,7 @@ impl AI for Egg { } impl AI for Queen { - fn step(&mut self, b: &Screen, w: &mut World) -> BoardCommand { + fn step(&mut self, b: &Screen, w: &mut World, t: u32) -> BoardCommand { let valid: Vec = self.pos.get_neighbors(); let mut rng = thread_rng(); @@ -128,3 +146,14 @@ impl AI for Queen { BoardCommand::Noop } } + +impl AI for Food { + fn step(&mut self, b: &Screen, w: &mut World, t: u32) -> BoardCommand { + for n in self.pos.get_neighbors() { + w.drop_pheremone(&n, &AIGoal::Return); + } + w.drop_pheremone(&self.pos, &AIGoal::Return); + + BoardCommand::Noop + } +} diff --git a/src/lib/entity.rs b/src/lib/entity.rs index 7733123..76b81f1 100644 --- a/src/lib/entity.rs +++ b/src/lib/entity.rs @@ -1,8 +1,6 @@ use crate::lib::ai::{AIGoal, AI}; use crate::lib::point::{Direction, Point}; -use crate::lib::screen::{BoardCommand, Screen}; -use crate::lib::world::World; -use rand::Rng; +use crate::lib::screen::Screen; use std::collections::{HashMap, HashSet}; @@ -75,6 +73,11 @@ impl Ant { pub fn cw(&mut self) { self.dir = self.dir.cw(); } + + pub fn about_face(&mut self) { + self.cw(); + self.cw(); + } } impl_entity!(Ant); @@ -211,7 +214,7 @@ impl Entities { #[derive(Clone)] pub struct Food { - pos: Point, + pub pos: Point, id: u32, } @@ -224,17 +227,6 @@ impl Food { } } -impl AI for Food { - fn step(&mut self, b: &Screen, w: &mut World) -> BoardCommand { - for n in self.pos.get_neighbors() { - w.drop_pheremone(&n, &AIGoal::Seek); - } - w.drop_pheremone(&self.pos, &AIGoal::Seek); - - BoardCommand::Noop - } -} - impl Renderable for Food { fn representation(&self) -> &str { "f" @@ -244,10 +236,10 @@ impl Renderable for Food { // no position, does not get rendered yet acts per turn #[derive(Clone)] pub struct FoodGenerator { - timer: u32, + pub timer: u32, pos: Point, id: u32, - counter: u32, + pub counter: u32, } impl FoodGenerator { @@ -261,26 +253,6 @@ impl FoodGenerator { } } -impl AI for FoodGenerator { - fn step(&mut self, b: &Screen, w: &mut World) -> BoardCommand { - // eventually might want to use poisson disk distrib instead - if self.timer % 600 == 0 && self.counter < 10 { - // generate random coords, if valid, spawn - // if not, try again next step - let (min, max) = b.get_dimensions(); - - let mut rng = rand::thread_rng(); - let r_x = rng.gen_range(min.0..max.0 + 1); - let r_y = rng.gen_range(min.1..max.1 + 1); - - self.counter += 1; - return BoardCommand::SpawnFood(Point(r_x, r_y)); - } - self.timer += 1; - BoardCommand::Noop - } -} - impl Renderable for FoodGenerator { fn render(&self, b: &Screen) {} } diff --git a/src/lib/screen.rs b/src/lib/screen.rs index 96b5309..8a2c57d 100644 --- a/src/lib/screen.rs +++ b/src/lib/screen.rs @@ -36,15 +36,6 @@ impl Screen { (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 { - let binding = pos.get_neighbors(); - binding - .iter() - .filter(|e| self.is_in_bounds(e)) - .map(|e| e.clone()) - .collect() - } - pub fn render(&self, p: &Point, char: &str) { mvprintw(p.1, p.0, char); } diff --git a/src/lib/world.rs b/src/lib/world.rs index 5e776d5..2aba20b 100644 --- a/src/lib/world.rs +++ b/src/lib/world.rs @@ -81,7 +81,7 @@ pub fn render(e: &Entities, w: &World, b: &Screen) { pub fn simulate(e: &mut Entities, w: &mut World, b: &mut Screen, step: u32) { let plan_cmds: Vec = e.data.values_mut().map(|a| a.plan(b, w)).collect(); - let mut cmds: Vec = e.data.values_mut().map(|a| a.step(b, w)).collect(); + let mut cmds: Vec = e.data.values_mut().map(|a| a.step(b, w, step)).collect(); cmds.extend(plan_cmds); @@ -115,7 +115,7 @@ pub fn simulate(e: &mut Entities, w: &mut World, b: &mut Screen, step: u32) { } // decay all pheremones by some amount - if step % 60 == 0 { + if step % 600 == 0 { for ph in w.pheremones.iter_mut() { ph.decay(); } diff --git a/src/main.rs b/src/main.rs index a867dbf..f52aa97 100644 --- a/src/main.rs +++ b/src/main.rs @@ -26,9 +26,6 @@ fn main() { let mut entities = Entities::new(); - //let q = Queen::new(board.center.0,board.center.1); - //entities.add_entity(&q); - let fg = FoodGenerator::new(); entities.add_entity(&fg); @@ -38,8 +35,6 @@ fn main() { entities.add_entity(&a); } - //world.create_chamber(Point(board.center.0, board.center.1), 3); - let mut t = 0; loop { // TODO: add way to break out of the loop by hitting a random key