rewrite to use objects for data storage

This commit is contained in:
Paul Liverman III 2017-12-09 09:31:35 -08:00
parent 43e8048341
commit 6a61891ade
3 changed files with 347 additions and 298 deletions

View File

@ -84,11 +84,12 @@ after the entire tree has been processed.
## Decorator Nodes
Pass a single node to these, except for `Repeat`, which needs a number & a node.
All decorator nodes (except `RunOnce`) repeat after the entire tree has been
processed.
Pass a single node to these, except for `Repeat`, which needs a number followed
by a node. All decorator nodes (except `RunOnce`) repeat after the entire tree
has been processed.
- Repeat: Repeats a node a specified number of times, fails if the node fails.
- Decorator: Does nothing except return the result of its child node.
- Succeed: Runs a node and returns success.
- Fail: Runs a node and returns failure.
- Invert: Runs a node, reporting a success on fail, and failure on success.

View File

@ -17,23 +17,28 @@ local Node
do
local _class_0
local _base_0 = {
addObject = function(self, obj)
obj[self.u] = {
started = false
}
end,
run = function(self)
return success
end,
update = function(self, ...)
update = function(self, obj, ...)
local result = success
if not self.started and self.start then
result = self:start(...)
self.started = true
if not obj[self.u].started and self.start then
result = self:start(obj, ...)
obj[self.u].started = true
end
if result == success then
result = self:run(...)
result = self:run(obj, ...)
end
if result == success then
if self.finish then
result = self:finish(...)
result = self:finish(obj, ...)
end
self.started = false
obj[self.u].started = false
end
return result
end
@ -50,7 +55,7 @@ do
self.success = success
self.running = running
self.fail = fail
self.started = false
self.u = { }
end,
__base = _base_0,
__name = "Node"
@ -70,22 +75,28 @@ do
local _class_0
local _parent_0 = Node
local _base_0 = {
update = function(self, ...)
addObject = function(self, obj)
obj[self.u] = {
index = 0,
running = 0
}
end,
update = function(self, obj, ...)
local result = success
if self._running then
result = self._running:update(...)
if obj[self.u].running then
result = obj[self.u].running:update(obj, ...)
if not (result == running) then
self._running = false
obj[self.u].running = false
end
end
while result == success and self.index < #self.nodes do
self.index = self.index + 1
result = self.nodes[self.index]:update(...)
while result == success and obj[self.u].index < #self.nodes do
obj[self.u].index = obj[self.u].index + 1
result = self.nodes[obj[self.u].index]:update(obj, ...)
end
if result == running then
self._running = self.nodes[self.index]
obj[self.u].running = self.nodes[obj[self.u].index]
else
self.index = 0
obj[self.u].index = 0
end
return result
end
@ -98,9 +109,7 @@ do
nodes = { }
end
self.nodes = nodes
_class_0.__parent.__init(self)
self.index = 0
self._running = false
return _class_0.__parent.__init(self)
end,
__base = _base_0,
__name = "Sequence",
@ -134,22 +143,28 @@ do
local _class_0
local _parent_0 = Node
local _base_0 = {
update = function(self, ...)
addObject = function(self, obj)
obj[self.u] = {
index = 0,
running = 0
}
end,
update = function(self, obj, ...)
local result = fail
if self._running then
result = self._running:update(...)
if obj[self.u].running then
result = obj[self.u].running:update(obj, ...)
if not (result == running) then
self._running = false
obj[self.u].running = false
end
end
while result == fail and self.index < #self.nodes do
self.index = self.index + 1
result = self.nodes[self.index]:update(...)
while result == fail and obj[self.u].index < #self.nodes do
obj[self.u].index = obj[self.u].index + 1
result = self.nodes[obj[self.u].index]:update(obj, ...)
end
if result == running then
self._running = self.nodes[self.index]
obj[self.u].running = self.nodes[obj[self.u].index]
else
self.index = 0
obj[self.u].index = 0
end
return result
end
@ -162,9 +177,7 @@ do
nodes = { }
end
self.nodes = nodes
_class_0.__parent.__init(self)
self.index = 0
self._running = false
return _class_0.__parent.__init(self)
end,
__base = _base_0,
__name = "Selector",
@ -198,9 +211,9 @@ do
local _class_0
local _parent_0 = Node
local _base_0 = {
update = function(self, ...)
update = function(self, obj, ...)
local index = math.floor(math.random() * #self.nodes + 1)
return self.nodes[index]:update(...)
return self.nodes[index]:update(obj, ...)
end
}
_base_0.__index = _base_0
@ -240,40 +253,26 @@ do
end
Random = _class_0
end
local RandomSequence
local Randomizer
do
local _class_0
local _parent_0 = Node
local _base_0 = {
shuffle = function(self)
self._shuffled = { }
addObject = function(self, obj)
obj[self.u] = {
running = false
}
return self:shuffle(obj)
end,
shuffle = function(self, obj)
obj[self.u].shuffledNodes = { }
for i = 1, #self.nodes do
local r = math.random(i)
if not (r == i) then
self._shuffled[i] = self._shuffled[r]
obj[self.u].shuffledNodes[i] = obj[self.u].shuffledNodes[r]
end
self._shuffled[r] = self.nodes[i]
obj[self.u].shuffledNodes[r] = self.nodes[i]
end
end,
update = function(self, ...)
local result = success
if self._running then
result = self._running:update(...)
if not (result == running) then
self._running = false
end
end
local tmp
while result == success and #self._shuffled > 0 do
result = self._shuffled[1]:update(...)
tmp = table.remove(self._shuffled, 1)
end
if result == running then
self._running = tmp
else
self:shuffle()
end
return result
end
}
_base_0.__index = _base_0
@ -284,9 +283,66 @@ do
nodes = { }
end
self.nodes = nodes
_class_0.__parent.__init(self)
self._running = false
return self:shuffle()
return _class_0.__parent.__init(self)
end,
__base = _base_0,
__name = "Randomizer",
__parent = _parent_0
}, {
__index = function(cls, name)
local val = rawget(_base_0, name)
if val == nil then
local parent = rawget(cls, "__parent")
if parent then
return parent[name]
end
else
return val
end
end,
__call = function(cls, ...)
local _self_0 = setmetatable({}, _base_0)
cls.__init(_self_0, ...)
return _self_0
end
})
_base_0.__class = _class_0
if _parent_0.__inherited then
_parent_0.__inherited(_parent_0, _class_0)
end
Randomizer = _class_0
end
local RandomSequence
do
local _class_0
local _parent_0 = Randomizer
local _base_0 = {
update = function(self, obj, ...)
local result = success
if obj[self.u].running then
result = obj[self.u].running:update(obj, ...)
if not (result == running) then
obj[self.u].running = false
end
end
local tmp
while result == success and #obj[self.u].shuffledNodes > 0 do
result = obj[self.u].shuffledNodes[1]:update(obj, ...)
tmp = table.remove(obj[self.u].shuffledNodes, 1)
end
if result == running then
obj[self.u].running = tmp
else
self:shuffle(obj)
end
return result
end
}
_base_0.__index = _base_0
setmetatable(_base_0, _parent_0.__base)
_class_0 = setmetatable({
__init = function(self, ...)
return _class_0.__parent.__init(self, ...)
end,
__base = _base_0,
__name = "RandomSequence",
@ -318,33 +374,23 @@ end
local RandomSelector
do
local _class_0
local _parent_0 = Node
local _parent_0 = Randomizer
local _base_0 = {
shuffle = function(self)
self._shuffled = { }
for i = 1, #self.nodes do
local r = math.random(i)
if not (r == i) then
self._shuffled[i] = self._shuffled[r]
end
self._shuffled[r] = self.nodes[i]
end
end,
update = function(self, ...)
update = function(self, obj, ...)
local result = fail
if self._running then
result = self._running:update(...)
if obj[self.u].running then
result = obj[self.u].running:update(obj, ...)
if not (result == running) then
self._running = false
obj[self.u].running = false
end
end
local tmp
while result == fail and #self._shuffled > 0 do
result = self._shuffled[1]:update(...)
tmp = table.remove(self._shuffled, 1)
while result == fail and #obj[self.u].shuffledNodes > 0 do
result = obj[self.u].shuffledNodes[1]:update(obj, ...)
tmp = table.remove(obj[self.u].shuffledNodes, 1)
end
if result == running then
self._running = tmp
obj[self.u].running = tmp
else
self:shuffle()
end
@ -354,14 +400,8 @@ do
_base_0.__index = _base_0
setmetatable(_base_0, _parent_0.__base)
_class_0 = setmetatable({
__init = function(self, nodes)
if nodes == nil then
nodes = { }
end
self.nodes = nodes
_class_0.__parent.__init(self)
self._running = false
return self:shuffle()
__init = function(self, ...)
return _class_0.__parent.__init(self, ...)
end,
__base = _base_0,
__name = "RandomSelector",
@ -395,22 +435,28 @@ do
local _class_0
local _parent_0 = Node
local _base_0 = {
update = function(self, ...)
addObject = function(self, obj)
obj[self.u] = {
counter = 1,
running = false
}
end,
update = function(self, obj, ...)
local result = success
if self._running then
result = self.node:update(...)
if obj[self.u].running then
result = self.node:update(obj, ...)
if not (result == running) then
self._running = false
obj[self.u].running = false
end
end
while result == success and self.counter < self.cycles do
self.counter = self.counter + 1
result = self.node:update(...)
while result == success and obj[self.u].counter < self.cycles do
obj[self.u].counter = obj[self.u].counter + 1
result = self.node:update(obj, ...)
end
if result == running then
self._running = true
obj[self.u].running = true
else
self.counter = 1
obj[self.u].counter = 1
end
return result
end
@ -426,9 +472,7 @@ do
node = Node()
end
self.cycles, self.node = cycles, node
_class_0.__parent.__init(self)
self.counter = 1
self._running = false
return _class_0.__parent.__init(self)
end,
__base = _base_0,
__name = "Repeat",
@ -457,17 +501,13 @@ do
end
Repeat = _class_0
end
local Succeed
local Decorator
do
local _class_0
local _parent_0 = Node
local _base_0 = {
update = function(self, ...)
if running == self.node:update(...) then
return running
else
return success
end
update = function(self, obj, ...)
return self.node:update(obj, ...)
end
}
_base_0.__index = _base_0
@ -481,6 +521,52 @@ do
return _class_0.__parent.__init(self)
end,
__base = _base_0,
__name = "Decorator",
__parent = _parent_0
}, {
__index = function(cls, name)
local val = rawget(_base_0, name)
if val == nil then
local parent = rawget(cls, "__parent")
if parent then
return parent[name]
end
else
return val
end
end,
__call = function(cls, ...)
local _self_0 = setmetatable({}, _base_0)
cls.__init(_self_0, ...)
return _self_0
end
})
_base_0.__class = _class_0
if _parent_0.__inherited then
_parent_0.__inherited(_parent_0, _class_0)
end
Decorator = _class_0
end
local Succeed
do
local _class_0
local _parent_0 = Decorator
local _base_0 = {
update = function(self, obj, ...)
if running == self.node:update(obj, ...) then
return running
else
return success
end
end
}
_base_0.__index = _base_0
setmetatable(_base_0, _parent_0.__base)
_class_0 = setmetatable({
__init = function(self, ...)
return _class_0.__parent.__init(self, ...)
end,
__base = _base_0,
__name = "Succeed",
__parent = _parent_0
}, {
@ -510,10 +596,10 @@ end
local Fail
do
local _class_0
local _parent_0 = Node
local _parent_0 = Decorator
local _base_0 = {
update = function(self, ...)
if running == self.node:update(...) then
update = function(self, obj, ...)
if running == self.node:update(obj, ...) then
return running
else
return fail
@ -523,12 +609,8 @@ do
_base_0.__index = _base_0
setmetatable(_base_0, _parent_0.__base)
_class_0 = setmetatable({
__init = function(self, node)
if node == nil then
node = Node()
end
self.node = node
return _class_0.__parent.__init(self)
__init = function(self, ...)
return _class_0.__parent.__init(self, ...)
end,
__base = _base_0,
__name = "Fail",
@ -560,10 +642,10 @@ end
local Invert
do
local _class_0
local _parent_0 = Node
local _parent_0 = Decorator
local _base_0 = {
update = function(self, ...)
local result = self.node:update(...)
update = function(self, obj, ...)
local result = self.node:update(obj, ...)
if result == running then
return running
elseif result == success then
@ -576,12 +658,8 @@ do
_base_0.__index = _base_0
setmetatable(_base_0, _parent_0.__base)
_class_0 = setmetatable({
__init = function(self, node)
if node == nil then
node = Node()
end
self.node = node
return _class_0.__parent.__init(self)
__init = function(self, ...)
return _class_0.__parent.__init(self, ...)
end,
__base = _base_0,
__name = "Invert",
@ -613,13 +691,18 @@ end
local RunOnce
do
local _class_0
local _parent_0 = Node
local _parent_0 = Decorator
local _base_0 = {
update = function(self, ...)
if not (self.ran) then
local result = self.node:update(...)
addObject = function(self, obj)
obj[self.u] = {
ran = false
}
end,
update = function(self, obj, ...)
if not (obj[self.u].ran) then
local result = self.node:update(obj, ...)
if not (result == running) then
self.run = true
obj[self.u].ran = true
end
return result
else
@ -630,13 +713,8 @@ do
_base_0.__index = _base_0
setmetatable(_base_0, _parent_0.__base)
_class_0 = setmetatable({
__init = function(self, node)
if node == nil then
node = Node()
end
self.node = node
_class_0.__parent.__init(self)
self.ran = false
__init = function(self, ...)
return _class_0.__parent.__init(self, ...)
end,
__base = _base_0,
__name = "RunOnce",
@ -672,19 +750,19 @@ Class = function(name, parent)
__index = base,
__class = newClass
}
newClass = setmetable({
newClass = setmetatable({
__init = function() end,
__base = base,
__name = name
}, {
__call = function(cls, ...)
local self = setmetable({ }, base)
local self = setmetatable({ }, base)
cls.__init(self, ...)
return self
end
})
if parent then
setmetable(base, {
setmetatable(base, {
__parent = parent.__base
})
newClass.__parent = parent
@ -702,13 +780,14 @@ Class = function(name, parent)
end
return newClass, base
end
local behave = {
return setmetatable({
Node = Node,
Sequence = Sequence,
Selector = Selector,
Random = Random,
RandomSequence = RandomSequence,
RandomSelector = RandomSelector,
Decorator = Decorator,
Repeat = Repeat,
Succeed = Succeed,
Fail = Fail,
@ -718,24 +797,8 @@ local behave = {
running = running,
fail = fail,
Class = Class
}
behave.clone = function(object)
local new
local cls = getmetatable(object).__class.__name
if cls == "Repeat" then
new = behave[cls](object.cycles, object)
else
new = behave[cls](object)
}, {
__call = function(bt, ...)
return bt.Sequence(...)
end
if object.nodes then
local nodes = { }
for k, v in pairs(object.nodes) do
nodes[k] = behave.clone(v)
end
new.nodes = nodes
elseif object.node then
new.node = behave.clone(object.node)
end
return new
end
return behave
})

View File

@ -11,21 +11,26 @@ class Node
@running = running
@fail = fail
@started = false
@u = {}
addObject: (obj) =>
obj[@u] = {
started: false
}
run: =>
return success
update: (...) =>
update: (obj, ...) =>
result = success
if not @started and @start
result = @\start ...
@started = true
if not obj[@u].started and @start
result = @\start obj, ...
obj[@u].started = true
if result == success
result = @\run ...
result = @\run obj, ...
if result == success
result = @\finish(...) if @finish
@started = false
result = @\finish(obj, ...) if @finish
obj[@u].started = false
return result
-- Runs children in order until one returns fail, or all succeed.
@ -33,25 +38,28 @@ class Sequence extends Node
new: (@nodes={}) =>
super!
@index = 0
@_running = false
addObject: (obj) =>
obj[@u] = {
index: 0
running: 0
}
update: (...) =>
update: (obj, ...) =>
result = success
if @_running
result = @_running\update ...
if obj[@u].running
result = obj[@u].running\update obj, ...
unless result == running
@_running = false
obj[@u].running = false
while result == success and @index < #@nodes
@index += 1
result = @nodes[@index]\update ...
while result == success and obj[@u].index < #@nodes
obj[@u].index += 1
result = @nodes[obj[@u].index]\update obj, ...
if result == running
@_running = @nodes[@index]
obj[@u].running = @nodes[obj[@u].index]
else
@index = 0
obj[@u].index = 0
return result
@ -60,24 +68,27 @@ class Selector extends Node
new: (@nodes={}) =>
super!
@index = 0
@_running = false
addObject: (obj) =>
obj[@u] = {
index: 0
running: 0
}
update: (...) =>
update: (obj, ...) =>
result = fail
if @_running
result = @_running\update ...
if obj[@u].running
result = obj[@u].running\update obj, ...
unless result == running
@_running = false
obj[@u].running = false
while result == fail and @index < #@nodes
@index += 1
result = @nodes[@index]\update ...
while result == fail and obj[@u].index < #@nodes
obj[@u].index += 1
result = @nodes[obj[@u].index]\update obj, ...
if result == running
@_running = @nodes[@index]
obj[@u].running = @nodes[obj[@u].index]
else
@index = 0
obj[@u].index = 0
return result
@ -86,77 +97,67 @@ class Random extends Node
new: (@nodes={}) =>
super!
update: (...) =>
update: (obj, ...) =>
index = math.floor math.random! * #@nodes + 1
return @nodes[index]\update ...
return @nodes[index]\update obj, ...
-- Randomizes order of nodes in between complete runs of them as a Sequence.
class RandomSequence extends Node
class Randomizer extends Node
new: (@nodes={}) =>
super!
@_running = false
@shuffle!
addObject: (obj) =>
obj[@u] = {
running: false
}
@shuffle obj
shuffle: =>
@_shuffled = {}
shuffle: (obj) =>
obj[@u].shuffledNodes = {}
for i = 1, #@nodes
r = math.random i
unless r == i
@_shuffled[i] = @_shuffled[r]
@_shuffled[r] = @nodes[i]
obj[@u].shuffledNodes[i] = obj[@u].shuffledNodes[r]
obj[@u].shuffledNodes[r] = @nodes[i]
update: (...) =>
-- Randomizes order of nodes in between complete runs of them as a Sequence.
class RandomSequence extends Randomizer
update: (obj, ...) =>
result = success
if @_running
result = @_running\update ...
if obj[@u].running
result = obj[@u].running\update obj, ...
unless result == running
@_running = false
obj[@u].running = false
local tmp
while result == success and #@_shuffled > 0
result = @_shuffled[1]\update ...
tmp = table.remove @_shuffled, 1
while result == success and #obj[@u].shuffledNodes > 0
result = obj[@u].shuffledNodes[1]\update obj, ...
tmp = table.remove obj[@u].shuffledNodes, 1
if result == running
@_running = tmp
obj[@u].running = tmp
else
@shuffle!
@shuffle obj
return result
-- Randomizes order of nodes in between complete runs of them as a Selector.
class RandomSelector extends Node
new: (@nodes={}) =>
super!
@_running = false
@shuffle!
shuffle: =>
@_shuffled = {}
for i = 1, #@nodes
r = math.random i
unless r == i
@_shuffled[i] = @_shuffled[r]
@_shuffled[r] = @nodes[i]
update: (...) =>
class RandomSelector extends Randomizer
update: (obj, ...) =>
result = fail
if @_running
result = @_running\update ...
if obj[@u].running
result = obj[@u].running\update obj, ...
unless result == running
@_running = false
obj[@u].running = false
local tmp
while result == fail and #@_shuffled > 0
result = @_shuffled[1]\update ...
tmp = table.remove @_shuffled, 1
while result == fail and #obj[@u].shuffledNodes > 0
result = obj[@u].shuffledNodes[1]\update obj, ...
tmp = table.remove obj[@u].shuffledNodes, 1
if result == running
@_running = tmp
obj[@u].running = tmp
else
@shuffle!
@ -167,57 +168,58 @@ class Repeat extends Node
new: (@cycles=2, @node=Node!) =>
super!
@counter = 1
@_running = false
addObject: (obj) =>
obj[@u] = {
counter: 1
running: false
}
update: (...) =>
update: (obj, ...) =>
result = success
if @_running
result = @node\update ...
if obj[@u].running
result = @node\update obj, ...
unless result == running
@_running = false
obj[@u].running = false
while result == success and @counter < @cycles
@counter += 1
result = @node\update ...
while result == success and obj[@u].counter < @cycles
obj[@u].counter += 1
result = @node\update obj, ...
if result == running
@_running = true
obj[@u].running = true
else
@counter = 1
obj[@u].counter = 1
return result
-- Returns success whether or not the node succeeds.
class Succeed extends Node
class Decorator extends Node
new: (@node=Node!) =>
super!
update: (...) =>
if running == @node\update ...
update: (obj, ...) =>
return @node\update obj, ...
-- Returns success whether or not the node succeeds.
class Succeed extends Decorator
update: (obj, ...) =>
if running == @node\update obj, ...
return running
else
return success
-- Returns fail whether or not the node fails.
class Fail extends Node
new: (@node=Node!) =>
super!
update: (...) =>
if running == @node\update ...
class Fail extends Decorator
update: (obj, ...) =>
if running == @node\update obj, ...
return running
else
return fail
-- Returns success when the node fails, and failure on success.
class Invert extends Node
new: (@node=Node!) =>
super!
update: (...) =>
result = @node\update ...
class Invert extends Decorator
update: (obj, ...) =>
result = @node\update obj, ...
if result == running
return running
elseif result == success
@ -226,17 +228,17 @@ class Invert extends Node
return success
-- Only runs children once, and returns fail from then on.
class RunOnce extends Node
new: (@node=Node!) =>
super!
class RunOnce extends Decorator
addObject: (obj) =>
obj[@u] = {
ran: false
}
@ran = false
update: (...) =>
unless @ran
result = @node\update ...
update: (obj, ...) =>
unless obj[@u].ran
result = @node\update obj, ...
unless result == running
@run = true
obj[@u].ran = true
return result
else
return fail
@ -249,19 +251,19 @@ Class = (name, parent) ->
__class: newClass
}
newClass = setmetable {
newClass = setmetatable {
__init: ->
__base: base
__name: name
}, {
__call: (cls, ...) ->
@ = setmetable({}, base)
@ = setmetatable({}, base)
cls.__init(@, ...)
return @
}
if parent
setmetable base, {
setmetatable base, {
__parent: parent.__base
}
@ -278,7 +280,7 @@ Class = (name, parent) ->
return newClass, base
behave = {
setmetatable {
-- Leaf Node
:Node
@ -290,6 +292,7 @@ behave = {
:RandomSelector
-- Decorator Nodes
:Decorator
:Repeat
:Succeed
:Fail
@ -303,25 +306,7 @@ behave = {
-- Utility Fns
:Class
}, {
__call: (bt, ...) ->
bt.Sequence ...
}
behave.clone = (object) ->
local new
cls = getmetatable(object).__class.__name
if cls == "Repeat"
new = behave[cls] object.cycles, object
else
new = behave[cls] object
if object.nodes
nodes = {}
for k,v in pairs object.nodes
nodes[k] = behave.clone v
new.nodes = nodes
elseif object.node
new.node = behave.clone object.node
return new
return behave