/* * Copyright (C) 2021 Christopher J. Howard * * This file is part of Antkeeper source code. * * Antkeeper source code is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Antkeeper source code is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Antkeeper source code. If not, see . */ #ifndef ANTKEEPER_BEHAVIOR_TREE_HPP #define ANTKEEPER_BEHAVIOR_TREE_HPP #include #include namespace behavior_tree { /// Behavior tree node return status enumerations. enum class status { failure, ///< Indicates a node's execution failed. success, ///< Indicates a node's execution succeed. running ///< Indicates a node's execution has not finished. }; /** * Abstract base class for behavior tree nodes. * * @tparam T Data type on which nodes operate. */ template struct node { /// Data type on which nodes operate. typedef T context_type; /** * Executes a node's functionality and returns its status. * * @param context Context data on which the node will operate. */ virtual status execute(context_type& context) const = 0; }; /// A node with no children. template using leaf_node = node; /// A node with exactly one child. template struct decorator_node: node { node* child; }; /// A node that can have one or more children. template struct composite_node: node { std::list children; }; /// Executes a function on a context and returns the status. template struct action: leaf_node { virtual status execute(context_type& context) const final; typedef std::function function_type; function_type function; }; /// Evaluates a boolean condition (predicate) and returns either `status::success` or `status::failure`. template struct condition: leaf_node { virtual status execute(context_type& context) const final; typedef std::function predicate_type; predicate_type predicate; }; /// Executes a child node and returns its inverted status. If the child returns `status::success`, then `status::failure` will be returned. Otherwise if the child returns `status::failure`, then `status::success` will be returned. template struct inverter: decorator_node { virtual status execute(context_type& context) const final; }; /// Attempts to execute a child node `n` times or until the child fails. template struct repeater: decorator_node { virtual status execute(context_type& context) const final; int n; }; /// Executes a child node and returns `status::success` regardless of the child node status. template struct succeeder: decorator_node { virtual status execute(context_type& context) const final; }; /// Attempts to execute each child node sequentially until one fails. If all children are executed successfully, `status::success` will be returned. Otherwise if any children fail, `status::failure` will be returned. template struct sequence: composite_node { virtual status execute(context_type& context) const final; }; /// Attempts to execute each child node sequentially until one succeeds. If a child succeeds, `status::success` will be returned. Otherwise if all children fail, `status::failure` will be returned. template struct selector: composite_node { virtual status execute(context_type& context) const final; }; template status action::execute(context_type& context) const { return function(context); } template status condition::execute(context_type& context) const { return (predicate(context)) ? status::success : status::failure; } template status inverter::execute(context_type& context) const { status child_status = child->execute(context); return (child_status == status::success) ? status::failure : (child_status == status::failure) ? status::success : child_status; } template status repeater::execute(context_type& context) const { status child_status; for (int i = 0; i < n; ++i) { child_status = child->execute(context); if (child_status == status::failure) break; } return child_status; } template status succeeder::execute(context_type& context) const { child->execute(context); return status::success; } template status sequence::execute(context_type& context) const { for (const node* child: children) { status child_status = child->execute(context); if (child_status != status::success) return child_status; } return status::success; } template status selector::execute(context_type& context) const { for (const node* child: children) { status child_status = child->execute(context); if (child_status != status::failure) return child_status; } return status::failure; } } // namespace behavior_tree #endif // ANTKEEPER_BEHAVIOR_TREE_HPP