LOXMWV3OSAWZFCORHIBGHMCI4OTDQPNYD4CREMLLXIBO24AUI7OQC
// Utilities for testing
#[cfg(test)]
mod tests {
use crate::simple_bt::BehaviorRunner;
pub(super) struct Context {
pub stack: Vec<i32>,
}
pub(super) fn test_with_context<F>(
init_context: F,
mut runner: BehaviorRunner<Context>,
running_limit: usize,
) -> (Option<bool>, Context)
where
F: FnOnce() -> Context,
{
let mut context = init_context();
let mut running_count = 0;
let mut res = None;
while res.is_none() {
if running_count >= running_limit {
return (None, context);
}
res = runner.proceed(&mut context);
if res.is_none() {
running_count += 1;
}
}
(res, context)
}
}
}
}
}
#[derive(Debug)]
struct TwoStepPush {
payload: i32,
fail: bool,
step: usize,
}
impl BehaviorNode<Context> for TwoStepPush {
fn tick(&self, context: &mut Context) -> NodeResult<Context> {
if self.step < 1 {
NodeResult::Running(
Self {
payload: self.payload,
fail: self.fail,
step: self.step + 1,
}
.arc(),
)
} else {
context.stack.push(self.payload);
if self.fail {
NodeResult::Failure
} else {
NodeResult::Success
}
fn sequence_resumes_after_tried_node() {
let runner = BehaviorRunner::new(
vec![
TwoStepPush {
payload: 1,
fail: false,
step: 0,
}
.arc(),
TwoStepPush {
payload: 2,
fail: false,
step: 0,
}
.arc(),
]
.into_iter()
.collect::<Sequence<_>>()
.arc(),
);
let (res, context) = test_with_context(|| Context { stack: Vec::new() }, runner, 10);
check!(res == Some(true));
check!(context.stack == vec![1, 2]);
}
#[test]
mod tests {}
mod tests {
use assert2::check;
use super::*;
use crate::simple_bt::{
composite::tests::{test_with_context, Context},
BehaviorNode, BehaviorRunner, NodeResult,
};
#[derive(Debug)]
struct TwoStepPush {
payload: i32,
fail: bool,
step: usize,
}
impl BehaviorNode<Context> for TwoStepPush {
fn tick(&self, context: &mut Context) -> NodeResult<Context> {
if self.step < 1 {
NodeResult::Running(
Self {
payload: self.payload,
fail: self.fail,
step: self.step + 1,
}
.arc(),
)
} else {
context.stack.push(self.payload);
if self.fail {
NodeResult::Failure
} else {
NodeResult::Success
}
}
}
}
#[test]
fn selector_skips_tried_node() {
let runner = BehaviorRunner::new(
vec![
TwoStepPush {
payload: 1,
fail: true,
step: 0,
}
.arc(),
TwoStepPush {
payload: 2,
fail: false,
step: 0,
}
.arc(),
]
.into_iter()
.collect::<Selector<_>>()
.arc(),
);
let (res, context) = test_with_context(|| Context { stack: Vec::new() }, runner, 10);
check!(res == Some(true));
check!(context.stack == vec![1, 2]);
}
}
match resume.tick(blackboard) {
NodeResult::Running(resume) => {
return NodeResult::Running(
Self {
resume: Some(resume),
child: self.child.clone(),
}
.arc(),
)
}
_ => {}
}
}
match self.child.tick(blackboard) {
NodeResult::Running(resume) => {
if let NodeResult::Running(resume) = resume.tick(blackboard) {
todo!()
let mut completed = self.completed;
if completed >= self.limit {
return NodeResult::Success;
}
if let Some(resume) = self.resume.as_ref() {
match resume.tick(blackboard) {
NodeResult::Running(resume) => {
return NodeResult::Running(
Self {
resume: Some(resume),
child: self.child.clone(),
limit: self.limit,
completed: self.completed,
}
.arc(),
)
}
_ => {
completed += 1;
}
}
}
match self.child.tick(blackboard) {
NodeResult::Running(resume) => {
return NodeResult::Running(
Self {
resume: Some(resume),
child: self.child.clone(),
limit: self.limit,
completed,
}
.arc(),
)
}
_ => {
completed += 1;
}
}
// Restart until we've completed the repetitions
NodeResult::Running(Arc::new(Self {
child: self.child.clone(),
resume: None,
limit: self.limit,
completed,
}))
todo!()
if let Some(resume) = self.resume.as_ref() {
match resume.tick(blackboard) {
NodeResult::Running(resume) => {
return NodeResult::Running(
Self {
resume: Some(resume),
child: self.child.clone(),
}
.arc(),
);
}
NodeResult::Failure => return NodeResult::Success,
_ => (),
}
}
match self.child.tick(blackboard) {
NodeResult::Running(resume) => NodeResult::Running(
Self {
resume: Some(resume),
child: self.child.clone(),
}
.arc(),
),
NodeResult::Success => {
// Restart whenever we succeed
NodeResult::Running(Arc::new(Self {
child: self.child.clone(),
resume: None,
}))
}
NodeResult::Failure => {
// We have encounted a failure, so *succeed*
NodeResult::Success
}
}
mod tests {}
mod tests {
use crate::simple_bt::{
composite::{
tests::{test_with_context, Context},
Sequence,
},
BehaviorRunner,
};
use super::*;
use assert2::check;
#[derive(Debug)]
struct Push1;
impl BehaviorNode<Context> for Push1 {
fn tick(&self, context: &mut Context) -> NodeResult<Context> {
context.stack.push(1);
NodeResult::Success
}
}
#[derive(Debug)]
struct FibPush;
impl BehaviorNode<Context> for FibPush {
fn tick(&self, context: &mut Context) -> NodeResult<Context> {
if context.stack.len() < 2 {
context.stack.push(1);
} else {
let len = context.stack.len();
let a = context.stack[len - 2];
let b = context.stack[len - 1];
context.stack.push(a + b);
}
NodeResult::Success
}
}
#[derive(Debug)]
struct IsCapped {
cap: i32,
}
impl BehaviorNode<Context> for IsCapped {
fn tick(&self, context: &mut Context) -> NodeResult<Context> {
if context.stack.iter().any(|v| *v > self.cap) {
NodeResult::Failure
} else {
NodeResult::Success
}
}
}
#[test]
fn limited_repeat_repeats_to_limit() {
let runner = BehaviorRunner::new(LimitedRepeated::new(3, Push1.arc()).arc());
let (res, context) = test_with_context(|| Context { stack: Vec::new() }, runner, 4);
check!(res == Some(true));
check!(context.stack == vec![1, 1, 1]);
}
#[test]
fn repeat_until_failure_stops_on_failure() {
let runner = BehaviorRunner::new(
RepeatedUntilFailure::new(
vec![FibPush.arc(), IsCapped { cap: 100 }.arc()]
.into_iter()
.collect::<Sequence<_>>()
.arc(),
)
.arc(),
);
let (res, context) = test_with_context(|| Context { stack: Vec::new() }, runner, 12);
check!(res == Some(true));
check!(context.stack == vec![1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144]);
}
}
mod tests {}
mod tests {
use assert2::check;
use super::*;
use crate::simple_bt::{
composite::{
tests::{test_with_context, Context},
Succeeder,
},
BehaviorNode, BehaviorRunner, NodeResult,
};
#[derive(Debug)]
struct SucceedAfterSteps {
steps: u32,
step: u32,
}
impl SucceedAfterSteps {
fn new(steps: u32) -> Self {
Self { steps, step: 0 }
}
}
impl BehaviorNode<Context> for SucceedAfterSteps {
fn tick(&self, _context: &mut Context) -> crate::simple_bt::NodeResult<Context> {
if self.step < self.steps {
NodeResult::Running(
Self {
steps: self.steps,
step: self.step + 1,
}
.arc(),
)
} else {
NodeResult::Success
}
}
}
#[test]
fn inverter_inverts_properly() {
let runner1 =
BehaviorRunner::new(Inverter::<Context>::new(Succeeder::default().arc()).arc());
let (res, context) = test_with_context(|| Context { stack: Vec::new() }, runner1, 1);
check!(res == Some(false));
check!(context.stack == Vec::<i32>::new());
let runner2 = BehaviorRunner::new(Inverter::new(SucceedAfterSteps::new(9).arc()).arc());
let (res, context) = test_with_context(|| Context { stack: Vec::new() }, runner2, 10);
check!(res == Some(false));
check!(context.stack == Vec::<i32>::new());
}
}