btcode

behavirotree code

http://www.cplusplus.com/forum/general/141582/

/ Behaviour tree that models the behaviour of a person whose goal is to open a door.

#include <iostream>
#include <list>

/*

	    Root
             |
             |
  Selector (only one of these children need to succeed)  
       /             \
      /               \
     /                 \
Door is open?      Sequence (all of these children need to succeed)
(if door is                /           \
already open,             /             \
we are done)             /               \
                   Approach door      Open the door
                  (if this fails
                  then the door
                  cannot be opened)
*/

class Node {  // This class represents each node in the behaviour tree.
	public:
		virtual bool run() = 0;
};

class CompositeNode : public Node {  //  This type of Node follows the Composite Pattern, containing a list of other Nodes.
	private:
		std::list<Node*> children;
	public:
		const std::list<Node*>& getChildren() const {return children;}
		void addChild (Node* child) {children.emplace_back(child);}
};

class Selector : public CompositeNode {
	public:
		virtual bool run() override {
			for (Node* child : getChildren()) {  // The generic Selector implementation
				if (child->run())  // If one child succeeds, the entire operation run() succeeds.  Failure only results if all children fail.
					return true;
			}
			return false;  // All children failed so the entire run() operation fails.
		}
};

class Sequence : public CompositeNode {
	public:
		virtual bool run() override {
			for (Node* child : getChildren()) {  // The generic Sequence implementation.
				if (!child->run())  // If one child fails, then enter operation run() fails.  Success only results if all children succeed.
					return false;
			}
			return true;  // All children suceeded, so the entire run() operation succeeds.
		}
};

struct DoorStatus {
	bool doorIsOpen;
	int distanceToDoor;
};

class CheckIfDoorIsOpenTask : public Node {  // Each task will be a class (derived from Node of course).
	private:
		DoorStatus* status;
	public:
		CheckIfDoorIsOpenTask (DoorStatus* status) : status(status) {}
		virtual bool run() override {
			if (status->doorIsOpen == true)
				std::cout << "The person sees that the door is open." << std::endl;  // will return true
			else
				std::cout << "The person sees that the door is closed." << std::endl;  // will return false
			return status->doorIsOpen;
		}
};

class ApproachDoorTask : public Node {
	private:
		DoorStatus* status;
		bool obstructed;
	public:
		ApproachDoorTask (DoorStatus* status, bool obstructed) : status(status), obstructed(obstructed) {}
		virtual bool run() override {
			if (obstructed)
				return false;
			if (status->distanceToDoor > 0) {
				std::cout << "The person approaches the door." << std::endl;
				status->distanceToDoor--;  // thus run() is not a const function
				if (status->distanceToDoor > 1)
					std::cout << "The person is now " << status->distanceToDoor << " meters from the door." << std::endl;
				else if (status->distanceToDoor == 1)
					std::cout << "The person is now only one meter away from the door." << std::endl;
				else
					std::cout << "The person is at the door." << std::endl;
			}
			return true;
		}
};

class OpenDoorTask : public Node {
	private:
		DoorStatus* status;
	public:
		OpenDoorTask (DoorStatus* status) : status(status) {}
		virtual bool run() override {
			if (status->distanceToDoor > 0) {
				std::cout << "The person is still too far away from the door.  He cannot open the door." << std::endl;
				return false;	
			}
			status->doorIsOpen = true;  // run() not const because of this too
			std::cout << "The person opens the door." << std::endl;
			return true;
		}
};

int main() {
	Sequence *root = new Sequence, *sequence1 = new Sequence;  // Note that root can be either a Sequence or a Selector, since it has only one child.
	Selector* selector1 = new Selector;  // In general there will be several nodes that are Sequence or Selector, so they should be suffixed by an integer to distinguish between them.
	DoorStatus* doorStatus = new DoorStatus {false, 5};  // The door is initially closed and 5 meters away.
	CheckIfDoorIsOpenTask* checkOpen = new CheckIfDoorIsOpenTask (doorStatus);
	ApproachDoorTask* approach = new ApproachDoorTask (doorStatus, false);
	OpenDoorTask* open = new OpenDoorTask (doorStatus);
	
	root->addChild (selector1);
	
	selector1->addChild (checkOpen);
	selector1->addChild (sequence1);
	
	sequence1->addChild (approach);
	sequence1->addChild (open);
	
	while (!root->run())  // If the operation starting from the root fails, keep trying until it succeeds.
		std::cout << "--------------------" << std::endl;
	std::cout << std::endl << "Operation complete.  Behaviour tree exited." << std::endl;
	std::cin.get();
}

/*
Output:
The person sees that the door is closed.
The person approaches the door.
The person is now 4 meters from the door.
The person is still too far away from the door.  He cannot open the door.
--------------------
The person sees that the door is closed.
The person approaches the door.
The person is now 3 meters from the door.
The person is still too far away from the door.  He cannot open the door.
--------------------
The person sees that the door is closed.
The person approaches the door.
The person is now 2 meters from the door.
The person is still too far away from the door.  He cannot open the door.
--------------------
The person sees that the door is closed.
The person approaches the door.
The person is now only one meter away from the door.
The person is still too far away from the door.  He cannot open the door.
--------------------
The person sees that the door is closed.
The person approaches the door.
The person is at the door.
The person opens the door.

Operation complete.  Behaviour tree exited.
*/

Edit & Run

Last edited on Sep 2, 2014 at 1:22am

 Sep 1, 2014 at 12:34pm

prestokeys (357)

