Analizador de reglas genérico para reglas de juego de mesa RPG: ¿cómo hacerlo?

19

Quiero construir un analizador genérico de reglas para los sistemas RPG de estilo lápiz y papel. Una regla puede involucrar usualmente de 1 a N entidades de 1 a N roles de un dado y calcular valores basados ​​en múltiples atributos de una entidad.

Por ejemplo:

El jugador tiene STR 18, su arma actualmente equipada le da una bonificación de +1 STR pero un malus de DEX -1. Ataca a una entidad monstruosa y la lógica del juego ahora es necesaria para ejecutar un conjunto de reglas o acciones:

El jugador tira el dado, si obtiene por ejemplo 8 o más (¡el valor de ataque base que necesita pasar es uno de sus atributos base!) Su ataque es exitoso. El monstruo tira los dados para calcular si el ataque atraviesa su armadura. En caso afirmativo, el daño se toma si no, el ataque fue bloqueado.

Además, las reglas matemáticas simples también pueden tener restricciones como aplicar solo a una determinada clase de usuario (guerrero vs mago, por ejemplo) o cualquier otro atributo. Por lo tanto, esto no se limita solo a las operaciones matemáticas.

Si estás familiarizado con los sistemas RPG como Dungeon and Dragons, sabrás lo que estoy haciendo.

Mi problema ahora es que no tengo idea de cómo construir exactamente esto de la mejor manera posible. Quiero que las personas puedan establecer cualquier tipo de regla y luego simplemente realizar una acción como seleccionar un jugador y un monstruo y ejecutar una acción (conjunto de reglas como un ataque).

Estoy pidiendo menos ayuda con el lado de la base de datos, pero más acerca de cómo crear una estructura y un analizador para que mantenga mis reglas flexibles. El lenguaje de elección para esto es php por cierto.

Editar I:

Permítanme refinar mi objetivo: quiero crear una interfaz fácil de usar (que no requiera que alguien aprenda un lenguaje de programación) para construir reglas de juego más o menos complejas. La razón simple: uso personal para no tener que recordar todas las reglas todo el tiempo, simplemente no jugamos tan a menudo y es un obstáculo para buscarlas cada vez. Además: parece una tarea divertida para hacer y aprender algo. :)

Lo que he intentado hasta ahora: solo pensar en un concepto en lugar de perder el tiempo construyendo una arquitectura incorrecta. Hasta ahora tengo la idea de permitir que un usuario cree tantos atributos como quiera y luego asigne tantos atributos como quiera a cualquier tipo de entidad. Una entidad puede ser un jugador, un monstruo, un objeto, cualquier cosa. Ahora, al calcular algo, los datos se ponen a disposición del analizador de reglas para que el analizador de reglas pueda hacer cosas como si Player.base_attack + dice (1x6)> Monster.armor_check luego Monster.health - 1; La pregunta aquí es sobre cómo crear ese analizador.

Editar II:

Aquí hay un ejemplo de valor bastante básico, pero para calcularlo correctamente hay muchas cosas y variables diferentes a tener en cuenta:

Bono de ataque base (término) Su bono de ataque base (comúnmente conocido como BAB por la comunidad d20) es un bono de tirada de ataque derivado de la clase y el nivel del personaje. Las bonificaciones de ataque base aumentan a diferentes velocidades para diferentes clases de personajes. Un personaje gana un segundo ataque por ronda cuando su bonificación de ataque base alcanza +6, una tercera con una bonificación de ataque base de +11 o superior, y una cuarta con una bonificación de ataque base de +16 o superior. Las bonificaciones de ataque base obtenidas de diferentes clases, como por ejemplo para un personaje multiclase, se acumulan. La bonificación de ataque base de un personaje no otorga más ataques después de alcanzar +16, no puede ser inferior a +0 y no aumenta debido a los niveles de clase después de que el nivel de personaje alcanza el 20. Se requiere una bonificación de ataque base mínima para ciertas hazañas.

Puedes leerlo aquí http://www.dandwiki.com/wiki/Base_Attack_Bonus_(Term) incluyendo los enlaces a clases y hazañas que tienen nuevamente sus propias reglas para calcular los valores necesarios para el ataque base.

