use crate::simple_bt::{BehaviorArc, BehaviorNode, NodeResult};
use std::sync::Arc;
pub struct Selector<B> {
pub(crate) sub: Arc<[BehaviorArc<B>]>,
}
impl<B> std::fmt::Debug for Selector<B> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct(&format!("Selector<{:p}>", self.sub.as_ref()))
.field("sub", &self.sub)
.finish()
}
}
impl<B, I: Into<BehaviorArc<B>>> FromIterator<I> for Selector<B> {
fn from_iter<T: IntoIterator<Item = I>>(iter: T) -> Self {
Self {
sub: Arc::from(iter.into_iter().map(Into::into).collect::<Vec<_>>()),
}
}
}
impl<B: 'static> Selector<B> {
pub(crate) fn resume(
seq: Arc<[BehaviorArc<B>]>,
index: usize,
resume: BehaviorArc<B>,
) -> BehaviorArc<B> {
SelectorResume { seq, resume, index }.arc()
}
}
impl<B: 'static> BehaviorNode<B> for Selector<B> {
fn tick(&self, blackboard: &mut B) -> NodeResult<B> {
for (idx, sub) in self.sub.iter().enumerate() {
match sub.tick(blackboard) {
NodeResult::Failure => {}
NodeResult::Success => return NodeResult::Success,
NodeResult::Running(resume) => {
return NodeResult::Running(Self::resume(self.sub.clone(), idx, resume))
}
}
}
NodeResult::Failure
}
}
pub(crate) struct SelectorResume<B> {
pub(crate) seq: Arc<[BehaviorArc<B>]>,
pub(crate) resume: BehaviorArc<B>,
pub(crate) index: usize,
}
impl<B> std::fmt::Debug for SelectorResume<B> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct(&format!("SelectorResume<{:p}>", self.seq.as_ref()))
.field("resume", &self.resume)
.field("index", &self.index)
.finish_non_exhaustive()
}
}
impl<B: 'static> BehaviorNode<B> for SelectorResume<B> {
fn tick(&self, blackboard: &mut B) -> NodeResult<B> {
match self.resume.tick(blackboard) {
NodeResult::Failure => {}
NodeResult::Success => return NodeResult::Success,
NodeResult::Running(resume) => {
return NodeResult::Running(Selector::resume(self.seq.clone(), self.index, resume))
}
}
for (idx, sub) in self.seq.iter().enumerate().skip(self.index) {
match sub.tick(blackboard) {
NodeResult::Failure => {}
NodeResult::Success => return NodeResult::Success,
NodeResult::Running(resume) => {
return NodeResult::Running(Selector::resume(self.seq.clone(), idx, resume))
}
}
}
NodeResult::Failure
}
}
#[cfg(test)]
mod tests {}