Общий анализатор правил для правил настольной игры RPG - как это сделать?

19

Я хочу создать общий синтаксический анализатор правил для ролевых и бумажных систем. Правило может включать в себя от 1 до N объектов от 1 до N ролей игральных костей и вычисления значений на основе нескольких атрибутов объекта.

Например:

У игрока есть STR 18, его экипированное оружие дает ему бонус +1 STR, но малус DEX -1. Он нападает на монстра, и теперь игровая логика необходима для запуска набора правил или действий:

Игрок бросает кубик, если он получает, например, 8 или более (базовое значение атаки, которое он должен пройти, является одним из его базовых атрибутов!), Его атака успешна. Затем монстр бросает кубик, чтобы рассчитать, прошла ли атака его броню. Если да, то ущерб получен, если не атака была заблокирована.

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

Если вы знакомы с системами RPG, такими как Dungeon и Dragons, вы поймете, чем я занимаюсь.

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

Я прошу не столько помощи со стороны базы данных, сколько о том, как придумать структуру и синтаксический анализатор для ее гибкости. Кстати, язык для этого - php.

Изменить I:

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

Что я пробовал до сих пор: просто думать о концепции, а не тратить время на построение неправильной архитектуры. До сих пор у меня была идея позволить пользователю создавать столько атрибутов, сколько они хотят, а затем назначать столько атрибутов, сколько они хотят, любому виду сущности. Сущность может быть игроком, монстром, предметом, чем угодно. Теперь при вычислении чего-либо данные становятся доступными для анализатора правил, так что анализатор правил должен иметь возможность выполнять такие действия, как если Player.base_attack + dice (1x6)> Monster.armor_check, то Monster.health - 1; Вопрос здесь в том, как создать этот парсер.

Редактировать II:

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

Базовый бонус атаки (термин) Ваш базовый бонус атаки (обычно называемый BAB сообществом d20) - это бонус броска атаки, полученный из класса и уровня персонажа. Бонусы базовой атаки увеличиваются с разной скоростью для разных классов персонажей. Персонаж получает вторую атаку за раунд, когда его базовый бонус атаки достигает +6, третий с базовым бонусом атаки +11 или выше, и четвертый с базовым бонусом атаки +16 или выше. Базовые бонусы за атаку, полученные от разных классов, таких как мультиклассовый персонаж, стек. Базовый бонус атаки персонажа не дает больше атак после достижения +16, не может быть меньше +0 и не увеличивается из-за уровней классов после того, как уровень персонажа достигает 20-го. Для определенных умений требуется минимальный базовый бонус атаки.

Вы можете прочитать его здесь http://www.dandwiki.com/wiki/Base_Attack_Bonus_(Term), включая ссылки на классы и умения, которые снова имеют свои собственные правила для расчета значений, необходимых для базовой атаки.

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

Burzum
источник
2
Я действительно думал об этом типе проблемы этим утром (не связанным с RPG, а механизмами обработки правил) и пытался думать о подходах к обработке правил, не связанных с конечным автоматом, и о том, как комбинаторные синтаксические анализаторы настолько эффективны при выполнении задачи, обычно выполняемой конечные автоматы. Я думаю, что у монадных комбинаторов есть богатая возможность более аккуратно подходить к большинству задач конечного автомата. Это может звучать как бред, но я думаю, что в этой идее есть что-то, только мои 2 цента. РПГ-системы - это классическая забавная практика, мне нравится программировать, возможно, я попробую этот подход.
Джимми Хоффа
1
@jk. эта статья напоминает мне шаблон, который мне понравился для разбора аргументов программы командной строки, используя словарь Funcs, который инициализирует состояние программы на основе аргументов в качестве ключей к словарю. Удивленный, я никогда не находил тот пост от Yegge прежде, очень классный, спасибо за то, что указал на это.
Джимми Хоффа
4
Я не совсем уверен, почему это было закрыто как "не реальный вопрос". Это вопрос «белой доски» более высокого уровня о том, как спроектировать приложение, которое имеет определенный набор требований (система правил RPG). Я проголосовал за его повторное открытие, но для его открытия понадобятся еще 4 голоса.
Рейчел
1
Честно говоря, я думал, что этот сайт предназначен именно для такого рода концептуальных вопросов, в то время как stackoverflow.com предназначен для проблем с кодом / реализацией.
Burzum

Ответы:

9

То, что вы запрашиваете, это, по сути, предметно-ориентированный язык - маленький язык программирования для узкой цели, в данном случае определяющий правила P & P RPG. Разработка языка в принципе не сложна, но для того, чтобы быть продуктивным, вы должны получить значительные предварительные знания. К сожалению, нет центральной ссылки на этот материал - вы должны поднять его путем проб, ошибок и большого количества исследований.

