mecha10_behavior_runtime/
composition.rs1use crate::{BehaviorNode, BoxedBehavior, NodeStatus};
6use async_trait::async_trait;
7use mecha10_core::Context;
8use tracing::{debug, warn};
9
10#[derive(Debug)]
38pub struct SequenceNode {
39 children: Vec<BoxedBehavior>,
40 current_index: usize,
41}
42
43impl SequenceNode {
44 pub fn new(children: Vec<BoxedBehavior>) -> Self {
46 Self {
47 children,
48 current_index: 0,
49 }
50 }
51
52 pub fn add_child(&mut self, child: BoxedBehavior) {
54 self.children.push(child);
55 }
56
57 pub fn len(&self) -> usize {
59 self.children.len()
60 }
61
62 pub fn is_empty(&self) -> bool {
64 self.children.is_empty()
65 }
66}
67
68#[async_trait]
69impl BehaviorNode for SequenceNode {
70 async fn tick(&mut self, ctx: &Context) -> anyhow::Result<NodeStatus> {
71 if self.children.is_empty() {
73 return Ok(NodeStatus::Success);
74 }
75
76 let total_children = self.children.len();
78 while self.current_index < total_children {
79 debug!(
80 "Sequence: ticking child {} of {}",
81 self.current_index + 1,
82 total_children
83 );
84
85 let child = &mut self.children[self.current_index];
86 match child.tick(ctx).await? {
87 NodeStatus::Success => {
88 self.current_index += 1;
90 }
91 NodeStatus::Failure => {
92 debug!("Sequence: child {} failed", self.current_index + 1);
94 return Ok(NodeStatus::Failure);
95 }
96 NodeStatus::Running => {
97 return Ok(NodeStatus::Running);
99 }
100 }
101 }
102
103 debug!("Sequence: all children succeeded");
105 Ok(NodeStatus::Success)
106 }
107
108 async fn reset(&mut self) -> anyhow::Result<()> {
109 self.current_index = 0;
110 for child in &mut self.children {
111 child.reset().await?;
112 }
113 Ok(())
114 }
115
116 fn name(&self) -> &str {
117 "sequence"
118 }
119
120 fn children_mut(&mut self) -> Vec<&mut dyn BehaviorNode> {
121 self.children
122 .iter_mut()
123 .map(|c| c.as_mut() as &mut dyn BehaviorNode)
124 .collect()
125 }
126}
127
128#[derive(Debug)]
156pub struct SelectOrNode {
157 children: Vec<BoxedBehavior>,
158 current_index: usize,
159}
160
161impl SelectOrNode {
162 pub fn new(children: Vec<BoxedBehavior>) -> Self {
164 Self {
165 children,
166 current_index: 0,
167 }
168 }
169
170 pub fn add_child(&mut self, child: BoxedBehavior) {
172 self.children.push(child);
173 }
174
175 pub fn len(&self) -> usize {
177 self.children.len()
178 }
179
180 pub fn is_empty(&self) -> bool {
182 self.children.is_empty()
183 }
184}
185
186#[async_trait]
187impl BehaviorNode for SelectOrNode {
188 async fn tick(&mut self, ctx: &Context) -> anyhow::Result<NodeStatus> {
189 if self.children.is_empty() {
191 return Ok(NodeStatus::Failure);
192 }
193
194 let total_children = self.children.len();
196 while self.current_index < total_children {
197 debug!(
198 "Selector: ticking child {} of {}",
199 self.current_index + 1,
200 total_children
201 );
202
203 let child = &mut self.children[self.current_index];
204 match child.tick(ctx).await? {
205 NodeStatus::Success => {
206 debug!("Selector: child {} succeeded", self.current_index + 1);
208 return Ok(NodeStatus::Success);
209 }
210 NodeStatus::Failure => {
211 warn!("Selector: child {} failed, trying next", self.current_index + 1);
213 self.current_index += 1;
214 }
215 NodeStatus::Running => {
216 return Ok(NodeStatus::Running);
218 }
219 }
220 }
221
222 debug!("Selector: all children failed");
224 Ok(NodeStatus::Failure)
225 }
226
227 async fn reset(&mut self) -> anyhow::Result<()> {
228 self.current_index = 0;
229 for child in &mut self.children {
230 child.reset().await?;
231 }
232 Ok(())
233 }
234
235 fn name(&self) -> &str {
236 "selector"
237 }
238
239 fn children_mut(&mut self) -> Vec<&mut dyn BehaviorNode> {
240 self.children
241 .iter_mut()
242 .map(|c| c.as_mut() as &mut dyn BehaviorNode)
243 .collect()
244 }
245}
246
247#[derive(Debug, Clone, Copy, PartialEq, Eq)]
253pub enum ParallelPolicy {
254 RequireAll,
256
257 RequireOne,
259
260 RequireN(usize),
262}
263
264#[derive(Debug)]
291pub struct ParallelNode {
292 children: Vec<BoxedBehavior>,
293 policy: ParallelPolicy,
294 child_statuses: Vec<NodeStatus>,
295}
296
297impl ParallelNode {
298 pub fn new(children: Vec<BoxedBehavior>, policy: ParallelPolicy) -> Self {
300 let child_statuses = vec![NodeStatus::Running; children.len()];
301 Self {
302 children,
303 policy,
304 child_statuses,
305 }
306 }
307
308 pub fn add_child(&mut self, child: BoxedBehavior) {
310 self.children.push(child);
311 self.child_statuses.push(NodeStatus::Running);
312 }
313
314 pub fn len(&self) -> usize {
316 self.children.len()
317 }
318
319 pub fn is_empty(&self) -> bool {
321 self.children.is_empty()
322 }
323}
324
325#[async_trait]
326impl BehaviorNode for ParallelNode {
327 async fn tick(&mut self, ctx: &Context) -> anyhow::Result<NodeStatus> {
328 if self.children.is_empty() {
330 return Ok(NodeStatus::Success);
331 }
332
333 for (i, child) in self.children.iter_mut().enumerate() {
335 if self.child_statuses[i].is_running() {
336 let status = child.tick(ctx).await?;
337 self.child_statuses[i] = status;
338 debug!("Parallel: child {} status: {}", i + 1, status);
339 }
340 }
341
342 let success_count = self.child_statuses.iter().filter(|s| s.is_success()).count();
344 let failure_count = self.child_statuses.iter().filter(|s| s.is_failure()).count();
345 let _running_count = self.child_statuses.iter().filter(|s| s.is_running()).count();
346
347 match self.policy {
348 ParallelPolicy::RequireAll => {
349 if failure_count > 0 {
350 debug!("Parallel (RequireAll): at least one child failed");
351 Ok(NodeStatus::Failure)
352 } else if success_count == self.children.len() {
353 debug!("Parallel (RequireAll): all children succeeded");
354 Ok(NodeStatus::Success)
355 } else {
356 Ok(NodeStatus::Running)
357 }
358 }
359 ParallelPolicy::RequireOne => {
360 if success_count > 0 {
361 debug!("Parallel (RequireOne): at least one child succeeded");
362 Ok(NodeStatus::Success)
363 } else if failure_count == self.children.len() {
364 debug!("Parallel (RequireOne): all children failed");
365 Ok(NodeStatus::Failure)
366 } else {
367 Ok(NodeStatus::Running)
368 }
369 }
370 ParallelPolicy::RequireN(n) => {
371 if success_count >= n {
372 debug!("Parallel (RequireN({})): {} children succeeded", n, success_count);
373 Ok(NodeStatus::Success)
374 } else if (self.children.len() - failure_count) < n {
375 debug!("Parallel (RequireN({})): not enough children can succeed", n);
377 Ok(NodeStatus::Failure)
378 } else {
379 Ok(NodeStatus::Running)
380 }
381 }
382 }
383 }
384
385 async fn reset(&mut self) -> anyhow::Result<()> {
386 for i in 0..self.children.len() {
387 self.child_statuses[i] = NodeStatus::Running;
388 self.children[i].reset().await?;
389 }
390 Ok(())
391 }
392
393 fn name(&self) -> &str {
394 "parallel"
395 }
396
397 fn children_mut(&mut self) -> Vec<&mut dyn BehaviorNode> {
398 self.children
399 .iter_mut()
400 .map(|c| c.as_mut() as &mut dyn BehaviorNode)
401 .collect()
402 }
403}