Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix forever while loop (WIP) #49

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/behavior.rs
Expand Up @@ -4,7 +4,7 @@ use input::Button;
///
/// This is used for more complex event logic.
/// Can also be used for game AI.
#[derive(Clone, RustcDecodable, RustcEncodable, PartialEq)]
#[derive(Clone, Debug, RustcDecodable, RustcEncodable, PartialEq)]
pub enum Behavior<A> {
/// A button was pressed.
Pressed(Button),
Expand Down
5 changes: 4 additions & 1 deletion src/state.rs
Expand Up @@ -49,6 +49,7 @@ use state::State::{
pub const RUNNING: (Status, f64) = (Running, 0.0);

/// The arguments in the action callback.
#[derive(Debug)]
pub struct ActionArgs<'a, E: 'a, A: 'a, S: 'a> {
/// The event.
pub event: &'a E,
Expand All @@ -61,7 +62,7 @@ pub struct ActionArgs<'a, E: 'a, A: 'a, S: 'a> {
}

/// Keeps track of a behavior.
#[derive(Clone, RustcDecodable, RustcEncodable, PartialEq)]
#[derive(Clone, Debug, RustcDecodable, RustcEncodable, PartialEq)]
pub enum State<A, S> {
/// Returns `Success` when button is pressed.
PressedState(input::Button),
Expand Down Expand Up @@ -167,6 +168,7 @@ fn sequence<A, S, E, F>(
// Create a new cursor for next event.
// Use the same pointer to avoid allocation.
**cursor = State::new(seq[*i].clone());
if remaining_dt == 0.0 { break }
}
RUNNING
}
Expand Down Expand Up @@ -424,6 +426,7 @@ impl<A: Clone, S> State<A, S> {
// Create a new cursor for next event.
// Use the same pointer to avoid allocation.
**cur = State::new(rep[*i].clone());
if remaining_dt == 0.0 { break }
}
RUNNING
}
Expand Down
82 changes: 67 additions & 15 deletions tests/test_events.rs
Expand Up @@ -6,14 +6,15 @@ use ai_behavior::{
Sequence,
Success,
Wait,
WaitForever,
WhenAll,
While,
};

use test_events::TestActions::{ Inc, Dec };

/// Some test actions.
#[derive(Clone)]
#[derive(Clone, Debug)]
pub enum TestActions {
/// Increment accumulator.
Inc,
Expand All @@ -22,13 +23,14 @@ pub enum TestActions {
}

// A test state machine that can increment and decrement.
fn exec(mut acc: u32, dt: f64, state: &mut State<TestActions, ()>) -> u32 {
fn exec(mut acc: u32, dt: f64, state: &mut State<TestActions, ()>, all_time: bool) -> u32 {
let e: Event = Update(UpdateArgs { dt: dt });
state.event(&e, &mut |args| {
match *args.action {
Inc => { acc += 1; (Success, args.dt) },
Dec => { acc -= 1; (Success, args.dt) },
Inc => acc += 1,
Dec => acc -= 1,
}
(Success, if all_time { 0.0 } else { args.dt })
});
acc
}
Expand All @@ -37,37 +39,43 @@ fn exec(mut acc: u32, dt: f64, state: &mut State<TestActions, ()>) -> u32 {
// consumes a time of 0.0 seconds.
// This makes it possible to execute one action
// after another without delay or waiting for next update.
// so long as there is time remaining.
#[test]
fn print_2() {
let a: u32 = 0;
let seq = Sequence(vec![Action(Inc), Action(Inc)]);
let mut state = State::new(seq);
let a = exec(a, 0.0, &mut state);
let a = exec(a, 0.1, &mut state, false);
assert_eq!(a, 2);
}

// If you wait the exact amount before to execute an action,
// it will execute. This behavior makes it easy to predict
// it will not execute. There must be time remaining
// for the action to run. This behavior makes it easy to predict
// when an action will run.
#[test]
fn wait_sec() {
let a: u32 = 0;
let seq = Sequence(vec![Wait(1.0), Action(Inc)]);
let mut state = State::new(seq);
let a = exec(a, 1.0, &mut state);
let a = exec(a, 1.0, &mut state, false);
assert_eq!(a, 0);
let a = exec(a, 1.0, &mut state, false);
assert_eq!(a, 1);
}

// When we execute half the time and then the other half,
// then the action should be executed.
// then give some time then the action should be executed.
#[test]
fn wait_half_sec() {
let a: u32 = 0;
let seq = Sequence(vec![Wait(1.0), Action(Inc)]);
let mut state = State::new(seq);
let a = exec(a, 0.5, &mut state);
let a = exec(a, 0.5, &mut state, false);
assert_eq!(a, 0);
let a = exec(a, 0.5, &mut state, false);
assert_eq!(a, 0);
let a = exec(a, 0.5, &mut state);
let a = exec(a, 0.5, &mut state, false);
assert_eq!(a, 1);
}

Expand All @@ -77,7 +85,7 @@ fn sequence_of_one_event() {
let a: u32 = 0;
let seq = Sequence(vec![Action(Inc)]);
let mut state = State::new(seq);
let a = exec(a, 1.0, &mut state);
let a = exec(a, 1.0, &mut state, false);
assert_eq!(a, 1);
}

Expand All @@ -87,7 +95,9 @@ fn wait_two_waits() {
let a: u32 = 0;
let seq = Sequence(vec![Wait(0.5), Wait(0.5), Action(Inc)]);
let mut state = State::new(seq);
let a = exec(a, 1.0, &mut state);
let a = exec(a, 1.0, &mut state, false);
assert_eq!(a, 0);
let a = exec(a, 1.0, &mut state, false);
assert_eq!(a, 1);
}

Expand All @@ -97,10 +107,50 @@ fn loop_ten_times() {
let a: u32 = 0;
let rep = While(Box::new(Wait(50.0)), vec![Wait(0.5), Action(Inc), Wait(0.5)]);
let mut state = State::new(rep);
let a = exec(a, 10.0, &mut state);
let a = exec(a, 10.0, &mut state, false);
assert_eq!(a, 10);
}

// Increase counter once using all available time
#[test]
fn all_time() {
let a: u32 = 0;
let rep = While(Box::new(WaitForever), vec![Action(Inc)]);
let mut state = State::new(rep);
let a = exec(a, 10.0, &mut state, true);
assert_eq!(a, 1);
}

// Increase then decrease counter using all available time
#[test]
fn all_time_twice() {
let a: u32 = 0;
let rep = While(Box::new(WaitForever), vec![Action(Inc), Action(Dec)]);
let mut state = State::new(rep);
let a = exec(a, 10.0, &mut state, true);
assert_eq!(a, 1);
let a = exec(a, 10.0, &mut state, true);
assert_eq!(a, 0);
}

// Increase then decrease counter using all available time inside a sequence
#[test]
fn all_time_sequence() {
let a: u32 = 0;
let rep = While(Box::new(WaitForever), vec![Sequence(vec![Action(Inc), Action(Dec)])]);
let mut state = State::new(rep);
let a = exec(a, 10.0, &mut state, true);
assert_eq!(a, 1);
let a = exec(a, 10.0, &mut state, true);
assert_eq!(a, 0);
let a = exec(a, 10.0, &mut state, true);
assert_eq!(a, 1);
let a = exec(a, 10.0, &mut state, true);
assert_eq!(a, 0);
}

// two waits in parallel is the same as one wait
// of the longest wait.
#[test]
fn when_all_wait() {
let a: u32 = 0;
Expand All @@ -110,8 +160,10 @@ fn when_all_wait() {
Action(Inc)
]);
let mut state = State::new(all);
let a = exec(a, 0.5, &mut state);
let a = exec(a, 0.5, &mut state, false);
assert_eq!(a, 0);
let a = exec(a, 0.5, &mut state, false);
assert_eq!(a, 0);
let a = exec(a, 0.5, &mut state);
let a = exec(a, 0.5, &mut state, false);
assert_eq!(a, 1);
}