use crate::{BehaviorNode, BoxedBehavior, NodeStatus};
use async_trait::async_trait;
use mecha10_core::Context;
use tracing::{debug, warn};
#[derive(Debug)]
pub struct SequenceNode {
children: Vec<BoxedBehavior>,
current_index: usize,
}
impl SequenceNode {
pub fn new(children: Vec<BoxedBehavior>) -> Self {
Self {
children,
current_index: 0,
}
}
pub fn add_child(&mut self, child: BoxedBehavior) {
self.children.push(child);
}
pub fn len(&self) -> usize {
self.children.len()
}
pub fn is_empty(&self) -> bool {
self.children.is_empty()
}
}
#[async_trait]
impl BehaviorNode for SequenceNode {
async fn tick(&mut self, ctx: &Context) -> anyhow::Result<NodeStatus> {
if self.children.is_empty() {
return Ok(NodeStatus::Success);
}
let total_children = self.children.len();
while self.current_index < total_children {
debug!(
"Sequence: ticking child {} of {}",
self.current_index + 1,
total_children
);
let child = &mut self.children[self.current_index];
match child.tick(ctx).await? {
NodeStatus::Success => {
self.current_index += 1;
}
NodeStatus::Failure => {
debug!("Sequence: child {} failed", self.current_index + 1);
return Ok(NodeStatus::Failure);
}
NodeStatus::Running => {
return Ok(NodeStatus::Running);
}
}
}
debug!("Sequence: all children succeeded");
Ok(NodeStatus::Success)
}
async fn reset(&mut self) -> anyhow::Result<()> {
self.current_index = 0;
for child in &mut self.children {
child.reset().await?;
}
Ok(())
}
async fn on_init(&mut self, ctx: &Context) -> anyhow::Result<()> {
for child in &mut self.children {
child.on_init(ctx).await?;
}
Ok(())
}
async fn on_terminate(&mut self, ctx: &Context) -> anyhow::Result<()> {
for child in &mut self.children {
child.on_terminate(ctx).await?;
}
Ok(())
}
fn name(&self) -> &str {
"sequence"
}
}
#[derive(Debug)]
pub struct SelectOrNode {
children: Vec<BoxedBehavior>,
current_index: usize,
}
impl SelectOrNode {
pub fn new(children: Vec<BoxedBehavior>) -> Self {
Self {
children,
current_index: 0,
}
}
pub fn add_child(&mut self, child: BoxedBehavior) {
self.children.push(child);
}
pub fn len(&self) -> usize {
self.children.len()
}
pub fn is_empty(&self) -> bool {
self.children.is_empty()
}
}
#[async_trait]
impl BehaviorNode for SelectOrNode {
async fn tick(&mut self, ctx: &Context) -> anyhow::Result<NodeStatus> {
if self.children.is_empty() {
return Ok(NodeStatus::Failure);
}
let total_children = self.children.len();
while self.current_index < total_children {
debug!(
"Selector: ticking child {} of {}",
self.current_index + 1,
total_children
);
let child = &mut self.children[self.current_index];
match child.tick(ctx).await? {
NodeStatus::Success => {
debug!("Selector: child {} succeeded", self.current_index + 1);
return Ok(NodeStatus::Success);
}
NodeStatus::Failure => {
warn!("Selector: child {} failed, trying next", self.current_index + 1);
self.current_index += 1;
}
NodeStatus::Running => {
return Ok(NodeStatus::Running);
}
}
}
debug!("Selector: all children failed");
Ok(NodeStatus::Failure)
}
async fn reset(&mut self) -> anyhow::Result<()> {
self.current_index = 0;
for child in &mut self.children {
child.reset().await?;
}
Ok(())
}
async fn on_init(&mut self, ctx: &Context) -> anyhow::Result<()> {
for child in &mut self.children {
child.on_init(ctx).await?;
}
Ok(())
}
async fn on_terminate(&mut self, ctx: &Context) -> anyhow::Result<()> {
for child in &mut self.children {
child.on_terminate(ctx).await?;
}
Ok(())
}
fn name(&self) -> &str {
"selector"
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ParallelPolicy {
RequireAll,
RequireOne,
RequireN(usize),
}
#[derive(Debug)]
pub struct ParallelNode {
children: Vec<BoxedBehavior>,
policy: ParallelPolicy,
child_statuses: Vec<NodeStatus>,
}
impl ParallelNode {
pub fn new(children: Vec<BoxedBehavior>, policy: ParallelPolicy) -> Self {
let child_statuses = vec![NodeStatus::Running; children.len()];
Self {
children,
policy,
child_statuses,
}
}
pub fn add_child(&mut self, child: BoxedBehavior) {
self.children.push(child);
self.child_statuses.push(NodeStatus::Running);
}
pub fn len(&self) -> usize {
self.children.len()
}
pub fn is_empty(&self) -> bool {
self.children.is_empty()
}
}
#[async_trait]
impl BehaviorNode for ParallelNode {
async fn tick(&mut self, ctx: &Context) -> anyhow::Result<NodeStatus> {
if self.children.is_empty() {
return Ok(NodeStatus::Success);
}
for (i, child) in self.children.iter_mut().enumerate() {
if self.child_statuses[i].is_running() {
let status = child.tick(ctx).await?;
self.child_statuses[i] = status;
debug!("Parallel: child {} status: {}", i + 1, status);
}
}
let success_count = self.child_statuses.iter().filter(|s| s.is_success()).count();
let failure_count = self.child_statuses.iter().filter(|s| s.is_failure()).count();
let _running_count = self.child_statuses.iter().filter(|s| s.is_running()).count();
match self.policy {
ParallelPolicy::RequireAll => {
if failure_count > 0 {
debug!("Parallel (RequireAll): at least one child failed");
Ok(NodeStatus::Failure)
} else if success_count == self.children.len() {
debug!("Parallel (RequireAll): all children succeeded");
Ok(NodeStatus::Success)
} else {
Ok(NodeStatus::Running)
}
}
ParallelPolicy::RequireOne => {
if success_count > 0 {
debug!("Parallel (RequireOne): at least one child succeeded");
Ok(NodeStatus::Success)
} else if failure_count == self.children.len() {
debug!("Parallel (RequireOne): all children failed");
Ok(NodeStatus::Failure)
} else {
Ok(NodeStatus::Running)
}
}
ParallelPolicy::RequireN(n) => {
if success_count >= n {
debug!("Parallel (RequireN({})): {} children succeeded", n, success_count);
Ok(NodeStatus::Success)
} else if (self.children.len() - failure_count) < n {
debug!("Parallel (RequireN({})): not enough children can succeed", n);
Ok(NodeStatus::Failure)
} else {
Ok(NodeStatus::Running)
}
}
}
}
async fn reset(&mut self) -> anyhow::Result<()> {
for i in 0..self.children.len() {
self.child_statuses[i] = NodeStatus::Running;
self.children[i].reset().await?;
}
Ok(())
}
async fn on_init(&mut self, ctx: &Context) -> anyhow::Result<()> {
for child in &mut self.children {
child.on_init(ctx).await?;
}
Ok(())
}
async fn on_terminate(&mut self, ctx: &Context) -> anyhow::Result<()> {
for child in &mut self.children {
child.on_terminate(ctx).await?;
}
Ok(())
}
fn name(&self) -> &str {
"parallel"
}
}