"http://imagizer.imageshack.us/v2/150x100q90/540/BTUdjJ.jpg"

Here the behaviour tree simulates a person trying to escape a room. The tree is much bigger and deeper this time, so for brevity we will make the determination of success or failure simpler.
Note: The tree diagram picture above is too small to see. You can find it in the 7th picture in this website:
http://www.gamasutra.com/blogs/ChrisSimpson/20140717/221339/Behavior_trees_for_AI_How_they_work.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
#include <iostream>
#include <list>
#include <vector>
#include <stack>
#include <initializer_list>
#include <string>
#include <cstdlib>
#include <ctime>
#include <algorithm>

class BehaviourTree {  // Note:  A proper copy constructor and assignment operator should be defined, since the implicit ones use shallow copies only.
	public:
		class Node {  // This class represents each node in the behaviour tree.
			public:
				virtual bool run() = 0;
		};
		
		class CompositeNode : public Node {  //  This type of Node follows the Composite Pattern, containing a list of other Nodes.
			private:
				std::vector<Node*> children;
			public:
				const std::vector<Node*>& getChildren() const {return children;}
				void addChild (Node* child) {children.emplace_back(child);}
				void addChildren (std::initializer_list<Node*>&& newChildren) {for (Node* child : newChildren) addChild(child);}
				template <typename CONTAINER>
				void addChildren (const CONTAINER& newChildren) {for (Node* child : newChildren) addChild(child);}
			protected:
				std::vector<Node*> childrenShuffled() const {std::vector<Node*> temp = children;  std::random_shuffle (temp.begin(), temp.end());  return temp;}
		};
		
		class Selector : public CompositeNode {
			public:
				virtual bool run() override {
					for (Node* child : getChildren()) {  // The generic Selector implementation
						if (child->run())  // If one child succeeds, the entire operation run() succeeds.  Failure only results if all children fail.
							return true;
					}
					return false;  // All children failed so the entire run() operation fails.
				}
		};
		
		class RandomSelector : public CompositeNode {  // RandomSelector operates as a Selector, but in a random order instead of from first child to last child.
			public:
				virtual bool run() override {
					for (Node* child : childrenShuffled()) {  // The order is shuffled
						if (child->run())
							return true;
					}
					return false;
				}
		};

		class Sequence : public CompositeNode {
			public:
				virtual bool run() override {
					for (Node* child : getChildren()) {  // The generic Sequence implementation.
						if (!child->run())  // If one child fails, then enter operation run() fails.  Success only results if all children succeed.
							return false;
					}
					return true;  // All children suceeded, so the entire run() operation succeeds.
				}
		};

		class Root : public Node {
			private:
				Node* child;
				friend class BehaviourTree;
				void setChild (Node* newChild) {child = newChild;}
				virtual bool run() override {return child->run();}
		};
	private:
		Root* root;
	public:
		BehaviourTree() : root(new Root) {}
		void setRootChild (Node* rootChild) const {root->setChild (rootChild);}
		bool run() const {return root->run();}
};

class Action : public BehaviourTree::Node {
	private:
		std::string name;
		int probabilityOfSuccess;
	public:
		Action (const std::string newName, int prob) : name(newName), probabilityOfSuccess(prob) {}
	private:
		virtual bool run() override {
			if (std::rand() % 100 < probabilityOfSuccess) {
				std::cout << name << " succeeded." << std::endl;
				return true;
			}
			std::cout << name << " failed." << std::endl;
			return false;
		}
};

int main() {
	std::srand(std::time(nullptr));
	BehaviourTree behaviorTree;
	BehaviourTree::Selector selector[3];
	BehaviourTree::Sequence sequence[4];
	Action walkToDoor ("Walk to door", 99), openDoor1 ("Open door", 15), unlockDoor ("Unlock door", 25), openDoor2 ("Open door after unlocking it", 99), smashDoor ("Smash door", 60), 
		walkThroughDoor ("Walk through door", 60), closeDoor ("Close door", 100), walkToWindow ("Walk to Window", 99), openWindow1 ("Open window", 70), unlockWindow ("Unlock window", 65),
		openWindow2 ("Open window after unlocking it", 85), smashWindow ("Smash window", 95), climbThroughWindow ("Climb through window", 85), closeWindow ("Close window", 100);
	
	behaviorTree.setRootChild (&selector[0]);
	selector[0].addChildren ({&sequence[0],&sequence[2]});
	sequence[0].addChildren ({&walkToDoor, &selector[1], &walkThroughDoor, &closeDoor});
	selector[1].addChildren ({&openDoor1, &sequence[1], &smashDoor});
	sequence[1].addChildren ({&unlockDoor, &openDoor2});
	sequence[2].addChildren ({&walkToWindow, &selector[2], &climbThroughWindow, &closeWindow});
	const std::list<BehaviourTree::Node*> nodes = {&openWindow1, &sequence[3], &smashWindow};
	selector[2].addChildren(nodes);
	sequence[3].addChildren ({&unlockWindow, &openWindow2});
	
	if (behaviorTree.run())
		std::cout << "Congratulations!  You made it out!" << std::endl;
	else
		std::cout << "Sorry.  You are trapped here for life." << std::endl;
}
/*
Possible outcome:

Walk to door succeeded.
Open door failed.
Unlock door failed.
Smash door failed.
Walk to Window succeeded.
Open window failed.
Unlock window failed.
Smash window succeeded.
Climb through window succeeded.
Close window succeeded.
Congratulations!  You made it out!
*/	
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值