From d69b24dfd8cdaed6fd7510fb217b5787af23fe7e Mon Sep 17 00:00:00 2001 From: Rostyslav Hnatyshyn Date: Wed, 3 Jan 2024 00:10:05 -0700 Subject: [PATCH] ai goal - reach works --- src/lib/ai.rs | 42 +++++++++++++++++++++++++++++++++++++----- src/lib/entity.rs | 7 ++++++- src/lib/point.rs | 2 +- src/lib/world.rs | 9 ++++++++- 4 files changed, 52 insertions(+), 8 deletions(-) diff --git a/src/lib/ai.rs b/src/lib/ai.rs index b7ec3fe..18fdf64 100644 --- a/src/lib/ai.rs +++ b/src/lib/ai.rs @@ -1,5 +1,5 @@ use crate::lib::entity::{Ant, Egg, Queen}; -use crate::lib::point::Point; +use crate::lib::point::{astar, Point}; use crate::lib::screen::{BoardCommand, Screen}; use crate::lib::world::World; use rand::prelude::SliceRandom; @@ -8,18 +8,42 @@ use rand::thread_rng; pub trait AI { fn step(&mut self, b: &Screen, w: &mut World) -> BoardCommand; fn get_position(&self) -> Point; + fn plan(&mut self, w: &World) {} +} + +pub enum AIGoal { + Reach(Point), + Idle, } impl AI for Ant { fn get_position(&self) -> Point { self.pos.clone() } + + fn plan(&mut self, w: &World) { + if self.plan.len() == 0 { + self.plan = match self.goal { + AIGoal::Reach(target) => astar(&self.pos, &target), + AIGoal::Idle => vec![], + } + } + } + // return the next move for this ant fn step(&mut self, b: &Screen, w: &mut World) -> BoardCommand { - let valid = w.get_valid_movements(&self.pos, b); - let mut rng = thread_rng(); - - let choice = valid.choose(&mut rng).cloned(); + let choice = match self.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 + } + }; + if !choice.is_none() { let pos = choice.unwrap(); @@ -29,8 +53,16 @@ impl AI for Ant { w.update_occupied(&old_pos, &pos); } else { w.clear(pos); + match self.goal { + AIGoal::Reach(_) => { + self.plan.push(pos); + } + AIGoal::Idle => {} + } } } + + // need to check if progress has been made towards the plan BoardCommand::Noop } } diff --git a/src/lib/entity.rs b/src/lib/entity.rs index 3e538b2..a7b1035 100644 --- a/src/lib/entity.rs +++ b/src/lib/entity.rs @@ -1,6 +1,7 @@ -use crate::lib::ai::AI; +use crate::lib::ai::{AI, AIGoal}; use crate::lib::point::Point; use crate::lib::screen::Screen; + use std::collections::HashMap; use ncurses::*; @@ -13,6 +14,8 @@ impl_downcast!(Entity); pub struct Ant { pub pos: Point, pub id: u32, + pub goal: AIGoal, + pub plan: Vec } impl Ant { @@ -20,6 +23,8 @@ impl Ant { Ant { pos: Point(x, y), id, + plan: vec![], + goal: AIGoal::Idle } } } diff --git a/src/lib/point.rs b/src/lib/point.rs index dc117ff..c112343 100644 --- a/src/lib/point.rs +++ b/src/lib/point.rs @@ -18,7 +18,7 @@ fn manhattan(c1: &Point, c2: &Point) -> i32 { return (c2.0 - c1.0).abs() + (c2.1 - c1.1).abs(); } -fn astar(start: &Point, goal: &Point) -> Vec { +pub fn astar(start: &Point, goal: &Point) -> Vec { let mut open_set : HashSet = HashSet::new(); open_set.insert(*start); diff --git a/src/lib/world.rs b/src/lib/world.rs index 38f0610..1c77143 100644 --- a/src/lib/world.rs +++ b/src/lib/world.rs @@ -21,6 +21,10 @@ impl World { self.cleared.insert(pos); } + pub fn is_valid_movement(&self, pos: &Point, b: &Screen) -> bool { + b.is_in_bounds(pos) && !self.occupied.contains(pos) + } + pub fn get_valid_movements(&self, pos: &Point, b: &Screen) -> Vec { let moves = b.get_valid_movements(pos); moves @@ -50,7 +54,10 @@ pub fn simulate(e: &mut Entities, w: &mut World, b: &mut Screen) { let cmds: Vec = e .data .values_mut() - .map(|a| a.step(b, w)) + .map(|a| { + a.plan(w); + a.step(b, w) + }) .collect(); for cmd in cmds {