Перейти к основному содержимому

Структура сценария

Теперь разберемся со структурой сценария. Создадим интенты для осуществления переходов по стейтам, а также применим функции, которые мы написали ранее.

Start

В стейте Start запускается сценарий. Под тегом script обнуляем все сессионные переменные. Затем посылаем приветственное сообщение и предлагаем выбрать, кто начнет игру. Содержит три вложенных стейта: Computer, User и LocalCatchAll.

state: Start || modal = true
q!: $regex</start>
intent!: /LetsPlay
script:
$session = {}
$client = {}
$temp = {}
$response = {}
a: Привет! Предлагаю сыграть в игру "Города". Кто загадывает город: компьютер или пользователь?

state: User
intent: /user
a: Назовите город
script:
$session.keys = Object.keys($Cities);
$session.prevBotCity = 0;
go!: /LetsPlayCitiesGame

state: Computer
intent: /computer
script:
$session.keys = Object.keys($Cities);
var city = $Cities[chooseRandCityKey($session.keys)].value.name
$reactions.answer(city)
$session.prevBotCity = city
go!: /LetsPlayCitiesGame

state: LocalCatchAll
event: noMatch
a: Это не похоже на ответ. Попробуйте еще раз.

Предусмотрим переход в стейт Правила из любого другого стейта по фразе давай поиграем. Для этого создадим интент /LetsPlay.

Перейдите на вкладку NLU > Интенты, расположенную в боковом меню. Создайте интент /LetsPlay и добавьте в поле Тренировочные фразы фразы: хочу играть, играть, давай поиграем, давай играть.

Интент letsplay

Установим стейту Start флаг modal = true. Он используется, когда от клиента нужно получить важную информацию, без которой диалог не может продолжаться. В нашем случае игра не может быть продолжена, пока пользователь не выберет, кто начнет игру первым.

подсказка

User

Переход в стейт User осуществляется по интенту /user. Затем выводится сообщение Назовите город.

state: User
intent: /user
a: Назовите город
script:
$session.keys = Object.keys($Cities);
$session.prevBotCity = 0;
go!: /LetsPlayCitiesGame

Создайте интент /user и добавьте в поле Тренировочные фразы фразы человек, пользователь, я, не ты.

Интент user

подсказка
Дополните тренировочные фразы своими вариантами. Чем больше вариаций фраз, тем больше вероятность того, что ваш бот сможет правильно среагировать на сообщения пользователя.

В теге script присваиваем переменной $session.keys массив из id городов, находящихся в списке city/cities-ru.csv.

Обнуляем переменную $session.prevBotCity, в которой будем в дальнейшем хранить город, названный ботом. Затем с помощью тега go! осуществляем переход в следующий стейт LetsPlayCitiesGame.

Computer

Переход в стейт Computer осуществляется по интенту /computer.

state: Computer
intent: /computer
script:
$session.keys = Object.keys($Cities);
var city = $Cities[chooseRandCityKey($session.keys)].value.name
$reactions.answer(city)
$session.prevBotCity = city
go!: /LetsPlayCitiesGame

Создайте интент /computer и добавьте в поле Тренировочные фразы фразы компьютер, комп, бездушный кусок железа, ты, не я.

Интент computer

В теге script присваиваем переменной $session.keys массив из id городов, находящихся в списке city/cities-ru.csv.

В переменную city записываем случайно выбранный город с помощью функции chooseRandCityKey(). Воспользуемся встроенной функцией $reactions.answer(), чтобы вывести город из city в качестве ответа бота.

Записываем в переменную $session.prevBotCity названный ботом город. Затем переходим в стейт LetsPlayCitiesGame.

LocalCatchAll

Если в стейте установлен флаг modal = true, то система обработает запрос в контексте этого стейта. Следовательно, запрос может попасть только в один из его вложенных стейтов.

Если пользователь введет сообщение, не предусмотренное интентами /computer и /user, то система выдаст ошибку. Лог ошибки сообщит, что в сценарии не найден стейт для перехода. Поэтому создадим локальный стейт LocalCatchAll, который будет срабатывать на сообщения, не предусмотренные установленными стейтами.

state: LocalCatchAll
event: noMatch
a: Это не похоже на ответ. Попробуйте еще раз.

LetsPlayCitiesGame

Стейт LetsPlayCitiesGame содержит вложенные стейты CityPattern и NoMatch.

 state: LetsPlayCitiesGame
state: CityPattern
q: * $City *
script:
if (isAFullNameOfCity()) {
if (checkLetter($parseTree._City.name, $session.prevBotCity) == true
|| $session.prevBotCity == 0) {
var removeCity = findByName($parseTree._City.name, $session.keys, $Cities)

if (checkCity($parseTree, $session.keys, $Cities) == true) {
$session.keys.splice(removeCity, 1)
var key = responseCity($parseTree, $session.keys, $Cities)
if (key == 0) {
$reactions.answer("Я сдаюсь")
} else {
$reactions.answer($Cities[key].value.name)
$session.prevBotCity = $Cities[key].value.name
removeCity = findByName($Cities[key].value.name, $session.keys, $Cities)
$session.keys.splice(removeCity, 1)
}
} else $reactions.answer("Этот город уже был назван")
}
} else $reactions.answer("Используйте только полные названия городов")

state: NoMatch
event: noMatch
a: Я не знаю такого города. Попробуйте ввести другой город

CityPattern

Переход в стейт CityPattern выполняется по паттерну * $City *, указанному в теге q.

В теге script осуществляется логика игры:

  • В первом условии проверяем, что пользователь ввел полное название города. Если условие не было выполнено, то выводим сообщение:
Используйте только полные названия городов
  • Если первое условие было выполнено, то проверяем совпадает ли первая буква введенного пользователем города с последней буквой введенного ботом слова или же переменная $session.prevBotCity равна 0.
  • Если условие выполняется, то сохраняем введенный город в переменную removeCity и переходим к следующей проверке.
  • Проверяем не был ли назван город ранее. Если уже был, то выводим сообщение:
Этот город уже был назван

Иначе, удаляем из общего списка введенный город. В переменную key записываем результат вызова функции responseCity().

  • Если переменная key равна 0, значит города на последнюю и предпоследнюю букву закончились. Бот выведет сообщение Я сдаюсь.
  • Иначе выводим загаданный ботом город и удаляем его из списка всех городов.

NoMatch

Если пользователь допустит ошибку при вводе города или назовет несуществующий город, то сработает событие noMatch. Бот выведет сообщение:

Я не знаю такого города. Попробуйте ввести другой город

EndGame

Стейт EndGame обрабатывает конец игры, когда пользователь не хочет больше продолжать игру.

state: EndGame
intent!: /endThisGame
a: Очень жаль! Если передумаешь — скажи "давай поиграем"

Создайте глобальный интент /endThisGame, по которому будет осуществлен переход в стейт EndGame из любого другого стейта. Добавьте в поле Тренировочные фразы фразы стоп, надоело, сдаюсь, я устал, хватит.

Интент endThisGame

Теперь перейдем к тестированию разработанного сценария.