Behaviors — конечный автомат без головной боли

Стандартный подход к описанию последовательности вводов пользователя и реакции на них (например при управлении персонажем в игре) — это конечный автомат (state machine). Он, однако, часто приводит к громоздким программам, понимание которых требует немалых усилий или даже зарисовок на бумаге. В этой статье я предлагаю небольшой сдвиг в описании, который позволяет экономить место на экране и мозговой ресурс.

image

Сдвиг в описании заключается в использовании техники сопрограмм. Для применения этой техники, необходимо представить, какое поведение мы ожидаем от компьютера в итоге. Поэтому я назвал небольшую библиотеку, которую создал под эту задачу — Behaviors.
Когда пользователь взаимодействует с программой, компьютер ждет определенного действия и реагирует на ввод определенным образом. Примитивные Behaviors и их комбинации могут заменить громоздкие конечные автоматы (state machines), которые зачастую формально или неформально встречаются в программах. К примеру, когда программа находится в состоянии ожидания нажатия определенной клавиши, можно сказать, что она выполняет Behavior waitForKey (…). Удобство в том, что Behaviors комбинируются в легко читаемой форме в отличие от конечных автоматов. Простой пример Drag&Drop:

* DragAndDrop =
    * draggedObject = ждем MouseDown на каком-то объекте
    * First
        * ждем MouseUp
        * Forever
            * ждем MouseMove
            * Двигаем draggedObject


Behavior имеет начало, конец и может возвращать значение. Behaviors исполняются по порядку или могут исполняться параллельно с помощью комбинаторов. Например комбинатор First исполняет несколько Behaviors параллельно и заканчивается, когда одно из Behaviors окончено, возвращая его результат. Forever — повторяет исполнение определенного Behavior до бесконечности. В отличии от исполнения функции, Behavior не блокирует основной поток исполнения, таким образом бесконечные Behaviors могут быть очень полезными.

Я реализовал Behaviors с помощью функций, которые получают примитивные события (как MouseDown, MouseUp, MouseMove, …) в качестве параметра и выдают объект вида:

{
    done: true|false,
    value: result value
}


Реализацию можно посмотреть здесь: behavior.js на GitHubе, а пример Drag&Drop здесь: jsFiddle.

Где можно применять Behaviors?

  • Компьютерные игры — очень удобно писать логику и ИИ, иногда даже делаю все с Behaviors, включая анимацию и передвижение объектов, но надо следить за производительностью
  • Туториал во фронтенде (тур по новым функциям) — показываем информацию, ждем интеракции пользователя, продолжаем в зависимости от ввода, весь код в одном месте и читается почти как псевдокод
  • Парсер предметно ориентированного языка — идиоматический код, нет необходимости «заглядывать вперед» по вводу, так как можно исполнять несколько Behaviors параллельно

Фото: Behavior by Nick Youngson CC BY-SA 3.0 Alpha Stock Images

© Habrahabr.ru