Created
April 10, 2018 03:56
-
-
Save mizchi/d3cebad56eddd9dc88fc3a6bac6b1ab7 to your computer and use it in GitHub Desktop.
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
/* @flow */ | |
type Result<T> = { | |
result: boolean, | |
payload: T | |
} | |
type Conditional<T> = { | |
type: 'conditional', | |
exec(T): Result<T> | |
} | |
type Action<T> = { | |
type: 'action', | |
exec(T): Result<T> | |
} | |
type Sequence<T> = { | |
type: 'sequence', | |
children: Node<T>[] | |
} | |
type Selector<T> = { | |
type: 'selector', | |
children: Node<T>[] | |
} | |
type Decorator<T> = { | |
type: 'decorator', | |
decorator: (Result<T>) => Result<T>, | |
child: Node<T> | |
} | |
export type Node<T> = | |
| Selector<T> | |
| Action<T> | |
| Conditional<T> | |
| Sequence<T> | |
| Decorator<T> | |
export function update<T>(node: Node<T>, state: T): Result<T> { | |
switch (node.type) { | |
case 'action': { | |
return node.exec(state) | |
} | |
case 'conditional': { | |
return node.exec(state) | |
} | |
case 'decorator': { | |
return node.decorator(update(node.child, state)) | |
} | |
case 'sequence': { | |
let newState = state | |
for (const child of node.children) { | |
const { result, payload } = update(child, newState) | |
if (result) { | |
newState = payload | |
continue | |
} else { | |
return { | |
result: false, | |
payload | |
} | |
} | |
} | |
return { | |
result: true, | |
payload: newState | |
} | |
} | |
case 'selector': { | |
let newState = state | |
let once = false | |
for (const child of node.children) { | |
const { result, payload } = update(child, newState) | |
if (result) { | |
once = true | |
newState = payload | |
break | |
} else { | |
continue | |
} | |
} | |
return { | |
result: once, | |
payload: newState | |
} | |
} | |
default: { | |
return { | |
result: true, | |
payload: state | |
} | |
} | |
} | |
} | |
export type BehaviorTree<T> = Node<T> |
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
/* @flow */ | |
import { update, type BehaviorTree } from './behavior-tree' | |
type Counter = { | |
value: number | |
} | |
const b = { | |
selector: children => ({ type: 'selector', children }), | |
sequence: children => ({ type: 'sequence', children }), | |
conditional: fn => ({ | |
type: 'conditional', | |
exec: state => ({ result: fn(state), payload: state }) | |
}), | |
action: fn => ({ | |
type: 'action', | |
exec: state => ({ result: true, payload: fn(state) }) | |
}) | |
} | |
const tree: BehaviorTree<Counter> = b.selector([ | |
b.sequence([ | |
b.conditional(state => state.value % 2 === 1), | |
b.action(state => ({ | |
value: state.value + 1 | |
})), | |
b.conditional(state => state.value % 2 === 0) | |
]), | |
b.sequence([ | |
b.conditional(state => state.value % 2 === 0), | |
b.action(state => ({ | |
value: state.value + 5 | |
})) | |
]) | |
]) | |
const ret = update(tree, { value: 3 }) | |
console.log(ret) // => 4 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment