big-brain 0.22.0

Rusty Utility AI library
Documentation
use bevy::{app::AppExit, prelude::*};
use big_brain::{pickers, prelude::*};

#[test]
fn steps() {
    println!("steps test");
    App::new()
        .add_plugins((MinimalPlugins, BigBrainPlugin::new(PreUpdate)))
        .init_resource::<GlobalState>()
        .add_systems(Startup, setup)
        .add_systems(Update, no_failure_score.before(BigBrainSet::Scorers))
        .add_systems(
            PreUpdate,
            (action1, action2, exit_action, failure_action).in_set(BigBrainSet::Actions),
        )
        .add_systems(Last, last.before(BigBrainSet::Cleanup))
        .run();
    println!("end");
}

fn setup(mut cmds: Commands) {
    cmds.spawn_empty().insert(
        Thinker::build()
            .picker(pickers::FirstToScore::new(0.5))
            .when(NoFailureScore, Steps::build().step(FailureAction))
            .otherwise(Steps::build().step(Action1).step(Action2).step(ExitAction)),
    );
}

#[derive(Clone, Component, Debug, ActionBuilder)]
struct Action1;

fn action1(mut query: Query<(&Actor, &mut ActionState), With<Action1>>) {
    for (Actor(_actor), mut state) in query.iter_mut() {
        println!("action1 {state:?}");
        if *state == ActionState::Requested {
            *state = ActionState::Executing;
        }
        if *state == ActionState::Executing {
            *state = ActionState::Success;
        }
    }
}

#[derive(Clone, Component, Debug, ActionBuilder)]
struct Action2;

fn action2(mut query: Query<(&Actor, &mut ActionState), With<Action2>>) {
    for (Actor(_actor), mut state) in query.iter_mut() {
        println!("action2 {state:?}");
        if *state == ActionState::Requested {
            *state = ActionState::Executing;
        }
        if *state == ActionState::Executing {
            *state = ActionState::Success;
        }
    }
}

#[derive(Clone, Component, Debug, Default, ActionBuilder)]
struct ExitAction;

fn exit_action(
    mut query: Query<(&Actor, &mut ActionState), With<ExitAction>>,
    mut app_exit_events: EventWriter<AppExit>,
) {
    for (Actor(_actor), mut state) in query.iter_mut() {
        println!("exit_action {state:?}");
        if *state == ActionState::Requested {
            *state = ActionState::Executing;
        }
        if *state == ActionState::Executing {
            app_exit_events.send(AppExit::Success);
        }
    }
}

fn last() {
    println!();
}

#[derive(Clone, Component, Debug, Default, ActionBuilder)]
struct FailureAction;

fn failure_action(
    mut query: Query<(&Actor, &mut ActionState), With<FailureAction>>,
    mut global_state: ResMut<GlobalState>,
) {
    for (Actor(_actor), mut state) in query.iter_mut() {
        println!("failure_action {state:?}");
        if *state == ActionState::Requested {
            *state = ActionState::Executing;
        }
        if *state == ActionState::Executing {
            global_state.failure = true;
            *state = ActionState::Failure;
        }
    }
}

#[derive(Default, Resource)]
struct GlobalState {
    failure: bool,
}

#[derive(Clone, Component, Debug, ScorerBuilder)]
struct NoFailureScore;

fn no_failure_score(
    mut query: Query<(&NoFailureScore, &mut Score)>,
    global_state: Res<GlobalState>,
) {
    for (_, mut score) in query.iter_mut() {
        score.set(if global_state.failure { 0.0 } else { 1.0 });
    }
}