{"id":18257925,"url":"https://github.com/linkdd/aitoolkit","last_synced_at":"2025-04-05T05:06:17.735Z","repository":{"id":216093241,"uuid":"740454687","full_name":"linkdd/aitoolkit","owner":"linkdd","description":"Give a brain to your game's NPCs","archived":false,"fork":false,"pushed_at":"2024-05-08T14:18:53.000Z","size":1334,"stargazers_count":478,"open_issues_count":0,"forks_count":26,"subscribers_count":6,"default_branch":"main","last_synced_at":"2025-03-29T04:06:07.368Z","etag":null,"topics":["ai","behavior-tree","cpp","cpp23","finite-state-machine","gamedev","gamedev-library","goal-oriented-action-planning","utility-ai"],"latest_commit_sha":null,"homepage":"https://linkdd.github.io/aitoolkit/","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/linkdd.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":["linkdd"],"patreon":null,"open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"otechie":null,"lfx_crowdfunding":null,"custom":null}},"created_at":"2024-01-08T11:33:43.000Z","updated_at":"2025-03-28T14:22:32.000Z","dependencies_parsed_at":"2024-11-05T10:56:23.945Z","dependency_job_id":null,"html_url":"https://github.com/linkdd/aitoolkit","commit_stats":null,"previous_names":["linkdd/aitoolkit"],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/linkdd%2Faitoolkit","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/linkdd%2Faitoolkit/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/linkdd%2Faitoolkit/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/linkdd%2Faitoolkit/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/linkdd","download_url":"https://codeload.github.com/linkdd/aitoolkit/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247289426,"owners_count":20914464,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai","behavior-tree","cpp","cpp23","finite-state-machine","gamedev","gamedev-library","goal-oriented-action-planning","utility-ai"],"created_at":"2024-11-05T10:28:10.805Z","updated_at":"2025-04-05T05:06:17.717Z","avatar_url":"https://github.com/linkdd.png","language":"C++","readme":"# AI Toolkit\n\n\u003ccenter\u003e\n\n![tests](https://img.shields.io/github/actions/workflow/status/linkdd/aitoolkit/tests.yml?style=flat-square\u0026logo=github\u0026label=tests)\n![docs](https://img.shields.io/github/actions/workflow/status/linkdd/aitoolkit/docs.yml?style=flat-square\u0026logo=github\u0026label=docs)\n![license](https://img.shields.io/github/license/linkdd/aitoolkit?style=flat-square\u0026color=blue)\n![version](https://img.shields.io/github/v/release/linkdd/aitoolkit?style=flat-square\u0026color=red)\n\n\u003c/center\u003e\n\n**AI Toolkit** is a header-only C++ library which provides tools for building\nthe brain of your game's NPCs.\n\nIt provides:\n\n - Finite State Machines\n - Behavior Tree\n - Utility AI\n - Goal Oriented Action Planning\n\nWhy 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).\n\n## Installation\n\nAdd the `include` folder of this repository to your include paths.\n\nOr add it as a submodule:\n\n```\n$ git submodule add https://github.com/linkdd/aitoolkit.git\n$ g++ -std=c++23 -Iaitoolkit/include main.cpp -o mygame\n```\n\n\u003e **NB:** This library is compatible with C++20.\n\nOr using [Shipp](https://github.com/linkdd/shipp), add it to your dependencies:\n\n```json\n{\n  \"name\": \"myproject\",\n  \"version\": \"0.1.0\",\n  \"dependencies\": [\n    {\n      \"name\": \"aitoolkit\",\n      \"url\": \"https://github.com/linkdd/aitoolkit.git\",\n      \"version\": \"v0.5.1\"\n    }\n  ]\n}\n```\n\n## Usage\n\n### Finite State Machine\n\nFirst, include the header:\n\n```cpp\n#include \u003caitoolkit/fsm.hpp\u003e\n\nusing namespace aitoolkit::fsm;\n```\n\nThen, create your blackboard type:\n\n```cpp\nstruct blackboard_type {\n  // ...\n};\n```\n\nThen, create a state type for each of your states:\n\n```cpp\nclass state_dummy final : public state\u003cblackboard_type\u003e {\n  public:\n    virtual void enter(blackboard_type\u0026 blackboard) override {\n      // ...\n    }\n\n    virtual void exit(blackboard_type\u0026 blackboard) override {\n      // ...\n    }\n\n    virtual void pause(blackboard_type\u0026 blackboard) override {\n      // ...\n    }\n\n    virtual void resume(blackboard_type\u0026 blackboard) override {\n      // ...\n    }\n\n    virtual void update(blackboard_type\u0026 blackboard) override {\n      // ...\n    }\n};\n```\n\nCreate your simple state machine:\n\n```cpp\nauto simple_bb = blackboard_type{};\nauto simple_fsm = simple_machine\u003cblackboard_type\u003e();\n\nsimple_fsm.set_state(state_dummy{}, simple_bb);\nsimple_fsm.pause(simple_bb);\nsimple_fsm.resume(simple_bb);\nsimple_fsm.update(simple_bb);\n```\n\nOr with a stack state machine:\n\n```cpp\nauto stack_bb = blackboard_type{};\nauto stack_fsm = stack_machine\u003cblackboard_type\u003e{};\n\nstack_fsm.push_state(state_dummy{}, stack_bb);\nstack_fsm.push_state(state_dummy{}, stack_bb);\n\nstack_fsm.update(stack_bb);\n\nstack_fsm.pop_state(stack_bb);\nstack_fsm.pop_state(stack_bb);\n```\n\n### Behavior Tree\n\nFirst, include the header:\n\n```cpp\n#include \u003caitoolkit/behtree.hpp\u003e\n\nusing namespace aitoolkit::bt;\n```\n\nThen, create your blackboard type:\n\n```cpp\nstruct blackboard_type {\n  // ...\n};\n```\n\nThen, create your tree:\n\n```cpp\nauto tree = seq\u003cblackboard_type\u003e(\n  node_list\u003cblackboard_type\u003e(\n    check\u003cblackboard_type\u003e([](const blackboard_type\u0026 bb) {\n      // check some condition\n      return true;\n    }),\n    task\u003cblackboard_type\u003e([](blackboard_type\u0026 bb) {\n      // perform some action\n      return execution_state::success;\n    })\n  )\n);\n```\n\nFinally, evaluate it:\n\n```cpp\nauto blackboard = blackboard_type{\n  // ...\n};\n\nauto state = tree.evaluate(blackboard);\n```\n\nFor more informations, consult the\n[documentation](https://linkdd.github.io/aitoolkit/group__behtree.html).\n\n### Utility AI\n\nFirst, include the header file:\n\n```cpp\n#include \u003caitoolkit/utility.hpp\u003e\n\nusing namespace aitoolkit::utility;\n```\n\nThen, create a blackboard type:\n\n```cpp\nstruct blackboard_type {\n  int food{0};\n  int wood{0};\n  int stone{0};\n  int gold{0};\n};\n```\n\nNext, create a class for each action that you want to be able to perform:\n\n```cpp\nclass collect_food final : public action\u003cblackboard_type\u003e {\n  public:\n    virtual float score(const blackboard_type\u0026 blackboard) const override {\n      return 50.0f;\n    }\n\n    virtual void apply(blackboard_type\u0026 blackboard) const override {\n      blackboard.food += 1;\n    }\n};\n\nclass collect_wood final : public action\u003cblackboard_type\u003e {\n  public:\n    virtual float score(const blackboard_type\u0026 blackboard) const override {\n      return 150.0f;\n    }\n\n    virtual void apply(blackboard_type\u0026 blackboard) const override {\n      blackboard.wood += 1;\n    }\n};\n\nclass collect_stone final : public action\u003cblackboard_type\u003e {\n  public:\n    virtual float score(const blackboard_type\u0026 blackboard) const override {\n      return -10.0f;\n    }\n\n    virtual void apply(blackboard_type\u0026 blackboard) const override {\n      blackboard.stone += 1;\n    }\n};\n\nclass collect_gold final : public action\u003cblackboard_type\u003e {\n  public:\n    virtual float score(const blackboard_type\u0026 blackboard) const override {\n      return 75.0f;\n    }\n\n    virtual void apply(blackboard_type\u0026 blackboard) const override {\n      blackboard.gold += 1;\n    }\n};\n```\n\nFinally, create an evaluator and run it:\n\n```cpp\nauto evaluator = evaluator\u003cblackboard_type\u003e(\n  action_list\u003cblackboard_type\u003e(\n    collect_food{},\n    collect_wood{},\n    collect_stone{},\n    collect_gold{}\n  )\n);\n\nauto blackboard = blackboard_type{};\nevaluator.run(blackboard);\n```\n\n### Goal Oriented Action Planning\n\nFirst, include the header file:\n\n```cpp\n#include \u003caitoolkit/goap.hpp\u003e\n\nusing namespace aitoolkit::goap;\n```\n\nThen, create a blackboard class that will hold the state of the planner:\n\n```cpp\nstruct blackboard_type {\n  bool has_axe{false};\n  int wood{0};\n};\n```\n\n\u003e **NB:** The blackboard needs to be comparable (`a == b`) and hashable.\n\nNext, create a class for each action that you want to be able to perform:\n\n```cpp\nclass get_axe final : public action\u003cblackboard_type\u003e {\n  public:\n    virtual float cost(const blackboard_type\u0026 blackboard) const override {\n      return 1.0f;\n    }\n\n    virtual bool check_preconditions(const blackboard_type\u0026 blackboard) const override {\n      return !blackboard.has_axe;\n    }\n\n    virtual void apply_effects(blackboard_type\u0026 blackboard, bool dry_run) const override {\n      blackboard.has_axe = true;\n    }\n};\n\nclass chop_tree final : public action\u003cblackboard_type\u003e {\n  public:\n    virtual float cost(const blackboard_type\u0026 blackboard) const override {\n      return 1.0f;\n    }\n\n    virtual bool check_preconditions(const blackboard_type\u0026 blackboard) const override {\n      return blackboard.has_axe;\n    }\n\n    virtual void apply_effects(blackboard_type\u0026 blackboard, bool dry_run) const override {\n      blackboard.wood += 1;\n    }\n};\n```\n\nFinally, create a plan and run it:\n\n```cpp\nauto initial = blackboard_type{};\nauto goal = blackboard_type{\n  .has_axe = true,\n  .wood = 3\n};\n\nauto p = planner\u003cblackboard_type\u003e(\n  action_list\u003cblackboard_type\u003e(\n    get_axe{},\n    chop_tree{}\n  ),\n  initial,\n  goal\n);\n\nauto blackboard = initial;\nwhile (p) {\n  p.run_next(blackboard); // will mutate the blackboard\n}\n```\n\nFor more informations, consult the\n[documentation](https://linkdd.github.io/aitoolkit/group__goap.html).\n\n## Documentation\n\nThe documentation is available online [here](https://linkdd.github.io/aitoolkit).\n\nYou can build it locally using [doxygen](https://www.doxygen.nl/):\n\n```\n$ make docs\n```\n\n## License\n\nThis library is released under the terms of the [MIT License](./LICENSE.txt).\n","funding_links":["https://github.com/sponsors/linkdd"],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flinkdd%2Faitoolkit","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flinkdd%2Faitoolkit","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flinkdd%2Faitoolkit/lists"}