[#] Метапарсер
Andrew Lobanov(station13, 1) — All
2016-02-15 16:27:27


Автор: Петр Косых
Ссылка: http://ifprint.org/articles/metaparser/

INSTEAD начался как проект, который пытался избежать подхода CYOA при разработке текстовых квестов и реализовать игровой процесс как в «настоящем квесте», но только в текстовом виде.

Как вы наверняка знаете, классические текстовые приключения – это парсерные игры, в которых моделируется мир, и герой исследует этот мир под чутким управлением игрока, описывающего желаемые действия с помощью клавиатуры. Тут и клавиатура, и способ моделирования мира работают на создание общей цели – у игрока возникает чувство свободы и тайны. Ты можешь перемещаться по миру, взаимодействовать с ним – в этом смысле такая игра и есть настоящая «адвенчура» (квест).

CYOA игры — это игры с управлением через меню, обычно сводящиеся к выбору вариантов развития событий («убежать», «показать пропуск охраннику» и т.д.). Такая игра зачастую выглядит как сборник параграфов, нередко описывающих целые сюжетные повороты, а не только (и не столько) локации (места действия, декорации) с переходами между ними. В этом смысле жанр таких игр больше тяготеет к книгам-играм, хотя, конечно, многое зависит от конкретной игры.

Если же отойти от текстовых игр и посмотреть на классические графические квесты (из золотого фонда Lucas Arts и Sierra), то там мы увидим что-то среднее: либо глаголы, как в «Monkey Island», либо манипуляции предметами, как в «Goblins», либо что-то смешанное. Тем не менее, эти игры больше похожи на парсерные игры в том смысле, что герой свободно исследует мир, а его способ взаимодействия с миром носит условно свободный характер (набор универсальных действий, свободная манипуляция предметами и т.д.). Фактически, это и есть парсерные игры, которые перешли в графическую плоскость, заодно сильно упростив способ ввода.


Путь INSTEAD

INSTEAD начинался как проект по созданию движка для игры, которая, будучи текстовой, по своему игровому процессу не сильно отличалась бы от классических графических квестов. Такой первой игрой стала «Возвращение квантового кота».

В этой игре был выбран упрощенный ввод в виде свободного манипулирования предметами, что сильно снижало порог вхождения для потенциального игрока, но вместе с тем оставляло поле для свободы. Потом по мере развития движка появились игры с глагольным меню, которые еще больше сблизили текстовые квесты с классикой (правда, такие игры обычно обладали повышенной сложностью). В качестве примеров таких игр можно назвать «Кайлет» (набор глаголов) и «Особняк» (три глагола).


Чувство парсера

Тем не менее, мне было всегда интересно посмотреть, можно ли сблизить игру с парсером еще теснее, при этом не сильно подняв порог вхождения. Можно ли взять лучшее от INSTEAD подхода и парсера?

Кое-какой опыт по работе с парсером у меня был. Еще перед написанием INSTEAD я изучал Inform и даже писал небольшую игру, поэтому я примерно представлял проблемы и плюсы парсерной игры на русском языке.

Огромное преимущество парсерных игр – глубокое погружение. Во время игры игрок вынужден читать и думать, это очень сильно отличается от CYOA игр и все еще отличается от игр с глагольным меню. Именно эта черта заставляла экспериментировать с игровым вводом. Однако такие игры сложнее писать, особенно на русском, и (что не менее важно) в них не так просто играть!

Обычно неявным образом подразумевается, что идеальный парсер – это ИИ, который понимает все, что напишет игрок. Это и сила и слабость одновременно. Я не верю, что компьютер научится думать (по крайней мере, в обозримом будущем), а это значит, что ИИ, который бы мог учитывать в полной мере контекст введенных команд и вообще угадывать то, что игрок хочет сделать в свободной разговорной форме – утопия. Во всех существующих реализациях парсер пытается претвориться умным с разной степенью успешности, но любой парсер бессильно проигрывает, когда за клавиатуру садится неподготовленный игрок, который воображает, что игра поймет все, что он напишет.

Если же совместить это с богатством русского языка, то получится, что в русские парсерные игры способны играть далеко не все, да и даже подготовленный игрок с большой долей вероятности натолкнется на ситуации, где отсутствие привычного ему синонима отобьет всю охоту заканчивать игру.

В этом смысле, подход в реализации парсера как поиска по шаблонам может показаться перспективным. Суть его в том, что парсер не пытается понять что именно ввел игрок, а просто реагирует на заведомо забитые в него шаблоны игровой ситуации. Таким образом, задача игрока – угадать, хотя бы приблизительно, что от него требуется, а задача автора – написать хорошие шаблоны. Реализация может быть разной, но суть примерно такова. В качестве примера можно привести Adrift.

В какой-то момент я решил, что это хорошая идея и сделал свой концепт парсера, основанного на шаблонах. К счастью, даже отрицательный результат — это результат. Мой концепт оказался провальным. Основные недостатки шаблонного парсера:

* игрок по прежнему думает, что парсер понимает все;
* парсер слишком широко понимает игрока, в итоге возникают казусы, когда игрок получает совсем неожиданную реакцию на свои действия;
* парсер не понимает ввод, и вывод неудачных реакций не информативен;
* писать игру очень сложно, так как не так просто написать правильные, непротиворечивые шаблоны

В общем, пришлось оставить эту идею. Однако, меня не покидала мысль, что есть и другой путь. И действительно этот путь нашелся!


Квазипарсер или метапарсер?

Я давно заметил, что с ростом числа глаголов в глагольном меню чувство игры начинает приближаться к «парсерке». Правда при этом возникали другие проблемы: захламление меню и всевозрастающая сложность написания игры (так как универсальные обработчики неудачных действий ничего не знают о смысле действий, о падежных формах и вообще не занимаются анализом, то в целях литературности приходится вручную прописывать реакции на всевозможные действия). В то же время в парсерной игре указанных проблем нет.

Тогда меня внезапно посетила мысль о создании парсера, который работает одновременно и на принципах меню и на принципах парсера, взяв лучшее из обоих миров. Я подумал, что задачу абсолютной непротиворечивости интеллекта парсера можно решить не за счет его усложнения, а наоборот, за счет его упрощения. Другими словами, игрок не может ввести действия, которые не будут поняты игре, или же игрок должен постоянно как-то видеть, понимает ли его игра в данный момент.

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

К слову, забегая вперед, когда я рассказал (и показал прототип) своего парсера другу, он предложил назвать его «квазипарсер». В каком-то смысле — это точное определение, так как мой парсер не обладает никаким интеллектом. Тем не менее я назвал его «метапарсер», так как на мой взгляд, он обладает теми преимуществами, которые я искал.

Итак, нужно было решить две проблемы.

Первая из проблем – парсер должен уметь делать склонения, так как настоящая парсерная игра предполагает десятки и сотни действий, которые автор игры не обязан (да и не способен) прописывать сам. Например, если в игре есть дверь и ее можно открыть и закрыть, то движок сам в состоянии отреагировать на команды «открыть» или «закрыть дверь» на основании указания, что объект «дверь» может открываться. Или предметы, которые можно подбирать и бросать. Фразу «я взял яблоко» вполне может сформировать и сам движок. Но гораздо важнее, чтобы движок мог среагировать на непрописанное действие вроде такого:

" > толкнуть Габриэллу
Габриэлле это не понравится!

На самом деле, чтобы научить движок склонять слова, можно пойти двумя путями.

Первый путь — это при описании объекта четко описать его характеристики: число, род, одушевленность. Выделить окончание и воспользоваться алгоритмом для формирования склонений. У такого подхода есть пара существенных недостатков:

* алгоритм склонений не универсален;
* код игры становится сложным, высокий порог вхождения для автора игры.

Второй путь — это использование словаря. В этом случае для описания объекта только иногда необходимо указать одушевленность — и все. Тем не менее, и у этого подхода есть свои недостатки:

* объем словаря велик;
* иногда, в словаре может не быть нужного слова.

Я не пошел по пути алгоритма главным образом потому, что это сильно затрудняет написание игры (я помнил это еще по моим экспериментом с Inform). В итоге в метапарсере я использовал словарь, взяв за основу базу с aot.ru. К счастью, формат словаря оказался понятным. Кроме того я нашел его черновое описание, и в итоге мне удалось сконвертировать его для удобного распознавания внутри Lua. Фактически, за пару недель решение проблемы склонений было найдено! Словарь в UTF-8 кодировке занимает около 8 МБ и для повышения скорости и снижения объема игры был выбран путь компиляции словаря для конкретной игры. В итоге получаемый словарь вышел очень маленьким и быстрым, так как содержал только то, что реально нужно.

Результат мне очень понравился, ситуации, когда словарь срабатывал неправильно, можно было пересчитать по пальцам, кроме того оставалась возможность вписать свои варианты склонений (например, имя «Габриэлла»).

Осталось сделать совсем немного – сам парсер. :)

