From 47c6eff011eb5bbaaa19972d293b76d2f9c2ff5b Mon Sep 17 00:00:00 2001 From: Rostyslav Hnatyshyn Date: Thu, 4 Jan 2024 14:32:28 -0700 Subject: [PATCH] added seek --- src/lib/ai.rs | 39 ++++++++++++++++----------------------- src/lib/entity.rs | 1 + src/lib/world.rs | 43 +++++++++++++++++++++++-------------------- src/main.rs | 14 +++++++++++--- 4 files changed, 51 insertions(+), 46 deletions(-) diff --git a/src/lib/ai.rs b/src/lib/ai.rs index deabf10..23381fe 100644 --- a/src/lib/ai.rs +++ b/src/lib/ai.rs @@ -12,7 +12,7 @@ pub trait AI { #[derive(Clone, Debug)] pub enum AIGoal { - Reach(Point), + Seek, //Pickup(Point), //Drop(), Idle, @@ -23,8 +23,9 @@ impl AI for Ant { // check last part of plan if let Some(goal) = self.plan.last() { match goal { - AIGoal::Reach(target) => { - if self.pos == *target { + AIGoal::Seek => { + // if we reach food, we change state + if w.food.contains(&self.pos) { self.plan.pop(); } } @@ -40,31 +41,23 @@ impl AI for Ant { None => &AIGoal::Idle, }; - let choice = match goal { - AIGoal::Idle => { - // valid_movements does not return any diggables! - let valid = w.get_valid_movements(&self.pos, b, true); - let mut rng = thread_rng(); - valid.choose(&mut rng).cloned() - } - AIGoal::Reach(target) => { - // here astar only produces a path between the target & pos without digging - let result = astar(&self.pos, &target, Some(w), Some(b)); - let mut movements = match result { - Ok(m) => m, - Err(_) => vec![] - }; - movements.pop() - } - }; - + let valid = w.get_valid_movements(&self.pos, b, true); + let mut rng = thread_rng(); + let choice = valid.choose(&mut rng).cloned(); + if !choice.is_none() { let pos = choice.unwrap(); if w.cleared.contains(&pos) { self.pos = pos; } else { - if w.is_safe_to_dig(&pos, &b) { - w.clear(pos); + + match goal { + AIGoal::Seek => { + if w.is_safe_to_dig(&pos, &b) { + w.clear(pos); + } + }, + AIGoal::Idle => {} } } } diff --git a/src/lib/entity.rs b/src/lib/entity.rs index c8f7ac3..c22168a 100644 --- a/src/lib/entity.rs +++ b/src/lib/entity.rs @@ -217,6 +217,7 @@ 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 diff --git a/src/lib/world.rs b/src/lib/world.rs index b74341d..222bcaf 100644 --- a/src/lib/world.rs +++ b/src/lib/world.rs @@ -6,7 +6,7 @@ use std::collections::HashSet; #[derive(Clone)] pub struct World { pub cleared: HashSet, - pub food: HashSet, + pub food: HashSet, } impl World { @@ -22,27 +22,27 @@ impl World { } 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)); - } - } + 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_valid_movement(&self, current: &Point, target: &Point, b: &Screen) -> bool { // should allow down movements always - - let safe = target.is_below(*current) || ( - !self.cleared.contains(&target.down()) - || !self.cleared.contains(&target.left()) - || !self.cleared.contains(&target.right()) - || !self.cleared.contains(&target.bldiag()) - || !self.cleared.contains(&target.uldiag()) - || !self.cleared.contains(&target.brdiag()) - || !self.cleared.contains(&target.urdiag())); + + let safe = target.is_below(*current) + || (!self.cleared.contains(&target.down()) + || !self.cleared.contains(&target.left()) + || !self.cleared.contains(&target.right()) + || !self.cleared.contains(&target.bldiag()) + || !self.cleared.contains(&target.uldiag()) + || !self.cleared.contains(&target.brdiag()) + || !self.cleared.contains(&target.urdiag())); // of course, its only a valid move if you can walk there! b.is_in_bounds(target) && self.cleared.contains(target) && safe @@ -55,7 +55,7 @@ impl World { pub fn is_safe_to_dig(&self, target: &Point, b: &Screen) -> bool { let mut hypothetical_world = self.clone(); hypothetical_world.clear(*target); - let result = astar(target, &Point(0, 0), Some(&hypothetical_world), Some(b)); + let result = astar(target, &b.center, Some(&hypothetical_world), Some(b)); b.is_in_bounds(target) && result.is_ok() } @@ -82,10 +82,12 @@ impl World { .collect(); if return_diggables { - ans.extend(self.get_diggable(b, pos)); + let digs = self.get_diggable(b, pos); + ans.extend(digs); } ans + } } @@ -131,6 +133,7 @@ pub fn simulate(e: &mut Entities, w: &mut World, b: &mut Screen) { BoardCommand::SpawnFood(pos) => { let food = Food::new(pos.0, pos.1); e.add_entity(&food); + w.food.insert(pos); } BoardCommand::Noop => {} } diff --git a/src/main.rs b/src/main.rs index 4b511cb..5f8f67e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -17,16 +17,24 @@ mod lib { use lib::point::Point; use lib::screen::init_screen; use lib::world::{World, simulate, render}; -use lib::entity::{Entities, Queen}; +use lib::entity::{Entities, Ant, FoodGenerator}; fn main() { let mut board = init_screen(); let mut world = World::new(); let mut entities = Entities::new(); - let q = Queen::new(board.center.0,board.center.1); - entities.add_entity(&q); + //let q = Queen::new(board.center.0,board.center.1); + //entities.add_entity(&q); + + let fg = FoodGenerator::new(); + entities.add_entity(&fg); + + let mut a = Ant::new(board.center.0, board.center.1); + a.plan.push(lib::ai::AIGoal::Seek); + entities.add_entity(&a); + world.create_chamber(Point(board.center.0, board.center.1), 3); loop {