Synthia
Generic and flexible data structure generator
BehaviorTree.java
Go to the documentation of this file.
1 /*
2  Synthia, a data structure generator
3  Copyright (C) 2019-2020 Laboratoire d'informatique formelle
4  Université du Québec à Chicoutimi, Canada
5 
6  This program is free software: you can redistribute it and/or modify
7  it under the terms of the GNU Lesser General Public License as published
8  by the Free Software Foundation, either version 3 of the License, or
9  (at your option) any later version.
10 
11  This program is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU Lesser General Public License for more details.
15 
16  You should have received a copy of the GNU Lesser General Public License
17  along with this program. If not, see <http://www.gnu.org/licenses/>.
18  */
19 package ca.uqac.lif.synthia.sequence;
20 
21 import java.util.ArrayList;
22 import java.util.List;
23 
24 import ca.uqac.lif.synthia.Picker;
26 import ca.uqac.lif.synthia.util.Once;
28 
29 /**
30  * Generates a sequence of objects by following a behavior tree.
31  * A <a href="https://en.wikipedia.org/wiki/Behavior_tree_(artificial_intelligence,_robotics_and_control)">behavior
32  * tree</a> is a structure whose leaf nodes are associated to {@link Picker}s, and whose
33  * non-leaf nodes can be of two types:
34  * <ul>
35  * <li>{@link Sequence}: a sequence node calls {@link Picker#pick()} on its
36  * first child until it returns <tt>null</tt>, then calls {@link Picker#pick()} on
37  * its second child, and so on. When all children are exhausted, it returns
38  * <tt>null</tt>.</li>
39  * <li>{@link Selector}: a selector node chooses one of its children, and
40  * calls {@link Picker#pick()} on it until it returns <tt>null</tt>.</li>
41  * </ul>
42  *
43  * @param <T> The type of objects returned by the behavior tree. The pickers
44  * associated to each leaf node must return objects of type <tt>T</tt> or its
45  * descendants.
46  * @ingroup API
47  */
48 public abstract class BehaviorTree<T> implements Picker<T>
49 {
50  @Override
51  public abstract BehaviorTree<T> duplicate(boolean with_state);
52 
53  /**
54  * Sequence node in a behavior tree
55  * @param <T> The type of objects returned by the behavior tree
56  */
57  public static class Sequence<T> extends BehaviorTree<T>
58  {
59  /**
60  * The list of children to this node
61  */
62  /*@ non_null @*/ protected List<BehaviorTree<T>> m_children;
63 
64  /**
65  * The index of the current child node that is being "executed"
66  * (i.e. on which calls to {@link Picker#pick()} are currently
67  * being made)
68  */
69  protected int m_index;
70 
71  /**
72  * Creates a new sequence node with no children
73  */
74  public Sequence()
75  {
76  super();
77  m_children = new ArrayList<BehaviorTree<T>>();
78  m_index = 0;
79  }
80 
81  /**
82  * Creates a new sequence node with a list of child nodes
83  * @param nodes The child nodes
84  */
85  @SuppressWarnings("unchecked")
86  public Sequence(/*@ non_null @*/ BehaviorTree<T> ... nodes)
87  {
88  super();
89  m_children = new ArrayList<BehaviorTree<T>>(nodes.length);
90  for (BehaviorTree<T> n : nodes)
91  {
92  m_children.add(n);
93  }
94  m_index = 0;
95  }
96 
97  /**
98  * Adds children to this nodes
99  * @param nodes The nodes to add as children
100  * @return This node
101  */
102  @SuppressWarnings("unchecked")
103  public Sequence<T> add(/*@ non_null @*/ BehaviorTree<T> ... nodes)
104  {
105  for (BehaviorTree<T> tn : nodes)
106  {
107  m_children.add(tn);
108  }
109  return this;
110  }
111 
112  /**
113  * Puts the BehaviorTree back into its initial state. This means that the
114  * sequence of calls to {@link #pick()} will produce the same values
115  * as when the object was instantiated.
116  */
117  @Override
118  public void reset()
119  {
120  m_index = 0;
121  }
122 
123  /**
124  * Picks a value from a child of the BehaviorTree. Typically, this method is expected
125  * to return non-null objects; a <tt>null</tt> return value is used to signal that no more
126  * objects will be produced. That is, once this method returns
127  * <tt>null</tt>, it should normally return <tt>null</tt> on all subsequent
128  * calls.
129  * @return The value from a child of the BehaviorTree.
130  */
131 
132  @Override
133  public T pick()
134  {
135  T t = null;
136  while (t == null && m_index < m_children.size())
137  {
138  BehaviorTree<T> tn = m_children.get(m_index);
139  t = tn.pick();
140  if (t == null)
141  {
142  m_index++;
143  }
144  }
145  return t;
146  }
147 
148  /**
149  * Creates a copy of the BehaviorTree.
150  * @param with_state If set to <tt>false</tt>, the returned copy is set to
151  * the class' initial state (i.e. same thing as calling the picker's
152  * constructor). If set to <tt>true</tt>, the returned copy is put into the
153  * same internal state as the object it is copied from.
154  * @return The copy of the BehaviorTree
155  */
156  @Override
157  public Sequence<T> duplicate(boolean with_state)
158  {
159  Sequence<T> tn = new Sequence<T>();
160  for (BehaviorTree<T> child : m_children)
161  {
162  tn.m_children.add(child.duplicate(with_state));
163  }
164  if (with_state)
165  {
166  tn.m_index = m_index;
167  }
168  return tn;
169  }
170  }
171 
172  /**
173  * Selector node in a behavior tree
174  * @param <T> The type of objects returned by the behavior tree
175  */
176  public static class Selector<T> extends BehaviorTree<T>
177  {
178  /*@ non_null @*/ protected List<ProbabilityChoice<T>> m_choices;
179 
180  /**
181  * The index of the child node that is being "executed"
182  * (i.e. on which calls to {@link Picker#pick()} are currently
183  * being made). This field contains value -1 until a child node
184  * is chosen.
185  */
186  protected int m_chosenIndex;
187 
188  /**
189  * A picker used to choose the child node
190  */
191  /*@ non_null @*/ protected Picker<Float> m_floatPicker;
192 
193  /**
194  * Creates a new selector node with no children
195  * @param float_picker A picker used to choose the child node when
196  * a call to {@link #pick()} is being made
197  */
198  public Selector(/*@ non_null @*/ Picker<Float> float_picker)
199  {
200  super();
201  m_choices = new ArrayList<ProbabilityChoice<T>>();
202  m_chosenIndex = -1;
203  m_floatPicker = float_picker;
204  }
205 
206 
207  /**
208  * Puts the Selector back into its initial state. This means that the
209  * sequence of calls to {@link #pick()} will produce the same values
210  * as when the object was instantiated.
211  */
212  @Override
213  public void reset()
214  {
215  m_chosenIndex = -1;
216  for (ProbabilityChoice<T> pc : m_choices)
217  {
218  pc.reset();
219  }
220  }
221 
222 
223  /**
224  * Picks a value from a child of the Node. Typically, this method is expected to return non-null
225  * objects; a <tt>null</tt> return value is used to signal that no more
226  * objects will be produced. That is, once this method returns
227  * <tt>null</tt>, it should normally return <tt>null</tt> on all subsequent
228  * calls.
229  * @return The value picked from a child of the Selector Node.
230  */
231  @Override
232  public T pick()
233  {
234  if (m_chosenIndex < 0)
235  {
236  float[] probs = new float[m_choices.size()];
237  float total_prob = 0f;
238  for (int i = 0; i < probs.length; i++)
239  {
240  total_prob += m_choices.get(i).getProbability();
241  probs[i] = total_prob;
242  }
243  float f = m_floatPicker.pick();
244  int index = 0;
245  while (index < probs.length)
246  {
247  if (f <= probs[index])
248  {
249  m_chosenIndex = index;
250  break;
251  }
252  index++;
253  }
254  }
255  if (m_chosenIndex >= m_choices.size())
256  {
257  return null;
258  }
259  return m_choices.get(m_chosenIndex).getObject();
260  }
261 
262  /**
263  * Creates a copy of the Selector.
264  * @param with_state If set to <tt>false</tt>, the returned copy is set to
265  * the class' initial state (i.e. same thing as calling the picker's
266  * constructor). If set to <tt>true</tt>, the returned copy is put into the
267  * same internal state as the object it is copied from.
268  * @return The copy of the Selector
269  */
270  @Override
271  public Selector<T> duplicate(boolean with_state)
272  {
273  Selector<T> ch = new Selector<T>(m_floatPicker.duplicate(with_state));
274  for (ProbabilityChoice<T> pc : m_choices)
275  {
276  ch.m_choices.add(pc.duplicate(with_state));
277  }
278  if (with_state)
279  {
280  ch.m_chosenIndex = m_chosenIndex;
281  }
282  return ch;
283  }
284 
285  /**
286  * Adds a new child to this node
287  * @param node The behavior tree node to add
288  * @param probability The probability of this node being picked. The
289  * sum of probabilities associated to all child nodes of a given
290  * selector node should be equal to 1.
291  * @return This node
292  */
293  public Selector<T> add(BehaviorTree<T> node, Number probability)
294  {
295  m_choices.add(new ProbabilityChoice<T>(node, probability));
296  return this;
297  }
298 
299 
300  /**
301  * Returns the BehaviorTree Node as a string.
302  * @return The string representing the BehaviorTree Node.
303  */
304  @Override
305  public String toString()
306  {
307  StringBuilder out = new StringBuilder();
308  int size = m_choices.size();
309  String beg = "", end = "";
310  if (size > 1)
311  {
312  beg = "(";
313  end = ")";
314  }
315  out.append(beg);
316  for (int i = 0; i < m_choices.size(); i++)
317  {
318  if (i > 0)
319  {
320  out.append(" || ");
321  }
322  out.append(m_choices.get(i).toString());
323  }
324  out.append(end);
325  return out.toString();
326  }
327 
328  }
329 
330  /**
331  * Leaf node of a behavior tree. A leaf node contains an internal {@link Picker},
332  * which is called when the node's {@link #pick()} method is called.
333  * @param <T> The type of objects returned by the behavior tree
334  */
335  public static class Leaf<T> extends BehaviorTree<T>
336  {
337  /**
338  * The internal picker that will be called on a call to
339  * the node's {@link #pick()} method
340  */
341  /*@ non_null @*/ protected Picker<T> m_picker;
342 
343  /**
344  * Creates a new leaf node
345  * @param picker The internal picker that will be called on a call to
346  * the node's {@link #pick()} method
347  */
348  public Leaf(/*@ non_null @*/ Picker<T> picker)
349  {
350  super();
351  m_picker = picker;
352  }
353 
354  /**
355  * Creates a new leaf node that outputs a single value exactly once
356  * @param t The value to output
357  */
358  public Leaf(/*@ non_null @*/ T t)
359  {
360  super();
361  m_picker = new Once<T>(new Constant<T>(t));
362  }
363 
364  /**
365  * Puts the Leaf back into its initial state. This means that the
366  * sequence of calls to {@link #pick()} will produce the same values
367  * as when the object was instantiated.
368  */
369  @Override
370  public void reset()
371  {
372  m_picker.reset();
373  }
374 
375  /**
376  * Picks the value from the leaf node. Typically, this method is expected to return non-null
377  * objects; a <tt>null</tt> return value is used to signal that no more
378  * objects will be produced. That is, once this method returns
379  * <tt>null</tt>, it should normally return <tt>null</tt> on all subsequent
380  * calls.
381  * @return The value of the leaf node
382  */
383  @Override
384  public T pick()
385  {
386  return m_picker.pick();
387  }
388 
389 
390  /**
391  * Creates a copy of the Leaf.
392  * @param with_state If set to <tt>false</tt>, the returned copy is set to
393  * the class' initial state (i.e. same thing as calling the picker's
394  * constructor). If set to <tt>true</tt>, the returned copy is put into the
395  * same internal state as the object it is copied from.
396  * @return The copy of the leaf node
397  */
398  @Override
399  public Leaf<T> duplicate(boolean with_state)
400  {
401  return new Leaf<T>(m_picker.duplicate(with_state));
402  }
403 
404  @Override
405  public String toString()
406  {
407  return m_picker.toString();
408  }
409  }
410 }
ca.uqac.lif.synthia.Picker
Picks an object.
Definition: Picker.java:36
ca.uqac.lif.synthia.sequence.BehaviorTree
Generates a sequence of objects by following a behavior tree.
Definition: BehaviorTree.java:48
ca.uqac.lif.synthia.util
Miscellaneous pickers performing various functions.
Definition: ArrayPicker.java:19
ca.uqac.lif.synthia.sequence.BehaviorTree.duplicate
abstract BehaviorTree< T > duplicate(boolean with_state)
Creates a copy of the picker.
ca.uqac.lif.synthia.util.Choice.ProbabilityChoice
Simple data structure asssociating an object with a probability.
Definition: Choice.java:178
ca.uqac
ca.uqac.lif.synthia
Definition: Bounded.java:19
ca.uqac.lif.synthia.util.Constant
Picker that returns the same object every time.
Definition: Constant.java:37
ca.uqac.lif
ca.uqac.lif.synthia.util.Once
Picker that returns the first value fetched from another picker, and then null afterwards.
Definition: Once.java:45
ca
ca.uqac.lif.synthia.Picker.pick
T pick()
Picks an object.
ca.uqac.lif.synthia.util.Choice
Picks an element from a collection, where the probability of picking each element can be user-defined...
Definition: Choice.java:44
ca.uqac.lif.synthia.Picker.duplicate
Picker< T > duplicate(boolean with_state)
Creates a copy of the picker.
ca.uqac.lif.synthia.Picker.reset
void reset()
Puts the picker back into its initial state.