AI GOAP - планировщик целеориентированного ИИ
AI Goap
- это реализация GOAP
(Goal Oriented Action Planning) планировщика последовательности не связанных явно между собой действий для достижения определенной цели. Звучит не очень понятно, давайте разбираться.
Введение
Деревья Поведения
(BehaviourTree
) - это самая распространенная реализация для игрового ИИ, с которой все начинают, а часто и заканчивают, так как предоставляемого функционала для простых ботов хватает. Когда же схемы разрастаются, то возникает проблема по настройке старых и добавлению новых взаимосвязей между узлами действий - на сцену выходит GOAP
.
GOAP
- это подход к разработке ИИ для игровых персонажей, основанный на планировании действий с учетом целей. GOAP
позволяет персонажам принимать решения и планировать свои действия на основе текущей ситуации и желаемых целей.
Основная идея GOAP
заключается в том, что персонажи имеют набор целей, которые они стремятся достичь, и набор действий, которые они могут выполнить для достижения этих целей. Планировщик GOAP
анализирует текущую ситуацию, оценивает доступные действия и выбирает оптимальную последовательность действий, которая приведет к достижению выбранной цели.
Преимущество GOAP
заключается в гибкости и адаптивности за счет отсутствия явных связей между действиями, что позволяет достаточно просто расширять логику поведения.
Основные определения GOAP
- Условие. Флаг-признак чего-то, может быть либо в состоянии “Да”, либо “Нет”.
- Действие. Абстрактный элемент-узел плана действий.
GOAP
ничего не знает о том, что происходит вДействии
и требует явно переключатьУсловия
, на которые влияет этоДействие
. - Требования. Набор
Условий
, которые должны выполниться для того, чтобыДействие
стало возможным к использованию. - Планировщик. Сердце
GOAP
, получает список действий, стартовое состояниеУсловий
, цель, состоящую из таких жеУсловий
. На выход подает список действий в нужной последовательности для достижения указанной цели. Если цель недостижима - информирует об этом.
Пример
Ну и давайте рассмотрим простой пример - бот может быть “голодным”, он умеет “заказывать пиццу”, умеет “готовить еду” сам, умеет “ждать” и умеет “есть”.
“Заказывать”, “Ждать”, “Готовить” и “Есть” - это Действия
.
“Голодный”, “Есть номер телефона”, “Позвонил в пиццерию”, “Жду заказ”, “Есть ингредиенты”, “Еда в наличии” - это Условия
.
Переведем это в код:
Условия
1 | enum Conditions { |
Действия
1 | // Действие "Позвонить в пиццерию и сделать заказ" |
Теперь давайте попробуем построить план. Пусть бот будет голодным
, у него будет номер пиццерии
, задача перестать испытывать голод
:
1 | List<string> result = new(); |
Цель может быть как достижима, так и нет, об этом планировщик просигнализирует, вернув флаг успеха. Если путь валидный - мы можем просмотреть шаги плана:
1 | if (valid) { |
Результат:
“Call,WaitOrder,Eat” - “Позвонить в пиццерию”, “Подождать заказа”, “Съесть”.
Так, а что если номера нет, а есть ингредиенты для еды?
1 | // Инициализация планировщика та же, отличаются только параметры у Run(). |
Результат:
“Cook,Eat” - “Приготовить еду”, “Съесть”.
Отлично. Но что будет, если у нас есть и номер пиццерии и ингредиенты?
1 | // Инициализация планировщика та же, отличаются только параметры у Run(). |
Результат:
“Cook,Eat” - “Приготовить еду”, “Съесть”.
Тот же результат, но почему? У каждого действия есть “сложность/стоимость”, которая по умолчанию равна 1.0f
. Получается "Call,WaitOrder,Eat" => 1+1+1=3
, а "Cook,Eat" => 1+1=2
- самый “дешевый/простой” вариант победил. Мы можем настраивать этот параметр у каждого действия отдельно, давайте сделаем сложность приготовления пищи равной 10.0f
:
1 | class CookAction : IGoapAction<string> { |
Реализация действия осталась прежней, добавился метод Cost()
, который возвращает новую “сложность/стоимость” действия. Запускаем тест еще раз:
Результат:
“Call,WaitOrder,Eat” - “Позвонить в пиццерию”, “Подождать заказа”, “Съесть”.
Так получилось потому, что "Call,WaitOrder,Eat" => 1+1+1=3
, а "Cook,Eat" => 10+1=11
- победил заказ еды в пиццерии.
А что если у нас нет ни номера пиццерии, ни ингредиентов?
1 | var valid = planner.Run ( |
Результат:
“Нет плана” - цель недостижима.
Вот таким нехитрым способом строится план действий, который уже потом можно использовать для выполнения ботом.
Актуальные версии пакетов доступны в закрытом telegram-сервере для vk/boosty-подписчиков.