Я хочу создать общий синтаксический анализатор правил для ролевых и бумажных систем. Правило может включать в себя от 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), включая ссылки на классы и умения, которые снова имеют свои собственные правила для расчета значений, необходимых для базовой атаки.
Я начал думать, что поддерживая его как можно более общим, также будет довольно сложно сделать хороший анализатор правил.
Func
s, который инициализирует состояние программы на основе аргументов в качестве ключей к словарю. Удивленный, я никогда не находил тот пост от Yegge прежде, очень классный, спасибо за то, что указал на это.Ответы:
То, что вы запрашиваете, это, по сути, предметно-ориентированный язык - маленький язык программирования для узкой цели, в данном случае определяющий правила P & P RPG. Разработка языка в принципе не сложна, но для того, чтобы быть продуктивным, вы должны получить значительные предварительные знания. К сожалению, нет центральной ссылки на этот материал - вы должны поднять его путем проб, ошибок и большого количества исследований.
Сначала найдите набор примитивных операций, с помощью которых могут быть реализованы другие операции. Например:
Получить или установить свойство игрока, NPC или монстра
Получить результат броска кубика
Оценить арифметические выражения
Оценивать условные выражения
Выполнить условное ветвление
Разработайте синтаксис, который выражает ваши примитивы. Как вы будете представлять числа? Как выглядит утверждение? Являются ли операторы точкой с запятой? Newline завершающим? Есть ли блочная структура? Как вы это укажете: через символы или отступы? Есть ли переменные? Что представляет собой допустимое имя переменной? Являются ли переменные изменчивыми? Как вы получите доступ к свойствам объектов? Являются ли объекты первоклассными? Можете ли вы создать их самостоятельно?
Напишите синтаксический анализатор, который превращает вашу программу в абстрактное синтаксическое дерево (AST). Узнайте о синтаксическом анализе операторов с помощью синтаксического анализатора с рекурсивным спуском. Узнайте о том, как парсинг арифметических выражений с рекурсивным спуском раздражает, и анализатор приоритетов операторов сверху вниз (анализатор Pratt) может сделать вашу жизнь проще и ваш код короче.
Напишите переводчика, который оценит ваш AST. Он может просто читать каждый узел в дереве и делать то, что говорит:
a = b
становитсяnew Assignment("a", "b")
становитсяvars["a"] = vars["b"];
. Если это облегчает вашу жизнь, перед оценкой конвертируйте AST в более простую форму.Я рекомендую разработать простейшую вещь, которая будет работать и оставаться читабельной. Вот пример того, как может выглядеть язык. Ваш дизайн обязательно будет отличаться в зависимости от ваших конкретных потребностей и предпочтений.
Кроме того, вы можете узнать, как встроить существующий язык сценариев, такой как Python или Lua, в ваше приложение и использовать его. Недостатком использования языка общего назначения для задач, специфичных для предметной области, является то, что абстракция является утечкой: все функции и особенности языка все еще присутствуют. Плюс в том, что вам не нужно реализовывать это самостоятельно, а это существенный плюс. Учти это.
источник
Я бы начал с определения разных «Фаз» каждого действия.
Например, боевая фаза может включать:
Каждый из этих методов будет иметь доступ к некоторым довольно общим объектам, таким как
Player
иMonster
, и будет выполнять некоторые довольно общие проверки, которые другие объекты могут использовать для изменения значений.Например, в вашем
GetPlayerCombatStats()
методе может быть что-то похожее на это :Это позволяет вам легко добавлять любую сущность с определенными правилами, например, класс игрока, монстра или предмет экипировки.
В качестве другого примера, предположим, что вам нужен Меч истребления всего, кроме кальмара , который дает вам +4 против всего, если только у этого предмета нет щупальцев, и в этом случае вы должны уронить меч и получить -10 в бою.
У вашего класса снаряжения для этого меча может быть
GetCombatStats
что-то вроде этого:Это позволяет вам легко изменять боевые значения без необходимости знать об остальной боевой логике, и это позволяет вам легко добавлять новые части в приложение, потому что только детали и логика реализации вашего снаряжения (или любой другой сущности это только) нужно существовать в самом классе сущности.
Ключевым моментом, который необходимо выяснить, является то, в каких точках могут изменяться значения, и какие элементы влияют на эти значения. После того, как они у вас есть, создание ваших отдельных компонентов должно быть легко :)
источник
Player
,Monster
,Dice
, и т.д.), а также создание что - то , что позволяет пользователям штук сущностей перетащить / падение в «уравнение» области, заполнение параметров объект (например, заполнениеplayer.base_attack
), и укажите простые операторы относительно того, как части сочетаются друг с другом. На самом деле у меня есть кое-что опубликованное в моем блоге, которое анализирует математическое уравнение, которое вы можете использовать.Я бы взглянул на maptool, а именно на 4-й фреймворк Rumble . Это лучшая система, которую я видел для настройки того, о чем вы говорите. К сожалению, лучшее все еще ужасно жестоко. Их "макро" система ... скажем ... развивалась с течением времени.
Что касается "парсера правил", я бы просто придерживался любого языка программирования, который вам удобен, даже если это PHP. Там не будет никакого хорошего способа обойти все правила вашей системы.
Теперь, если вы хотите, чтобы ваши пользователи могли писать свой собственный набор правил, тогда вы смотрите на реализацию своего собственного языка сценариев. Пользователи пишут свои собственные высокоуровневые действия, ваш php интерпретирует это как нечто, что фактически влияет на значения в базе данных, а затем выдает кучу ошибок, потому что это ужасно хитрая система, которая на протяжении многих лет была введена в заблуждение. На самом деле, ответ Джона Пурди правильный.
источник
Я думаю, что вам нужно уметь абстрактно думать о том, что будет в вашем проблемном пространстве, придумывать какую-то модель и затем основывать свой DSL на этом.
Например, у вас может быть сущность сущностей, действие и событие на верхнем уровне. Броски кубика будут событиями, которые происходят в результате действий. Действия должны иметь условия, которые определяют, доступны ли они в данной ситуации, и «сценарий» того, что происходит при выполнении действия. Более сложные вещи - это способность определять последовательность этапов, на которых могут происходить различные действия.
Если у вас есть какая-то концептуальная модель (и я предлагаю вам записать ее и / или нарисовать диаграммы для ее представления), вы можете начать искать другие способы ее реализации.
Один из способов - определить то, что называется внешним DSL, где вы определяете свой синтаксис и используете инструмент, такой как antlr, для его анализа и вызова своей логики. Другой способ - использовать средства, имеющиеся в языке программирования, для определения вашего DSL. Такие языки, как Groovy и Ruby, особенно хороши в этом пространстве.
Одна из ловушек, которых вы должны избегать, - это смешивать логику отображения с вашей реализованной игровой моделью. Я бы проголосовал за то, чтобы дисплей читал вашу модель и отображал ее соответствующим образом, а не смешивал код вашего дисплея, смешанный с вашей моделью.
источник