From 50b237dc9b9e4791762de7bb93bc932c4caad0a4 Mon Sep 17 00:00:00 2001 From: David Delassus Date: Tue, 9 Jan 2024 04:26:42 +0100 Subject: [PATCH] :memo: add documentation for utility ai --- README.md | 81 +++++++++++++++++++- include/aitoolkit/utility.hpp | 136 ++++++++++++++++++++++++++++++++++ 2 files changed, 216 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 9d50d47..3b7bbab 100644 --- a/README.md +++ b/README.md @@ -152,7 +152,86 @@ For more informations, consult the ### Utility AI -TODO +First, include the header file: + +```cpp +#include + +using namespace aitoolkit::utility; +``` + +Then, create a blackboard type: + +```cpp +struct blackboard_type { + int food{0}; + int wood{0}; + int stone{0}; + int gold{0}; +}; +``` + +Next, create a class for each action that you want to be able to perform: + +```cpp +class collect_food final : public action { + public: + virtual float score(const blackboard_type& blackboard) const override { + return 50.0f; + } + + virtual void apply(blackboard_type& blackboard) const override { + blackboard.food += 1; + } +}; + +class collect_wood final : public action { + public: + virtual float score(const blackboard_type& blackboard) const override { + return 150.0f; + } + + virtual void apply(blackboard_type& blackboard) const override { + blackboard.wood += 1; + } +}; + +class collect_stone final : public action { + public: + virtual float score(const blackboard_type& blackboard) const override { + return -10.0f; + } + + virtual void apply(blackboard_type& blackboard) const override { + blackboard.stone += 1; + } +}; + +class collect_gold final : public action { + public: + virtual float score(const blackboard_type& blackboard) const override { + return 75.0f; + } + + virtual void apply(blackboard_type& blackboard) const override { + blackboard.gold += 1; + } +}; +``` + +Finally, create an evaluator and run it: + +```cpp +auto evaluator = evaluator{ + std::make_shared(), + std::make_shared(), + std::make_shared(), + std::make_shared() +}; + +auto blackboard = blackboard_type{}; +evaluator.run(blackboard); +``` ### Goal Oriented Action Planning diff --git a/include/aitoolkit/utility.hpp b/include/aitoolkit/utility.hpp index 4e10c2e..90947f0 100644 --- a/include/aitoolkit/utility.hpp +++ b/include/aitoolkit/utility.hpp @@ -1,26 +1,159 @@ #pragma once +/** +@defgroup utility Utility AI + +## Introduction + +Utility AI is a planning algorithm that can be used to find the best action to +perform in a given situation. The algorithm works by assigning a score to each +action based on how well it will achieve the goal. The algorithm is guaranteed +to find a solution. + +
+flowchart TD
+
+  a1[Collect food\nscore: +50]
+  a2[Collect wood\nscore: +150]
+  a3[Collect stone\nscore: -10]
+  a4[Collect gold\nscore: +75]
+
+  style a1 color:darkred
+  style a2 color:darkgreen
+  style a3 color:darkred
+  style a4 color:darkred
+
+ + +## Usage + +First, include the header file: + +```cpp +#include +``` + +Then, create a blackboard type: + +```cpp +struct blackboard_type { + int food{0}; + int wood{0}; + int stone{0}; + int gold{0}; +}; +``` + +Next, create a class for each action that you want to be able to perform: + +```cpp +using namespace aitoolkit::utility; + +class collect_food final : public action { + public: + virtual float score(const blackboard_type& blackboard) const override { + return 50.0f; + } + + virtual void apply(blackboard_type& blackboard) const override { + blackboard.food += 1; + } +}; + +class collect_wood final : public action { + public: + virtual float score(const blackboard_type& blackboard) const override { + return 150.0f; + } + + virtual void apply(blackboard_type& blackboard) const override { + blackboard.wood += 1; + } +}; + +class collect_stone final : public action { + public: + virtual float score(const blackboard_type& blackboard) const override { + return -10.0f; + } + + virtual void apply(blackboard_type& blackboard) const override { + blackboard.stone += 1; + } +}; + +class collect_gold final : public action { + public: + virtual float score(const blackboard_type& blackboard) const override { + return 75.0f; + } + + virtual void apply(blackboard_type& blackboard) const override { + blackboard.gold += 1; + } +}; +``` + +Finally, create an evaluator and run it: + +```cpp +auto evaluator = evaluator{ + std::make_shared(), + std::make_shared(), + std::make_shared(), + std::make_shared() +}; + +auto blackboard = blackboard_type{}; +evaluator.run(blackboard); +``` +*/ + #include #include #include #include namespace aitoolkit::utility { + /** + * @ingroup utility + * @class action + * @brief Base abstract class for all actions + */ template class action { public: virtual ~action() = default; + /** + * @brief Return the score of the action + */ virtual float score(const T& blackboard) const = 0; + + /** + * @brief Apply the action to the blackboard + */ virtual void apply(T& blackboard) const = 0; }; + /** + * @ingroup utility + * @brief Heap allocated pointer to an action. + */ template using action_ptr = std::shared_ptr>; + /** + * @ingroup utility + * @class evaluator + * @brief Evaluate a set of actions and apply the best one. + */ template class evaluator { public: + /** + * @brief Construct an evaluator from a list of actions + */ evaluator(std::initializer_list> actions) { m_actions.reserve(actions.size()); for (auto action : actions) { @@ -28,6 +161,9 @@ namespace aitoolkit::utility { } } + /** + * @brief Find the best action and apply it to the blackboard + */ void run(T& blackboard) const { if (m_actions.empty()) { return;