From 164030424db48b3da8932201166167ade9b03d8d Mon Sep 17 00:00:00 2001 From: Rostyslav Hnatyshyn Date: Wed, 3 Jan 2024 13:59:59 -0700 Subject: [PATCH] multiple goal ai --- src/lib/ai.rs | 41 ++++++++++++++++++++--------------------- src/lib/entity.rs | 4 +--- src/lib/point.rs | 4 +++- tests/ai_test.rs | 42 +++++++++++++++++++++++++++++++++++++----- 4 files changed, 61 insertions(+), 30 deletions(-) diff --git a/src/lib/ai.rs b/src/lib/ai.rs index d47bffa..0aebb09 100644 --- a/src/lib/ai.rs +++ b/src/lib/ai.rs @@ -10,40 +10,46 @@ pub trait AI { fn plan(&mut self, w: &World) {} } -#[derive(Clone)] +#[derive(Clone, Debug)] pub enum AIGoal { Reach(Point), + //Pickup(Point), + //Drop(), Idle, } impl AI for Ant { fn plan(&mut self, w: &World) { - if self.plan.len() == 0 { - self.plan = match self.goal { + // check last part of plan + if let Some(goal) = self.plan.last() { + match goal { AIGoal::Reach(target) => { - if &self.pos == &target { - self.goal = AIGoal::Idle; - vec![] - } else { - astar(&self.pos, &target) + if self.pos == *target { + self.plan.pop(); } } - AIGoal::Idle => vec![], + AIGoal::Idle => {} } - } + } } // return the next move for this ant fn step(&mut self, b: &Screen, w: &mut World) -> BoardCommand { - let choice = match self.goal { + + let goal = match self.plan.last() { + Some(g) => g, + None => &AIGoal::Idle, + }; + + let choice = match goal { AIGoal::Idle => { let valid = w.get_valid_movements(&self.pos, b); let mut rng = thread_rng(); valid.choose(&mut rng).cloned() } - AIGoal::Reach(_) => { - let movement = self.plan.pop(); - movement + AIGoal::Reach(target) => { + let mut movements = astar(&self.pos, &target); + movements.pop() } }; @@ -55,13 +61,6 @@ impl AI for Ant { w.update_occupied(&old_pos, &pos); } else { w.clear(pos); - match self.goal { - // push plan back because we haven't actually moved towards it - AIGoal::Reach(_) => { - self.plan.push(pos); - } - AIGoal::Idle => {} - } } } diff --git a/src/lib/entity.rs b/src/lib/entity.rs index 5ae270f..e768176 100644 --- a/src/lib/entity.rs +++ b/src/lib/entity.rs @@ -40,8 +40,7 @@ impl_downcast!(Renderable); pub struct Ant { pub pos: Point, pub id: u32, - pub goal: AIGoal, - pub plan: Vec, + pub plan: Vec, } impl Ant { @@ -50,7 +49,6 @@ impl Ant { pos: Point(x, y), id: 0, plan: vec![], - goal: AIGoal::Idle, } } } diff --git a/src/lib/point.rs b/src/lib/point.rs index c112343..084e3c7 100644 --- a/src/lib/point.rs +++ b/src/lib/point.rs @@ -45,7 +45,9 @@ pub fn astar(start: &Point, goal: &Point) -> Vec { answer.push(current.clone()); while came_from.contains_key(¤t) { current = came_from[¤t].clone(); - answer.push(current.clone()); + if current != *start { + answer.push(current.clone()); + } } break; } diff --git a/tests/ai_test.rs b/tests/ai_test.rs index 87bffcf..5a97d06 100644 --- a/tests/ai_test.rs +++ b/tests/ai_test.rs @@ -1,8 +1,8 @@ -use antf::lib::screen::init_screen; +use antf::lib::screen::{Screen, init_screen}; use antf::lib::point::Point; use antf::lib::ai::AIGoal; use antf::lib::world::{World, simulate, render}; -use antf::lib::entity::{Entities, Ant}; +use antf::lib::entity::{Entities, Ant, Food, FoodGenerator}; use ncurses::*; use std::thread::sleep; @@ -12,7 +12,7 @@ use std::time; #[test] fn test_reach_astar() { - let mut board = init_screen(); + let mut board = init_screen();//Screen::new(40,40); let mut world = World::new(); let mut entities = Entities::new(); @@ -22,9 +22,13 @@ fn test_reach_astar() { let a = entities.data.get_mut(&id).unwrap(); let ant: &mut Ant = a.downcast_mut::().unwrap(); - ant.goal = AIGoal::Reach(Point(10,10)); + ant.plan.push(AIGoal::Reach(Point(10,10))); + ant.plan.push(AIGoal::Reach(Point(-10,-10))); + ant.plan.push(AIGoal::Reach(Point(10,-10))); + ant.plan.push(AIGoal::Reach(Point(-10,10))); - for _ in 0..60 { + // craps out... need to make sure unwrap() is safe + for _ in 0..420 { // TODO: add way to break out of the loop by hitting a random key simulate(&mut entities, &mut world, &mut board); render(&entities, &world, &board); @@ -34,3 +38,31 @@ fn test_reach_astar() { clear(); endwin(); } + +/*#[test] +fn test_drag() { + let mut board = init_screen(); + let mut world = World::new(); + + let mut entities = Entities::new(); + + let f = Food::new(10,10); + let a = Ant::new(0,0); + let fid = entities.add_entity(&f); + let id = entities.add_entity(&a); + + let a = entities.data.get_mut(&id).unwrap(); + let ant: &mut Ant = a.downcast_mut::().unwrap(); + + //ant.goal = + + for _ in 0..60 { + // TODO: add way to break out of the loop by hitting a random key + simulate(&mut entities, &mut world, &mut board); + render(&entities, &world, &board); + sleep(time::Duration::from_millis(100)); + refresh(); + } + clear(); + endwin(); +}*/