Skip to content

Instantly share code, notes, and snippets.

@sethhoward
Created September 13, 2015 15:41
Show Gist options
  • Save sethhoward/c26a29ee4770a900b57c to your computer and use it in GitHub Desktop.
Save sethhoward/c26a29ee4770a900b57c to your computer and use it in GitHub Desktop.
Basic behavior tree implementation. Meant to be run in a playground.
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