Идея была в следующем. Парсер понимает некий набор глаголов с переменным числом параметров. Например, можно написать:

" >бросить лампу в гоблина

или просто:

" >бросить лампу

Оба действия – это действие «бросить», но в одном случае мы бросаем лампу в гоблина, а во втором — избавляемся от нее. Погружаться в детали пока не будем, но суть в том, что парсер всегда знает множество того, что может ввести игрок. То есть метапарсер в каком-то смысле обратен парсеру. Он не пытается понять, что пишет игрок – он знает, что вообще можно написать, и следит, какую из веток набирает сейчас игрок.

Такое устройство парсера означает, что в любой момент времени он может подсказать игроку возможные варианты. Например, игрок пишет:

" >бросить л_

В этот момент парсер знает, что игрок хочет написать какое-то слово, которое начинается на букву «л». Так как это слово должно быть предметов из сцены или инвентаря, то парсеру не составляет никакой сложности подсказать его.

Конечно, я сейчас упростил идею для наглядности, но суть метапарсера имено в этом – он знает, что именно можно ввести в каждый конкретный момент и предлагает это игроку в виде подсказок. Конечно, в реальной реализации присутствуют многие другие вещи, о которых я пока не рассказываю просто для того, чтобы пояснить саму идею.

Подсказки выводятся в каждый момент времени в виде списка слов, которые можно продолжать набирать (а также подставить автоматически, нажав TAB) или просто щелкнуть по ним мышкой. Это приводит к тому, что в метапарсер можно играть без клавиатуры.

