Структура сценария
Теперь разберемся со структурой сценария. Создадим интенты для осуществления переходов по стейтам, а также применим функции, которые мы написали ранее.
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
и добавьте в поле Тренировочные фразы фразы: хочу играть
, играть
, давай поиграем
, давай играть
.
Установим стейту Start
флаг modal = true
. Он используется, когда от клиента нужно получить важную информацию, без которой диалог не может продолжаться. В нашем случае игра не может быть продолжена, пока пользователь не выберет, кто начнет игру первым.
User
Переход в стейт User
осуществляется по интенту /user
. Затем выводится сообщение Назовите город
.
state: User
intent: /user
a: Назовите город
script:
$session.keys = Object.keys($Cities);
$session.prevBotCity = 0;
go!: /LetsPlayCitiesGame
Создайте интент /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
и добавьте в поле Тренировочные фразы фразы компьютер
, комп
, бездушный кусок железа
, ты
, не я
.
В теге 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
из любого другого стейта. Добавьте в поле Тренировочные фразы фразы стоп
, надоело
, сдаюсь
, я устал
, хватит
.
Теперь перейдем к тестированию разработанного сценария.