Сначала найдите набор примитивных операций, с помощью которых могут быть реализованы другие операции. Например:

  • Получить или установить свойство игрока, NPC или монстра

  • Получить результат броска кубика

  • Оценить арифметические выражения

  • Оценивать условные выражения

  • Выполнить условное ветвление

Разработайте синтаксис, который выражает ваши примитивы. Как вы будете представлять числа? Как выглядит утверждение? Являются ли операторы точкой с запятой? Newline завершающим? Есть ли блочная структура? Как вы это укажете: через символы или отступы? Есть ли переменные? Что представляет собой допустимое имя переменной? Являются ли переменные изменчивыми? Как вы получите доступ к свойствам объектов? Являются ли объекты первоклассными? Можете ли вы создать их самостоятельно?

Напишите синтаксический анализатор, который превращает вашу программу в абстрактное синтаксическое дерево (AST). Узнайте о синтаксическом анализе операторов с помощью синтаксического анализатора с рекурсивным спуском. Узнайте о том, как парсинг арифметических выражений с рекурсивным спуском раздражает, и анализатор приоритетов операторов сверху вниз (анализатор Pratt) может сделать вашу жизнь проще и ваш код короче.

Напишите переводчика, который оценит ваш AST. Он может просто читать каждый узел в дереве и делать то, что говорит: a = bстановится new Assignment("a", "b")становится vars["a"] = vars["b"];. Если это облегчает вашу жизнь, перед оценкой конвертируйте AST в более простую форму.

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

ATK = D20
if ATK >= player.ATK
    DEF = D20
    if DEF < monster.DEF
        monster.HP -= ATK
        if monster.HP < 0
            monster.ALIVE = 0
        end
    end
end

Кроме того, вы можете узнать, как встроить существующий язык сценариев, такой как Python или Lua, в ваше приложение и использовать его. Недостатком использования языка общего назначения для задач, специфичных для предметной области, является то, что абстракция является утечкой: все функции и особенности языка все еще присутствуют. Плюс в том, что вам не нужно реализовывать это самостоятельно, а это существенный плюс. Учти это.

Джон Перди
источник
2
Неплохой подход, но я постоянно скептически отношусь к DSL, они много работают для того, чтобы разобраться (особенно, если вы говорите об истинном DSL с пользовательским синтаксисом и т. Д., В отличие от просто свободного API, который есть у людей начал называть "DSL" s), так что вам лучше быть уверенным, что вы будете использовать чертовски из этого, если это так, то оно того стоит. Часто я думаю, что люди хотят попробовать DSL, где они собираются использовать его только для небольшого механизма правил. Вот мое эмпирическое правило: если реализация DSL + использование меньше кода, чем отсутствие DSL, сделайте это, я не думаю, что это было бы так в этом случае.
Джимми Хоффа
1
@JimmyHoffa: достаточно справедливо. Это просто в моей природе, чтобы достичь языковых решений, особенно для игр. Я, вероятно, недооцениваю сложность создания чего-то маленького и функционального, потому что я делал это много раз. Тем не менее, это похоже на соответствующую рекомендацию в этом случае.
Джон Пурди
Полагаю, я должен сказать, что это правильный подход к такого рода проблемам, но это основано на том, что человек, выполняющий реализацию, является человеком с достаточными навыками. Для обучения DSL отлично подходят для юниоров, но для реального выпускаемого продукта я бы никогда не хотел, чтобы кто-то ниже высшего уровня писал DSL, а для младших решаемая проблема DSL должна решаться другим способом.
Джимми Хоффа
Прочитав это, я думаю, что смогу просто оценить сценарии lua для этого. Недостатком здесь является то, что пользователь должен уметь писать сценарии lua. Моя личная цель - написать интерфейс, который можно использовать без знания программирования, например, конструктор правил в magento (приложение для электронной коммерции). Потому что я хочу, чтобы люди могли добавлять свои собственные правила. Я не внедряю ничего коммерческого, просто инструмент, позволяющий мне и моим друзьям вводить правила системы RPG, в которую мы играем нерегулярно, и возвращаясь к правилам, и применять их - это боль через некоторое время ...
burzum
1
@burzum: А как насчет того, чтобы ваш интерфейс генерировал сценарии lua?
TMN
3

Я бы начал с определения разных «Фаз» каждого действия.

Например, боевая фаза может включать:

