AI prompts
base on Give a brain to your game's NPCs # AI Toolkit
<center>
![tests](https://img.shields.io/github/actions/workflow/status/linkdd/aitoolkit/tests.yml?style=flat-square&logo=github&label=tests)
![docs](https://img.shields.io/github/actions/workflow/status/linkdd/aitoolkit/docs.yml?style=flat-square&logo=github&label=docs)
![license](https://img.shields.io/github/license/linkdd/aitoolkit?style=flat-square&color=blue)
![version](https://img.shields.io/github/v/release/linkdd/aitoolkit?style=flat-square&color=red)
</center>
**AI Toolkit** is a header-only C++ library which provides tools for building
the brain of your game's NPCs.
It provides:
- Finite State Machines
- Behavior Tree
- Utility AI
- Goal Oriented Action Planning
Why this project? Well, I wrote about it [here](https://david-delassus.medium.com/ai-toolkit-give-a-brain-to-your-npcs-a-header-only-c-library-02a50ae9faed?sk=011cd1ed8e61d22f1be6b6430847f430).
## Installation
Add the `include` folder of this repository to your include paths.
Or add it as a submodule:
```
$ git submodule add https://github.com/linkdd/aitoolkit.git
$ g++ -std=c++23 -Iaitoolkit/include main.cpp -o mygame
```
> **NB:** This library is compatible with C++20.
Or using [Shipp](https://github.com/linkdd/shipp), add it to your dependencies:
```json
{
"name": "myproject",
"version": "0.1.0",
"dependencies": [
{
"name": "aitoolkit",
"url": "https://github.com/linkdd/aitoolkit.git",
"version": "v0.5.1"
}
]
}
```
## Usage
### Finite State Machine
First, include the header:
```cpp
#include <aitoolkit/fsm.hpp>
using namespace aitoolkit::fsm;
```
Then, create your blackboard type:
```cpp
struct blackboard_type {
// ...
};
```
Then, create a state type for each of your states:
```cpp
class state_dummy final : public state<blackboard_type> {
public:
virtual void enter(blackboard_type& blackboard) override {
// ...
}
virtual void exit(blackboard_type& blackboard) override {
// ...
}
virtual void pause(blackboard_type& blackboard) override {
// ...
}
virtual void resume(blackboard_type& blackboard) override {
// ...
}
virtual void update(blackboard_type& blackboard) override {
// ...
}
};
```
Create your simple state machine:
```cpp
auto simple_bb = blackboard_type{};
auto simple_fsm = simple_machine<blackboard_type>();
simple_fsm.set_state(state_dummy{}, simple_bb);
simple_fsm.pause(simple_bb);
simple_fsm.resume(simple_bb);
simple_fsm.update(simple_bb);
```
Or with a stack state machine:
```cpp
auto stack_bb = blackboard_type{};
auto stack_fsm = stack_machine<blackboard_type>{};
stack_fsm.push_state(state_dummy{}, stack_bb);
stack_fsm.push_state(state_dummy{}, stack_bb);
stack_fsm.update(stack_bb);
stack_fsm.pop_state(stack_bb);
stack_fsm.pop_state(stack_bb);
```
### Behavior Tree
First, include the header:
```cpp
#include <aitoolkit/behtree.hpp>
using namespace aitoolkit::bt;
```
Then, create your blackboard type:
```cpp
struct blackboard_type {
// ...
};
```
Then, create your tree:
```cpp
auto tree = seq<blackboard_type>(
node_list<blackboard_type>(
check<blackboard_type>([](const blackboard_type& bb) {
// check some condition
return true;
}),
task<blackboard_type>([](blackboard_type& bb) {
// perform some action
return execution_state::success;
})
)
);
```
Finally, evaluate it:
```cpp
auto blackboard = blackboard_type{
// ...
};
auto state = tree.evaluate(blackboard);
```
For more informations, consult the
[documentation](https://linkdd.github.io/aitoolkit/group__behtree.html).
### Utility AI
First, include the header file:
```cpp
#include <aitoolkit/utility.hpp>
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<blackboard_type> {
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<blackboard_type> {
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<blackboard_type> {
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<blackboard_type> {
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<blackboard_type>(
action_list<blackboard_type>(
collect_food{},
collect_wood{},
collect_stone{},
collect_gold{}
)
);
auto blackboard = blackboard_type{};
evaluator.run(blackboard);
```
### Goal Oriented Action Planning
First, include the header file:
```cpp
#include <aitoolkit/goap.hpp>
using namespace aitoolkit::goap;
```
Then, create a blackboard class that will hold the state of the planner:
```cpp
struct blackboard_type {
bool has_axe{false};
int wood{0};
};
```
> **NB:** The blackboard needs to be comparable (`a == b`) and hashable.
Next, create a class for each action that you want to be able to perform:
```cpp
class get_axe final : public action<blackboard_type> {
public:
virtual float cost(const blackboard_type& blackboard) const override {
return 1.0f;
}
virtual bool check_preconditions(const blackboard_type& blackboard) const override {
return !blackboard.has_axe;
}
virtual void apply_effects(blackboard_type& blackboard, bool dry_run) const override {
blackboard.has_axe = true;
}
};
class chop_tree final : public action<blackboard_type> {
public:
virtual float cost(const blackboard_type& blackboard) const override {
return 1.0f;
}
virtual bool check_preconditions(const blackboard_type& blackboard) const override {
return blackboard.has_axe;
}
virtual void apply_effects(blackboard_type& blackboard, bool dry_run) const override {
blackboard.wood += 1;
}
};
```
Finally, create a plan and run it:
```cpp
auto initial = blackboard_type{};
auto goal = blackboard_type{
.has_axe = true,
.wood = 3
};
auto p = planner<blackboard_type>(
action_list<blackboard_type>(
get_axe{},
chop_tree{}
),
initial,
goal
);
auto blackboard = initial;
while (p) {
p.run_next(blackboard); // will mutate the blackboard
}
```
For more informations, consult the
[documentation](https://linkdd.github.io/aitoolkit/group__goap.html).
## Documentation
The documentation is available online [here](https://linkdd.github.io/aitoolkit).
You can build it locally using [doxygen](https://www.doxygen.nl/):
```
$ make docs
```
## License
This library is released under the terms of the [MIT License](./LICENSE.txt).
", Assign "at most 3 tags" to the expected json: {"id":"6834","tags":[]} "only from the tags list I provide: [{"id":77,"name":"3d"},{"id":89,"name":"agent"},{"id":17,"name":"ai"},{"id":54,"name":"algorithm"},{"id":24,"name":"api"},{"id":44,"name":"authentication"},{"id":3,"name":"aws"},{"id":27,"name":"backend"},{"id":60,"name":"benchmark"},{"id":72,"name":"best-practices"},{"id":39,"name":"bitcoin"},{"id":37,"name":"blockchain"},{"id":1,"name":"blog"},{"id":45,"name":"bundler"},{"id":58,"name":"cache"},{"id":21,"name":"chat"},{"id":49,"name":"cicd"},{"id":4,"name":"cli"},{"id":64,"name":"cloud-native"},{"id":48,"name":"cms"},{"id":61,"name":"compiler"},{"id":68,"name":"containerization"},{"id":92,"name":"crm"},{"id":34,"name":"data"},{"id":47,"name":"database"},{"id":8,"name":"declarative-gui "},{"id":9,"name":"deploy-tool"},{"id":53,"name":"desktop-app"},{"id":6,"name":"dev-exp-lib"},{"id":59,"name":"dev-tool"},{"id":13,"name":"ecommerce"},{"id":26,"name":"editor"},{"id":66,"name":"emulator"},{"id":62,"name":"filesystem"},{"id":80,"name":"finance"},{"id":15,"name":"firmware"},{"id":73,"name":"for-fun"},{"id":2,"name":"framework"},{"id":11,"name":"frontend"},{"id":22,"name":"game"},{"id":81,"name":"game-engine "},{"id":23,"name":"graphql"},{"id":84,"name":"gui"},{"id":91,"name":"http"},{"id":5,"name":"http-client"},{"id":51,"name":"iac"},{"id":30,"name":"ide"},{"id":78,"name":"iot"},{"id":40,"name":"json"},{"id":83,"name":"julian"},{"id":38,"name":"k8s"},{"id":31,"name":"language"},{"id":10,"name":"learning-resource"},{"id":33,"name":"lib"},{"id":41,"name":"linter"},{"id":28,"name":"lms"},{"id":16,"name":"logging"},{"id":76,"name":"low-code"},{"id":90,"name":"message-queue"},{"id":42,"name":"mobile-app"},{"id":18,"name":"monitoring"},{"id":36,"name":"networking"},{"id":7,"name":"node-version"},{"id":55,"name":"nosql"},{"id":57,"name":"observability"},{"id":46,"name":"orm"},{"id":52,"name":"os"},{"id":14,"name":"parser"},{"id":74,"name":"react"},{"id":82,"name":"real-time"},{"id":56,"name":"robot"},{"id":65,"name":"runtime"},{"id":32,"name":"sdk"},{"id":71,"name":"search"},{"id":63,"name":"secrets"},{"id":25,"name":"security"},{"id":85,"name":"server"},{"id":86,"name":"serverless"},{"id":70,"name":"storage"},{"id":75,"name":"system-design"},{"id":79,"name":"terminal"},{"id":29,"name":"testing"},{"id":12,"name":"ui"},{"id":50,"name":"ux"},{"id":88,"name":"video"},{"id":20,"name":"web-app"},{"id":35,"name":"web-server"},{"id":43,"name":"webassembly"},{"id":69,"name":"workflow"},{"id":87,"name":"yaml"}]" returns me the "expected json"