use goaprs::utils::actor::{ActionFn, Fact, PlannerFn, SensorFn};
use goaprs::utils::ActorAutomatonController;
use std::collections::HashMap;
use std::sync::{Arc, Mutex};
use std::time::Duration;
use tokio::time::sleep;
#[derive(Debug)]
struct WorldState {
heater_on: bool,
temperature_increased: bool,
}
impl WorldState {
fn new() -> Self {
Self {
heater_on: false,
temperature_increased: false,
}
}
}
#[derive(Debug)]
struct HeaterSensor {
world_state: Arc<Mutex<WorldState>>,
}
impl HeaterSensor {
fn new(world_state: Arc<Mutex<WorldState>>) -> Self {
Self { world_state }
}
}
#[async_trait::async_trait]
impl SensorFn for HeaterSensor {
async fn exec(&self, _world_state: &HashMap<String, Fact>) -> Vec<Fact> {
let state = self.world_state.lock().unwrap();
vec![Fact::new(
"heater_on",
&state.heater_on.to_string(),
"HeaterSensor",
)]
}
}
#[derive(Debug)]
struct TemperatureSensor {
world_state: Arc<Mutex<WorldState>>,
}
impl TemperatureSensor {
fn new(world_state: Arc<Mutex<WorldState>>) -> Self {
Self { world_state }
}
}
#[async_trait::async_trait]
impl SensorFn for TemperatureSensor {
async fn exec(&self, _world_state: &HashMap<String, Fact>) -> Vec<Fact> {
let state = self.world_state.lock().unwrap();
vec![Fact::new(
"temperature_increased",
&state.temperature_increased.to_string(),
"TemperatureSensor",
)]
}
}
struct TurnHeaterOnAction {
world_state: Arc<Mutex<WorldState>>,
}
impl TurnHeaterOnAction {
fn new(world_state: Arc<Mutex<WorldState>>) -> Self {
Self { world_state }
}
}
#[async_trait::async_trait]
impl ActionFn for TurnHeaterOnAction {
async fn exec(&self, _world_state: &HashMap<String, Fact>) -> bool {
println!("Executing: Turn heater ON");
let mut state = self.world_state.lock().unwrap();
state.heater_on = true;
true
}
}
struct TurnHeaterOffAction {
world_state: Arc<Mutex<WorldState>>,
}
impl TurnHeaterOffAction {
fn new(world_state: Arc<Mutex<WorldState>>) -> Self {
Self { world_state }
}
}
#[async_trait::async_trait]
impl ActionFn for TurnHeaterOffAction {
async fn exec(&self, _world_state: &HashMap<String, Fact>) -> bool {
println!("Executing: Turn heater OFF");
let mut state = self.world_state.lock().unwrap();
state.heater_on = false;
state.temperature_increased = false;
true
}
}
struct IncreaseTemperatureAction {
world_state: Arc<Mutex<WorldState>>,
}
impl IncreaseTemperatureAction {
fn new(world_state: Arc<Mutex<WorldState>>) -> Self {
Self { world_state }
}
}
#[async_trait::async_trait]
impl ActionFn for IncreaseTemperatureAction {
async fn exec(&self, _world_state: &HashMap<String, Fact>) -> bool {
println!("Executing: Increase temperature");
let mut state = self.world_state.lock().unwrap();
if state.heater_on {
state.temperature_increased = true;
println!(" Temperature increased successfully!");
true
} else {
println!(" Cannot increase temperature - heater is off!");
false
}
}
}
struct ActionWrapper {
id: &'static str,
action: Arc<dyn ActionFn>,
}
impl ActionWrapper {
fn new(id: &'static str, action: Arc<dyn ActionFn>) -> Self {
Self { id, action }
}
}
struct TemperatureControlPlanner;
#[async_trait::async_trait]
impl PlannerFn for TemperatureControlPlanner {
async fn plan(
&self,
world_state: &HashMap<String, Fact>,
goal: &HashMap<String, Fact>,
available_actions: &[Arc<dyn ActionFn>],
) -> Vec<Arc<dyn ActionFn>> {
println!("Planning with world state: {:?}", world_state.keys());
let action_wrappers = vec![
ActionWrapper::new("TurnHeaterOnAction", available_actions[0].clone()),
ActionWrapper::new("TurnHeaterOffAction", available_actions[1].clone()),
ActionWrapper::new("IncreaseTemperatureAction", available_actions[2].clone()),
];
let mut plan = Vec::new();
if let Some(goal_temp_increased) = goal.get("temperature_increased") {
if goal_temp_increased.data() == "true" {
let heater_on = world_state
.get("heater_on")
.map(|f| f.data() == "true")
.unwrap_or(false);
let temp_increased = world_state
.get("temperature_increased")
.map(|f| f.data() == "true")
.unwrap_or(false);
if !temp_increased {
if !heater_on {
if let Some(turn_on_wrapper) = action_wrappers
.iter()
.find(|a| a.id == "TurnHeaterOnAction")
{
plan.push(turn_on_wrapper.action.clone());
}
}
if let Some(increase_wrapper) = action_wrappers
.iter()
.find(|a| a.id == "IncreaseTemperatureAction")
{
plan.push(increase_wrapper.action.clone());
}
}
}
}
if let Some(goal_heater) = goal.get("heater_on") {
if goal_heater.data() == "false" {
let heater_on = world_state
.get("heater_on")
.map(|f| f.data() == "true")
.unwrap_or(false);
if heater_on {
if let Some(turn_off_wrapper) = action_wrappers
.iter()
.find(|a| a.id == "TurnHeaterOffAction")
{
plan.push(turn_off_wrapper.action.clone());
}
}
}
}
println!("Plan created with {} steps", plan.len());
plan
}
}
fn print_state(world_state: &Arc<Mutex<WorldState>>) {
let state = world_state.lock().unwrap();
println!("Current state:");
println!(" Heater: {}", if state.heater_on { "ON" } else { "OFF" });
println!(
" Temperature increased: {}",
if state.temperature_increased {
"YES"
} else {
"NO"
}
);
}
#[tokio::main]
async fn main() {
println!("Starting Advanced Temperature Control Agent");
let local = tokio::task::LocalSet::new();
local
.run_until(async move {
let world_state = Arc::new(Mutex::new(WorldState::new()));
let sensors = vec![
Arc::new(HeaterSensor::new(Arc::clone(&world_state))) as Arc<dyn SensorFn>,
Arc::new(TemperatureSensor::new(Arc::clone(&world_state))) as Arc<dyn SensorFn>,
];
let actions = vec![
Arc::new(TurnHeaterOnAction::new(Arc::clone(&world_state))) as Arc<dyn ActionFn>,
Arc::new(TurnHeaterOffAction::new(Arc::clone(&world_state))) as Arc<dyn ActionFn>,
Arc::new(IncreaseTemperatureAction::new(Arc::clone(&world_state)))
as Arc<dyn ActionFn>,
];
let planner = Arc::new(TemperatureControlPlanner) as Arc<dyn PlannerFn>;
let controller =
ActorAutomatonController::new("TemperatureController", sensors, actions, planner);
let mut goal = HashMap::new();
goal.insert(
"temperature_increased".to_string(),
Fact::new("temperature_increased", "true", "UserGoal"),
);
controller.set_goal(goal).await;
controller.start().await;
for cycle in 1..=5 {
println!("\n--- Cycle {} ---", cycle);
print_state(&world_state);
{
let state = world_state.lock().unwrap();
if state.temperature_increased && cycle == 3 {
println!("Temperature increase achieved!");
println!("New goal: Turn off heater to save energy");
drop(state);
let mut new_goal = HashMap::new();
new_goal.insert(
"heater_on".to_string(),
Fact::new("heater_on", "false", "UserGoal"),
);
controller.set_goal(new_goal).await;
}
}
sleep(Duration::from_secs(1)).await;
}
controller.stop().await;
println!("\nFinal state:");
print_state(&world_state);
println!("Advanced temperature control simulation complete!");
})
.await;
}