Comencé a pensar que mantenerlo tan genérico como sea posible también hará que sea bastante difícil hacer un buen analizador de reglas.

burzum
fuente
2
En realidad, estaba pensando exactamente en este tipo de problema esta mañana (no relacionado con RPG, sino con motores de procesamiento de reglas) y tratando de pensar en enfoques de máquinas no estatales para el procesamiento de reglas y cómo los analizadores combinatorios son tan efectivos para completar una tarea que generalmente realizan máquinas de estado. Creo que existe una gran posibilidad para que los combinadores monádicos aborden la mayoría de los problemas de máquinas de estado de manera más limpia. Puede sonar a galimatías, pero creo que hay algo en esta idea, solo mis 2 centavos. Los sistemas RPG son un problema clásico de práctica divertida. Me gusta la codificación, tal vez probaré este enfoque.
Jimmy Hoffa
1
@jk. ese artículo me recuerda un patrón que me ha gustado para el análisis de argumentos del programa de línea de comandos, usando un diccionario de Funcs que inicializa el estado del programa basado en los argumentos como claves del diccionario. Sorprendido, nunca encontré esa publicación de Yegge antes, muy genial, gracias por señalarlo.
Jimmy Hoffa
44
No estoy realmente seguro de por qué esto se cerró como "no es una pregunta real". Es una pregunta de "pizarra" de nivel superior sobre cómo diseñar una aplicación que tenga un conjunto específico de requisitos (sistema de reglas RPG). He votado para volver a abrirlo, pero aún necesitará otros 4 votos para volver a abrir.
Rachel
1
Honestamente, pensé que este sitio es exactamente para este tipo de preguntas conceptuales, mientras que stackoverflow.com está pensado para problemas de código / implementación.
burzum

Respuestas:

9

Lo que está pidiendo es esencialmente un lenguaje específico de dominio, un lenguaje de programación pequeño para un propósito limitado, en este caso, definir reglas de RPG de P&P. Diseñar un idioma no es, en principio, difícil, pero hay una considerable cantidad de conocimiento inicial que debes obtener para ser productivo. Desafortunadamente, no hay una referencia central para estas cosas: hay que recogerlas mediante prueba, error y mucha investigación.

Primero, encuentre un conjunto de operaciones primitivas mediante las cuales se puedan implementar otras operaciones. Por ejemplo:

  • Obtener o establecer una propiedad del jugador, un NPC o un monstruo

  • Obtenga el resultado de un dado

  • Evaluar expresiones aritméticas

  • Evaluar expresiones condicionales

  • Realizar ramificaciones condicionales

Diseña una sintaxis que exprese tus primitivas. ¿Cómo representarás los números? ¿Cómo se ve una declaración? ¿Las declaraciones terminan en punto y coma? ¿Nueva línea terminada? ¿Hay estructura de bloque? ¿Cómo lo indicará: a través de símbolos o sangría? ¿Hay variables? ¿Qué constituye un nombre de variable legal? ¿Las variables son mutables? ¿Cómo accederá a las propiedades de los objetos? ¿Son los objetos de primera clase? ¿Puedes crearlos tú mismo?

Escriba un analizador que convierta su programa en un árbol de sintaxis abstracta (AST). Aprenda acerca de las declaraciones de análisis con un analizador de descenso recursivo. Aprenda acerca de cómo analizar expresiones aritméticas con descenso recursivo es molesto, y un analizador de precedencia de operador de arriba hacia abajo (analizador Pratt) puede hacer su vida más fácil y su código más corto.

Escriba un intérprete que evalúe su AST. Simplemente puede leer cada nodo en el árbol y hacer lo que dice: a = bse new Assignment("a", "b")convierte en vars["a"] = vars["b"];. Si le facilita la vida, convierta el AST en una forma más simple antes de la evaluación.

Recomiendo diseñar lo más simple que funcione y siga siendo legible. Aquí hay un ejemplo de cómo se vería un idioma. Su diseño necesariamente diferirá según sus necesidades y preferencias específicas.

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

Alternativamente, aprenda a incrustar un lenguaje de script existente como Python o Lua en su aplicación, y úselo. La desventaja de usar un lenguaje de propósito general para una tarea específica de dominio es que la abstracción es permeable: todas las características y aspectos del lenguaje aún están presentes. La ventaja es que no tiene que implementarlo usted mismo, y eso es una ventaja significativa. Considéralo.