Моими первыми экспериментами стали маленькие игры: «roboto» и «Перекресток миров» от yandexx. Спасибо ему за любезное разрешение портировать эти небольшие игры! Потом Василий Воронков выпустил свою игру на метапарсере, которая реализовала несколько другой подход для игрока, самой заметной чертой которого является тот факт, что игрок не видит подсказок глаголов до того момента, пока не начнет набирать их на клавиатуре.

Опыт этих игр показал, что к вводу можно привыкнуть довольно быстро. К тому же, когда играешь в игру на метапарсере, ощущения практически идентичны ощущениям от классических парсерных игр, но недостатки последних отсутствуют!

Процесс написания игры тоже выглядит довольно элегантно – все лучшее я забрал из Inform 6 (в основном, идею цепочки сообщений), но из-за упрощенного устройства метапарсера и наличия словаря написание игры для метапарсера оказывается проще написания игры для Inform.

В данный момент метапарсер еще не вполне готов, но в скором времени я планирую выпустить документацию для того, чтобы все, кого это заинтересовало, могли попробовать свои силы в написании своей истории. Конечно, сам факт наличия метапарсера не означает снижение интереса к INSTEAD-играм с классическим управлением. Следует понимать, что даже в варианте «метапарсера» от игрока требуется большая концентрация, что подходит далеко не всем, поэтому метапарсер после релиза просто займет свое место среди других модулей INSTEAD, и, кто знает, может быть, кто-то напишет с его помощью отличную игру.

Да, конечно, можно возразить, что полученный движок — это не парсер. С чем я безговорочно соглашусь. Ведь это и правда не парсер. Это — «метапарсер». :)