Created
September 13, 2015 15:41
-
-
Save sethhoward/c26a29ee4770a900b57c to your computer and use it in GitHub Desktop.
Basic behavior tree implementation. Meant to be run in a playground.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
enum OperationState { | |
case Invalid | |
case Ready | |
case Executing | |
case Finished | |
} | |
enum OperationResult { | |
case Success | |
case Failure | |
} | |
protocol Behaves: class { | |
func main() | |
var completion: ((OperationResult) -> ())? { get set } | |
var state: OperationState { get set } | |
} | |
extension Behaves { | |
func initialize() { // use to reset state/set up behavior | |
state = .Ready | |
} | |
func execute() { | |
guard state != .Executing else { | |
return | |
} | |
if state != .Ready { | |
initialize() | |
} | |
state = .Executing | |
main() | |
} | |
func onCompletion(result: OperationResult) { | |
state = .Finished | |
completion?(result) | |
} | |
} | |
/** | |
Goes until fail... if anything fails it all fails. If all succeeds then the sequence return success. | |
*/ | |
final class Sequence: Behaves { | |
var completion: ((OperationResult) -> ())? | |
var state: OperationState = .Invalid | |
private var behaviors: [Behaves] | |
init(behaviors: [Behaves]) { | |
self.behaviors = behaviors | |
} | |
func main() { | |
runBehavior(0) | |
} | |
func runBehavior(var index: Int) { | |
guard index < behaviors.count else { | |
onCompletion(.Success) | |
return | |
} | |
behaviors[index].completion = { | |
[weak self] result in | |
guard let weakSelf = self else { | |
return | |
} | |
switch result { | |
case .Success: | |
index++ | |
weakSelf.runBehavior(index) | |
case .Failure: | |
weakSelf.onCompletion(.Failure) | |
} | |
} | |
behaviors[index].execute() | |
} | |
} | |
/** | |
Find one Success case and return. If there are no successes then selector fails. | |
*/ | |
final class Selector: Behaves { | |
var completion: ((OperationResult) -> ())? | |
var state: OperationState = .Invalid | |
private var behaviors: [Behaves] | |
init(behaviors: [Behaves]) { | |
self.behaviors = behaviors | |
} | |
func main() { | |
runBehavior(0) | |
} | |
func runBehavior(var index: Int) { | |
guard index < behaviors.count else { | |
onCompletion(.Failure) | |
return | |
} | |
behaviors[index].completion = { | |
[weak self] result in | |
guard let weakSelf = self else { | |
return | |
} | |
switch result { | |
case .Success: | |
weakSelf.onCompletion(.Success) | |
case .Failure: | |
index++ | |
weakSelf.runBehavior(index) | |
} | |
} | |
behaviors[index].execute() | |
} | |
} | |
// 🌳🌳Generic Test Behaviors🌳🌳 | |
final class MyBehavior: Behaves { | |
var completion: ((OperationResult) -> ())? | |
var state: OperationState = .Invalid | |
func main() { | |
"Actual Worker Block" | |
for var i = 0; i < 5; i++ { | |
sleep(1) | |
print(i) | |
} | |
onCompletion(.Success) | |
} | |
} | |
final class MyBadBehavior: Behaves { | |
var completion: ((OperationResult) -> ())? | |
var state: OperationState = .Invalid | |
func main() { | |
"Actual Worker Block" | |
for var i = 0; i < 5; i++ { | |
sleep(1) | |
print(i) | |
} | |
onCompletion(.Failure) | |
} | |
} | |
let sequence = Sequence(behaviors: [MyBehavior(), MyBehavior(), MyBadBehavior(), MyBehavior()]) | |
sequence.completion = { | |
result in | |
switch result { | |
case .Success: | |
"success" | |
case .Failure: | |
"failure" | |
} | |
} | |
//sequence.execute() | |
let selector = Selector(behaviors: [MyBadBehavior(), MyBadBehavior(), sequence]) | |
selector.completion = { | |
result in | |
switch result { | |
case .Success: | |
"success" | |
case .Failure: | |
"failure" | |
} | |
} | |
selector.execute() //tree will fail |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment