Skip to content

Instantly share code, notes, and snippets.

@mizchi
Created April 10, 2018 03:56
Show Gist options
  • Save mizchi/d3cebad56eddd9dc88fc3a6bac6b1ab7 to your computer and use it in GitHub Desktop.
Save mizchi/d3cebad56eddd9dc88fc3a6bac6b1ab7 to your computer and use it in GitHub Desktop.
/* @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>
/* @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