Jon Purdy
fuente
2
No es un mal enfoque, pero soy siempre escéptico con respecto a las DSL, son mucho trabajo para hacerlo bien (especialmente si se trata de una verdadera DSL con sintaxis personalizada y todo, en lugar de solo una API fluida que la gente tiene comenzó a llamar "DSL" s, por lo que es mejor estar seguro de que va a utilizarlo, si es así, entonces vale la pena. Muchas veces creo que la gente quiere intentar un DSL donde solo lo van a usar para un pequeño motor de reglas. Esta es mi regla general: si la implementación de DSL + uso es menos código que no DSL, anímate, no creo que sea así en este caso.
Jimmy Hoffa
1
@ Jimmy Jimmy: Bastante justo. Está en mi naturaleza buscar soluciones basadas en el lenguaje, especialmente para juegos. Probablemente subestimo la dificultad de hacer algo pequeño y funcional porque lo he hecho muchas veces. Aún así, parece una recomendación adecuada en este caso.
Jon Purdy
Supongo que debería decir que es el enfoque correcto para este tipo de problema, pero eso se basa en que la persona que realiza la implementación es alguien con suficiente habilidad. Para aprender, los DSL son excelentes para juniors, pero para un producto real liberable nunca quisiera ver a nadie por debajo del nivel senior escribiendo un DSL, y para un junior, un problema solucionable de DSL debería resolverse de una manera diferente.
Jimmy Hoffa
Después de leer esto, creo que simplemente podría evaluar los scripts lua para eso. La desventaja aquí sería que un usuario tiene que ser capaz de escribir scripts lua. Mi objetivo personal es escribir una interfaz que pueda usarse sin conocimientos de programación, como el creador de reglas en magento (aplicación de comercio electrónico). Porque quiero que las personas puedan agregar sus propias reglas. No estoy implementando nada comercial, solo una herramienta para permitirme a mí y a mis amigos ingresar las reglas del sistema RPG que jugamos de forma irregular y volver a las reglas y aplicarlas es un dolor después de un tiempo ...
burzum
1
@burzum: ¿Qué tal si su interfaz genera los scripts lua?
TMN
3

Comenzaría por determinar las diferentes "Fases" de cada acción.

Por ejemplo, una Fase de combate podría involucrar:

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

Cada uno de estos métodos tendría acceso a algunos objetos bastante genéricos, como el Playery el Monster, y realizaría algunas comprobaciones bastante genéricas que otras entidades pueden usar para modificar los valores.

Por ejemplo, es posible que tenga algo similar a esto incluido en su GetPlayerCombatStats()método:

GetPlayerCombatStats()
{
    Stats tempStats = player.BaseStats;

    player.GetCombatStats(player, monster, tempStats);

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

Esto le permite agregar fácilmente cualquier entidad con reglas específicas, como una clase de jugador, monstruo o pieza de equipo.

Como otro ejemplo, supongamos que desea un Espada de matar todo excepto el calamar , que le da +4 contra todo, a menos que esa cosa tenga tentáculos, en cuyo caso tiene que soltar su espada y obtener un -10 en el combate.

Su clase de equipo para esta espada podría tener un GetCombatStatsaspecto similar a este:

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

Esto le permite modificar fácilmente los valores de combate sin necesidad de conocer el resto de la lógica de combate, y le permite agregar fácilmente nuevas piezas a la aplicación porque los detalles y la lógica de implementación de su Equipo (o cualquier entidad que sea) solo necesita existir en la clase de entidad misma.

La clave para descubrir es en qué puntos pueden cambiar los valores y qué elementos influyen en esos valores. Una vez que los tenga, construir sus componentes individuales debería ser fácil :)

Rachel
fuente
Ese es el camino a seguir. En la mayoría de los juegos de rol de Pen & Paper, hay fases en los cálculos, que generalmente se escriben en las guías. También puede poner el orden de la etapa en una lista ordenada para hacerlo más genérico.
Hakan Deryal el
Esto me suena bastante estático y no permite que un usuario simplemente ingrese / cree las reglas requeridas en una interfaz de usuario. Lo que describe suena más como reglas codificadas. Esto también debería ser posible al tener una lista de reglas anidadas. No quiero codificar ninguna regla. Si pudiera hacer todo en código, no necesitaría hacer esa pregunta, eso sería fácil. :)
burzum
@burzum Sí, esto significa que las reglas serían definidas por el código, sin embargo, lo hace muy extensible desde el código. Por ejemplo, si desea agregar un nuevo tipo de clase, o una nueva pieza de equipamiento, o un nuevo tipo de monstruo, solo necesita construir los objetos de clase para esa entidad y completar los métodos apropiados en su clase con su lógica.
Rachel
@burzum Acabo de leer la edición de tu pregunta. Si quieres un motor de reglas sólo para uso de interfaz de usuario, consideraría hacer un grupo de entidades ( Player, Monster, Dice, etc.), y la creación de algo que permite a los usuarios piezas entidad arrastrar / soltar en un área de "ecuación", rellenando los parámetros de la entidad (como completar player.base_attack) y especificar operadores simples sobre cómo encajan las piezas. De hecho, tengo algo publicado en mi blog que analiza una ecuación matemática que puede usar.
Rachel
@Rachel, lo que describe es una OOP muy fácil, incluso hay muchos ejemplos en la naturaleza que usan cosas similares a los juegos de rol como ejemplos para enseñar OOP. Tener estos objetos y trabajar con ellos es la parte fácil, podría construirlos sobre la marcha en función de los datos de la base de datos. El problema en su enfoque son las reglas codificadas como GetEnemyCombatStats () lo que sea que haga este método necesitaría definirse en algún lugar a través de una interfaz de usuario y almacenarse en una base de datos. Su artículo parece ser similar a ese github.com/bobthecow/Ruler o ese github.com/Trismegiste/PhpRules .
burzum
0

