behaviortree 1.0 → 2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README +2 -41
- data/Rakefile +1 -1
- data/behaviortree.gemspec +2 -2
- data/lib/behaviortree.rb +3 -1
- data/lib/behaviortree/behaviortree.rb +5 -40
- metadata +3 -3
data/README
CHANGED
@@ -7,45 +7,6 @@ http://aigamedev.com/open/articles/bt-overview/
|
|
7
7
|
http://aigamedev.com/open/articles/behavior-trees-part1/
|
8
8
|
http://nakkaya.com/2010/06/29/alter-ego-a-reactive-ai-library/
|
9
9
|
|
10
|
-
To try it out, 'gem install
|
10
|
+
To try it out, 'gem install behaviortree'
|
11
11
|
|
12
|
-
|
13
|
-
|
14
|
-
In my spare time, I fancy myself a fan of AI. Mostly, this means sitting around pondering, but with some spare time today, I put together an actual working (though simple) library. I thought I would share a little about it on here. The code can be found here.
|
15
|
-
|
16
|
-
Behavior Trees are a way of representing an algorithm as nodes in a tree. The leaf nodes actually perform actions, and nodes higher up in the tree branch depending on the environment. They are often used to model behaviors for agents in first-person games. The idea is that algorithms become very modular and composable when modeled this way.
|
17
|
-
|
18
|
-
I'm going to walk through the examples in 'sample.rb' in the code repository. These examples revolve around some very simple behaviors on a list. First, we'll define a couple of actions:
|
19
|
-
|
20
|
-
|
21
|
-
action :pop do |e|
|
22
|
-
e.pop
|
23
|
-
end
|
24
|
-
|
25
|
-
action :empty do |e|
|
26
|
-
e.empty?
|
27
|
-
end
|
28
|
-
|
29
|
-
The syntax here is somewhat like rake. I played with a lot of different ideas for this, but this seemed to come out the most readable. We're creating two actions, pop, and empty. An action is a leaf node in a behavior tree, so it actually interacts with the environment. Thus, the actions take a block which takes the environment, e, and does something with it. These are the fundamental building blocks.
|
30
|
-
|
31
|
-
Now let's define a sequence node. A sequence node is a non-leaf node, which tries each of its children, and fails if any of the children fail. Very simple. So let's define it:
|
32
|
-
|
33
|
-
sequence :pop_twice, [:pop, :pop]
|
34
|
-
|
35
|
-
|
36
|
-
Simple idea, simple syntax! The name of this node is 'pop_twice', and it contains two children, both of which are leaf nodes, and which pop one element off of the list that we're interacting with. Since the first child will succeed (assuming the list is non-empty), the second will always run.
|
37
|
-
|
38
|
-
Next, let's do a selector node. A selector node is another type of non-leaf node, which tries each of its children, but returns true if any child node returns true (and then stops looking). You can see, it's sort of the opposite of a sequence in some ways. So, what might it look like? Well, it could look exactly the same as a sequence!
|
39
|
-
|
40
|
-
select :pop_once, [:pop, :pop]
|
41
|
-
|
42
|
-
This selector has the same children, but notice that the name is pop_once. This is because...drumroll please...it will only pop one item. When the first succeeds, which it will, it is satisfied, and returns true.
|
43
|
-
|
44
|
-
Now, lets look at the last two together:
|
45
|
-
|
46
|
-
select :make_empty, [:empty, :continue]
|
47
|
-
sequence :continue, [:pop, :make_empty]
|
48
|
-
|
49
|
-
This is the culmination of what this little library can do. Isn't it impressive!? Here, we have two nodes which are defined in terms of each other. make_empty first checks wither the list is empty. If so, then, since it's a selector, it's satisfied, and execution stops. If not, however, it hits the second node, which is continue. Continue pops an item off the stak, and then _recursively_ refers to make_empty. So, what's this going to do? It will keep popping items off the list, until it's empty. Very simple, but a very powerful idea.
|
50
|
-
|
51
|
-
And that's about it for now! Hopefully, I will soon add the ability to define custom decorators in the library. Until then, enjoy!
|
12
|
+
As an example of how to use this library, I've written a solution to the beginning level of rubywarrior (http://github.com/ryanb/ruby-warrior).
|
data/Rakefile
CHANGED
data/behaviortree.gemspec
CHANGED
@@ -2,11 +2,11 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = %q{behaviortree}
|
5
|
-
s.version = "
|
5
|
+
s.version = "2.0"
|
6
6
|
|
7
7
|
s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
|
8
8
|
s.authors = ["Andrew Wagner"]
|
9
|
-
s.date = %q{2010-10-
|
9
|
+
s.date = %q{2010-10-31}
|
10
10
|
s.description = %q{behavior trees for ruby}
|
11
11
|
s.email = %q{wagner.andrew@gmail.com}
|
12
12
|
s.extra_rdoc_files = ["README", "lib/behaviortree.rb", "lib/behaviortree/behaviortree.rb"]
|
data/lib/behaviortree.rb
CHANGED
@@ -1,43 +1,8 @@
|
|
1
|
-
|
2
|
-
@actions = {}
|
3
|
-
|
4
|
-
class << self
|
5
|
-
attr_reader :actions
|
6
|
-
end
|
7
|
-
|
8
|
-
def action name, &block
|
9
|
-
a = lambda {|e| yield e}
|
10
|
-
BTree.actions[name] = a unless name.nil?
|
11
|
-
a
|
12
|
-
end
|
1
|
+
require 'yaml'
|
13
2
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
def lookup symbol
|
19
|
-
BTree.actions[symbol]
|
20
|
-
end
|
21
|
-
|
22
|
-
def sequence symbol, children
|
23
|
-
process_children symbol, children, lambda {|result| result}
|
24
|
-
end
|
25
|
-
|
26
|
-
def select symbol, children
|
27
|
-
process_children symbol, children, lambda {|result| !result }
|
28
|
-
end
|
29
|
-
|
30
|
-
private
|
31
|
-
def process_children symbol, children, post_process
|
32
|
-
action symbol do |e|
|
33
|
-
continue = true
|
34
|
-
children.each do |child|
|
35
|
-
next unless continue
|
36
|
-
continue = post_process.call(execute child, e)
|
37
|
-
end
|
38
|
-
continue
|
39
|
-
end
|
3
|
+
module BTree
|
4
|
+
def self.load_file file_name
|
5
|
+
raw = YAML::load_file file_name
|
6
|
+
tree = BehaviorCreator.new(raw).create
|
40
7
|
end
|
41
8
|
end
|
42
|
-
|
43
|
-
include BTree
|
metadata
CHANGED
@@ -3,9 +3,9 @@ name: behaviortree
|
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
|
-
-
|
6
|
+
- 2
|
7
7
|
- 0
|
8
|
-
version: "
|
8
|
+
version: "2.0"
|
9
9
|
platform: ruby
|
10
10
|
authors:
|
11
11
|
- Andrew Wagner
|
@@ -13,7 +13,7 @@ autorequire:
|
|
13
13
|
bindir: bin
|
14
14
|
cert_chain: []
|
15
15
|
|
16
|
-
date: 2010-10-
|
16
|
+
date: 2010-10-31 00:00:00 -04:00
|
17
17
|
default_executable:
|
18
18
|
dependencies: []
|
19
19
|
|