multiple goal ai

master
Rostyslav Hnatyshyn 9 months ago
parent 1487614e86
commit 164030424d
  1. 39
      src/lib/ai.rs
  2. 4
      src/lib/entity.rs
  3. 4
      src/lib/point.rs
  4. 40
      tests/ai_test.rs

@ -10,40 +10,46 @@ pub trait AI {
fn plan(&mut self, w: &World) {} fn plan(&mut self, w: &World) {}
} }
#[derive(Clone)] #[derive(Clone, Debug)]
pub enum AIGoal { pub enum AIGoal {
Reach(Point), Reach(Point),
//Pickup(Point),
//Drop(),
Idle, Idle,
} }
impl AI for Ant { impl AI for Ant {
fn plan(&mut self, w: &World) { fn plan(&mut self, w: &World) {
if self.plan.len() == 0 { // check last part of plan
self.plan = match self.goal { if let Some(goal) = self.plan.last() {
match goal {
AIGoal::Reach(target) => { AIGoal::Reach(target) => {
if &self.pos == &target { if self.pos == *target {
self.goal = AIGoal::Idle; self.plan.pop();
vec![]
} else {
astar(&self.pos, &target)
} }
} }
AIGoal::Idle => vec![], AIGoal::Idle => {}
} }
} }
} }
// return the next move for this ant // return the next move for this ant
fn step(&mut self, b: &Screen, w: &mut World) -> BoardCommand { 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 => { AIGoal::Idle => {
let valid = w.get_valid_movements(&self.pos, b); let valid = w.get_valid_movements(&self.pos, b);
let mut rng = thread_rng(); let mut rng = thread_rng();
valid.choose(&mut rng).cloned() valid.choose(&mut rng).cloned()
} }
AIGoal::Reach(_) => { AIGoal::Reach(target) => {
let movement = self.plan.pop(); let mut movements = astar(&self.pos, &target);
movement movements.pop()
} }
}; };
@ -55,13 +61,6 @@ impl AI for Ant {
w.update_occupied(&old_pos, &pos); w.update_occupied(&old_pos, &pos);
} else { } else {
w.clear(pos); 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 => {}
}
} }
} }

@ -40,8 +40,7 @@ impl_downcast!(Renderable);
pub struct Ant { pub struct Ant {
pub pos: Point, pub pos: Point,
pub id: u32, pub id: u32,
pub goal: AIGoal, pub plan: Vec<AIGoal>,
pub plan: Vec<Point>,
} }
impl Ant { impl Ant {
@ -50,7 +49,6 @@ impl Ant {
pos: Point(x, y), pos: Point(x, y),
id: 0, id: 0,
plan: vec![], plan: vec![],
goal: AIGoal::Idle,
} }
} }
} }

@ -45,7 +45,9 @@ pub fn astar(start: &Point, goal: &Point) -> Vec<Point> {
answer.push(current.clone()); answer.push(current.clone());
while came_from.contains_key(&current) { while came_from.contains_key(&current) {
current = came_from[&current].clone(); current = came_from[&current].clone();
answer.push(current.clone()); if current != *start {
answer.push(current.clone());
}
} }
break; break;
} }

@ -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::point::Point;
use antf::lib::ai::AIGoal; use antf::lib::ai::AIGoal;
use antf::lib::world::{World, simulate, render}; use antf::lib::world::{World, simulate, render};
use antf::lib::entity::{Entities, Ant}; use antf::lib::entity::{Entities, Ant, Food, FoodGenerator};
use ncurses::*; use ncurses::*;
use std::thread::sleep; use std::thread::sleep;
@ -12,17 +12,49 @@ use std::time;
#[test] #[test]
fn test_reach_astar() { fn test_reach_astar() {
let mut board = init_screen();//Screen::new(40,40);
let mut world = World::new();
let mut entities = Entities::new();
let a = Ant::new(0,0);
let id = entities.add_entity(&a);
let a = entities.data.get_mut(&id).unwrap();
let ant: &mut Ant = a.downcast_mut::<Ant>().unwrap();
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)));
// 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);
sleep(time::Duration::from_millis(100));
refresh();
}
clear();
endwin();
}
/*#[test]
fn test_drag() {
let mut board = init_screen(); let mut board = init_screen();
let mut world = World::new(); let mut world = World::new();
let mut entities = Entities::new(); let mut entities = Entities::new();
let f = Food::new(10,10);
let a = Ant::new(0,0); let a = Ant::new(0,0);
let fid = entities.add_entity(&f);
let id = entities.add_entity(&a); let id = entities.add_entity(&a);
let a = entities.data.get_mut(&id).unwrap(); let a = entities.data.get_mut(&id).unwrap();
let ant: &mut Ant = a.downcast_mut::<Ant>().unwrap(); let ant: &mut Ant = a.downcast_mut::<Ant>().unwrap();
ant.goal = AIGoal::Reach(Point(10,10));
//ant.goal =
for _ in 0..60 { for _ in 0..60 {
// TODO: add way to break out of the loop by hitting a random key // TODO: add way to break out of the loop by hitting a random key
@ -33,4 +65,4 @@ fn test_reach_astar() {
} }
clear(); clear();
endwin(); endwin();
} }*/

Loading…
Cancel
Save