Echaría un vistazo a maptool específicamente el marco de la 4ª ed . De Rumble . Es el mejor sistema que he visto para configurar de qué estás hablando. Lamentablemente, lo mejor sigue siendo horriblemente cruel. Su sistema "macro" ha ... digamos ... evolucionado con el tiempo.

En cuanto a un "analizador de reglas", me quedaría con cualquier lenguaje de programación con el que se sienta cómodo, incluso si es PHP. No habrá una buena forma de codificar todas las reglas de su sistema.

Ahora, si desea que sus usuarios puedan escribir SU PROPIO conjunto de reglas, entonces está buscando implementar su propio lenguaje de secuencias de comandos. Los usuarios escriben sus propias acciones de alto nivel, su php lo interpreta como algo que realmente afecta los valores de la base de datos, y luego arroja un montón de errores porque es un sistema horriblemente rudo que ha sido implementado a lo largo de los años. Realmente, la respuesta de Jon Purdy es correcta.

Philip
fuente
0

Creo que debe ser capaz de pensar de manera abstracta sobre las cosas que van a estar en su espacio problemático, idear algún tipo de modelo y luego basar su DSL en eso.

Por ejemplo, puede tener las entidades entidad, acción y evento en el nivel superior. Las tiradas de dados serían eventos que ocurren como resultado de acciones. Las acciones tendrían condiciones que determinarían si están disponibles en una situación dada y un "guión" de las cosas que ocurren cuando se toma la acción. Las cosas más complejas serían la capacidad de definir una secuencia de fases donde pueden ocurrir diferentes acciones.

Una vez que tenga algún tipo de modelo conceptual (y le sugiero que lo escriba y / o dibuje diagramas para representarlo) puede comenzar a buscar diferentes medios para implementarlo.

Una ruta es definir lo que se llama un DSL externo donde define su sintaxis y utiliza una herramienta como antlr para analizarla y llamar a su lógica. Otra ruta es utilizar las instalaciones presentes en un lenguaje de programación para definir su DSL. Idiomas como Groovy y Ruby son particularmente buenos en este espacio.

Una trampa que debes evitar es mezclar tu lógica de visualización con tu modelo de juego implementado. Votaría para que la pantalla lea su modelo y se muestre adecuadamente en lugar de mezclar su código de pantalla entremezclado con su modelo.

Peter Kelley
fuente