GetPlayerCombatStats();
GetEnemyCombatStats();
GetDiceRoll();
CalculateDamage();

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

Например, в вашем GetPlayerCombatStats()методе может быть что-то похожее на это :

GetPlayerCombatStats()
{
    Stats tempStats = player.BaseStats;

    player.GetCombatStats(player, monster, tempStats);

    foreach(var item in Player.EquippedItems)
        item.GetCombatStats(player, monster, tempStats);
}

Это позволяет вам легко добавлять любую сущность с определенными правилами, например, класс игрока, монстра или предмет экипировки.

В качестве другого примера, предположим, что вам нужен Меч истребления всего, кроме кальмара , который дает вам +4 против всего, если только у этого предмета нет щупальцев, и в этом случае вы должны уронить меч и получить -10 в бою.

У вашего класса снаряжения для этого меча может быть GetCombatStatsчто-то вроде этого:

GetCombatStats(Player player, Monster monster, Stats tmpStats)
{
    if (monster.Type == MonsterTypes.Tentacled)
    {
        player.Equipment.Drop(this);
        tmpStats.Attack -= 10;
    }
    else
    {
        tmpStats.Attack += 4;
    }
}

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

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

Рейчел
источник
Это путь. В большинстве RPG Pen & Paper есть этапы в расчетах, которые обычно написаны в путеводителях. Вы также можете поместить порядок этапа в упорядоченный список, чтобы сделать его более общим.
Hakan Deryal
Это звучит довольно статично для меня и не позволяет пользователю просто ввести / построить необходимые правила в пользовательском интерфейсе? То, что вы описываете, больше похоже на жестко закодированные правила. Это должно быть также выполнимо, имея список вложенных правил. Я не хочу жестко задавать какие-либо правила. Если бы я мог делать все в коде, мне не нужно было бы задавать этот вопрос, это было бы легко. :)
burzum
@burzum Да, это означает, что правила будут определены кодом, однако это делает его очень расширяемым из кода. Например, если вы хотите добавить новый тип класса, или новый предмет Equipement, или новый тип Monster, вам просто нужно создать объекты класса для этой сущности и заполнить соответствующие методы в вашем классе своей логикой.
Рэйчел
@burzum Я только что прочитал правку вашего вопроса. Если вы хотите , двигатель правил только для использования пользовательского интерфейса, я хотел бы рассмотреть возможность сделать пул сущностей ( Player, Monster, Dice, и т.д.), а также создание что - то , что позволяет пользователям штук сущностей перетащить / падение в «уравнение» области, заполнение параметров объект (например, заполнение player.base_attack), и укажите простые операторы относительно того, как части сочетаются друг с другом. На самом деле у меня есть кое-что опубликованное в моем блоге, которое анализирует математическое уравнение, которое вы можете использовать.
Рэйчел
@Рэйчел, что вы описываете, очень простой ООП, есть даже много примеров в дикой природе, которые используют RPG-подобные вещи в качестве примеров для обучения ООП. Наличие этих объектов и работа с ними - самая простая часть, я мог бы построить их на лету, основываясь на данных из базы данных. Проблема в вашем подходе заключается в жестких правилах, таких как GetEnemyCombatStats (), что бы этот метод ни делал, его нужно было бы где-то определить через пользовательский интерфейс и сохранить в БД. Ваша статья похожа на github.com/bobthecow/Ruler или github.com/Trismegiste/PhpRules .
Burzum
0

Я бы взглянул на maptool, а именно на 4-й фреймворк Rumble . Это лучшая система, которую я видел для настройки того, о чем вы говорите. К сожалению, лучшее все еще ужасно жестоко. Их "макро" система ... скажем ... развивалась с течением времени.

Что касается "парсера правил", я бы просто придерживался любого языка программирования, который вам удобен, даже если это PHP. Там не будет никакого хорошего способа обойти все правила вашей системы.

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

Филипп
источник
0

Я думаю, что вам нужно уметь абстрактно думать о том, что будет в вашем проблемном пространстве, придумывать какую-то модель и затем основывать свой DSL на этом.

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

Если у вас есть какая-то концептуальная модель (и я предлагаю вам записать ее и / или нарисовать диаграммы для ее представления), вы можете начать искать другие способы ее реализации.

Один из способов - определить то, что называется внешним DSL, где вы определяете свой синтаксис и используете инструмент, такой как antlr, для его анализа и вызова своей логики. Другой способ - использовать средства, имеющиеся в языке программирования, для определения вашего DSL. Такие языки, как Groovy и Ruby, особенно хороши в этом пространстве.

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

Питер Келли
источник