Analyseur de règles générique pour les règles des jeux de société RPG - comment faire?

19

Je veux construire un analyseur de règles générique pour les systèmes RPG de style stylo et papier. Une règle peut impliquer généralement 1 à N entités 1 à N rôles d'un dé et calculer des valeurs en fonction de plusieurs attributs d'une entité.

Par exemple:

Le joueur a STR 18, son arme actuellement équipée lui donne un bonus de +1 STR mais un malus de DEX -1. Il attaque une entité monstre et la logique du jeu est maintenant requise pour exécuter un ensemble de règles ou d'actions:

Le joueur lance les dés, s'il obtient par exemple 8 ou plus (la valeur d'attaque de base dont il a besoin pour passer est l'un de ses attributs de base!) Son attaque est réussie. Le monstre lance ensuite les dés pour calculer si l'attaque passe par son armure. Si oui, les dégâts sont subis sinon l'attaque a été bloquée.

En plus des règles mathématiques simples peuvent également avoir des contraintes comme s'appliquer uniquement à une certaine classe d'utilisateurs (guerrier vs assistant par exemple) ou tout autre attribut. Donc, cela ne se limite pas aux opérations mathématiques.

Si vous connaissez des systèmes RPG comme Dungeon and Dragons, vous saurez ce que je fais.

Mon problème est maintenant que je ne sais pas comment construire exactement cela de la meilleure façon possible. Je veux que les gens puissent mettre en place n'importe quel type de règle et ensuite faire simplement une action comme sélectionner un joueur et un monstre et exécuter une action (un ensemble de règles comme une attaque).

Je demande moins d'aide pour le côté base de données, mais plutôt pour trouver une structure et un analyseur afin de garder mes règles flexibles. La langue de choix pour cela est d'ailleurs PHP.

Modifier I:

Permettez-moi d'affiner mon objectif: je veux créer une interface conviviale (qui ne nécessite pas que quelqu'un apprenne un langage de programmation) pour construire des règles de jeu plus ou moins complexes. La raison simple: une utilisation personnelle pour ne pas avoir besoin de se souvenir de toutes les règles tout le temps, nous ne jouons tout simplement pas souvent et c'est un bouchon pour les rechercher à chaque fois. Aussi: Cela ressemble à une tâche amusante à faire et à apprendre. :)

Ce que j'ai essayé jusqu'à présent: penser à un concept au lieu de perdre du temps à construire une mauvaise architecture. Jusqu'à présent, j'ai l'idée de permettre à un utilisateur de créer autant d'attributs qu'il le souhaite, puis d'attribuer autant d'attributs qu'il le souhaite à tout type d'entité. Une entité peut être un joueur, un monstre, un objet, n'importe quoi. Désormais, lors du calcul de quelque chose, les données sont mises à la disposition de l'analyseur de règles afin que l'analyseur de règles puisse faire des choses comme si Player.base_attack + dice (1x6)> Monster.armor_check puis Monster.health - 1; La question ici est de savoir comment créer cet analyseur.

Edit II:

Voici un exemple de valeur assez basique mais pour le calculer correctement, il y a beaucoup de choses et de variables différentes à prendre en compte:

Bonus d'attaque de base (durée) Votre bonus d'attaque de base (communément appelé BAB par la communauté d20) est un bonus de jet d'attaque dérivé de la classe et du niveau du personnage. Les bonus d'attaque de base augmentent à différents taux pour différentes classes de personnages. Un personnage gagne une deuxième attaque par round lorsque son bonus d'attaque de base atteint +6, un troisième avec un bonus d'attaque de base de +11 ou plus, et un quatrième avec un bonus d'attaque de base de +16 ou plus. Bonus d'attaque de base gagnés dans différentes classes, comme pour un personnage multiclasse, pile. Le bonus d'attaque de base d'un personnage n'accorde plus d'attaque après avoir atteint +16, ne peut pas être inférieur à +0 et n'augmente pas en raison des niveaux de classe une fois que le niveau du personnage atteint le 20e. Un bonus d'attaque de base minimum est requis pour certains exploits.

Vous pouvez le lire ici http://www.dandwiki.com/wiki/Base_Attack_Bonus_(Term) y compris les liens vers les classes et les exploits qui ont à nouveau leurs propres règles pour calculer les valeurs requises pour l'attaque de base.

J'ai commencé à penser que le garder aussi générique que possible rendrait également assez difficile d'obtenir un bon analyseur de règles.

burzum
la source
2
En fait, je pensais exactement à ce type de problème ce matin (non lié au RPG, mais aux moteurs de traitement des règles) et j'essayais de penser à des approches de machines non étatiques pour le traitement des règles et à la façon dont les analyseurs combinatoires sont si efficaces pour accomplir une tâche habituellement effectuée par machines d'état. Je pense qu'il existe une riche possibilité pour les combinateurs monadiques d'aborder plus proprement la plupart des problèmes de machine d'état. Cela peut sembler du charabia, mais je pense qu'il y a quelque chose dans cette idée, juste mes 2 cents. Les systèmes RPG sont un problème de pratique amusant classique. J'aime le codage, je vais peut-être essayer cette approche.
Jimmy Hoffa
1
@jk. cet article me rappelle un modèle que j'ai aimé pour l'analyse des arguments du programme de ligne de commande, en utilisant un dictionnaire de Funcs qui initialise l'état du programme en fonction des arguments comme clés du dictionnaire. Surpris, je n'avais jamais trouvé ce post de Yegge auparavant, très cool, merci de l'avoir signalé.
Jimmy Hoffa
4
Je ne sais pas vraiment pourquoi cela a été clos car "pas une vraie question". Il s'agit d'une question de «tableau blanc» de niveau supérieur sur la façon d'architecturer une application qui a un ensemble spécifique d'exigences (système de règles RPG). J'ai voté pour le rouvrir, mais il aura encore besoin de 4 autres votes de réouverture pour être rouvert.
Rachel
1
Honnêtement, je pensais que ce site est exactement pour ce genre de questions conceptuelles tandis que stackoverflow.com est pensé pour des problèmes de code / implémentation.
burzum

Réponses:

9

Ce que vous demandez est essentiellement un langage spécifique au domaine - un petit langage de programmation à des fins étroites, dans ce cas, définissant les règles RPG P&P. Concevoir une langue n'est en principe pas difficile, mais il y a une quantité considérable de connaissances initiales que vous devez acquérir pour être productif. Malheureusement, il n'y a pas de référence centrale pour ce genre de choses - vous devez le récupérer par le biais d'essais, d'erreurs et de nombreuses recherches.

Tout d'abord, trouvez un ensemble d'opérations primitives grâce auxquelles d'autres opérations peuvent être implémentées. Par exemple:

  • Obtenez ou définissez une propriété du joueur, d'un PNJ ou d'un monstre

  • Obtenez le résultat d'un jet de dé

  • Évaluer les expressions arithmétiques

  • Évaluer les expressions conditionnelles

  • Effectuer une ramification conditionnelle

Concevez une syntaxe qui exprime vos primitives. Comment représenterez-vous les nombres? À quoi ressemble une déclaration? Les instructions se terminent-elles par un point-virgule? Terminé à la nouvelle ligne? Existe-t-il une structure en blocs? Comment allez-vous l'indiquer: à travers des symboles ou une indentation? Y a-t-il des variables? Qu'est-ce qui constitue un nom de variable légal? Les variables sont-elles mutables? Comment allez-vous accéder aux propriétés des objets? Les objets sont-ils de première classe? Pouvez-vous les créer vous-même?

Écrivez un analyseur qui transforme votre programme en une arborescence de syntaxe abstraite (AST). En savoir plus sur l'analyse des instructions avec un analyseur de descente récursif. Découvrez comment analyser des expressions arithmétiques avec une descente récursive est ennuyeux, et un analyseur de priorité d'opérateur de haut en bas (analyseur Pratt) peut vous faciliter la vie et raccourcir votre code.

Écrivez un interprète qui évalue votre AST. Il peut simplement lire chaque nœud de l'arbre et faire ce qu'il dit: a = bdevient new Assignment("a", "b")devient vars["a"] = vars["b"];. Si cela vous facilite la vie, convertissez l'AST sous une forme plus simple avant l'évaluation.

Je recommande de concevoir la chose la plus simple qui fonctionnera et restera lisible. Voici un exemple de ce à quoi pourrait ressembler une langue. Votre conception différera nécessairement en fonction de vos besoins et préférences spécifiques.

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

Vous pouvez également apprendre à intégrer un langage de script existant tel que Python ou Lua dans votre application et l'utiliser. L'inconvénient de l'utilisation d'un langage à usage général pour une tâche spécifique au domaine est que l'abstraction est fuyante: toutes les fonctionnalités et les accrochages du langage sont toujours présents. L'avantage est que vous n'avez pas à le mettre en œuvre vous-même - et c'est un avantage important. Considère-le.

Jon Purdy
la source
2
Pas une mauvaise approche, mais je suis toujours sceptique vis-à-vis des DSL, ils ont beaucoup de travail à faire correctement (surtout si vous parlez d'un vrai DSL avec une syntaxe personnalisée et tout, par opposition à une API couramment utilisée par les gens) commencé à appeler "DSL" s, donc vous feriez mieux d'être sûr que vous allez utiliser le diable hors de lui, si vous êtes alors ça vaut le coup. Souvent, je pense que les gens veulent essayer une DSL où ils ne vont l'utiliser que pour un petit moteur de règles. Voici ma règle d'or: si la mise en œuvre + l'utilisation de DSL est moins de code que pas de DSL, allez-y, je ne pense pas que ce serait le cas dans ce cas.
Jimmy Hoffa
1
@JimmyHoffa: Très bien. C'est juste dans ma nature de rechercher des solutions basées sur le langage, en particulier pour les jeux. Je sous-estime probablement la difficulté de faire quelque chose de petit et fonctionnel parce que je l'ai fait plusieurs fois. Pourtant, cela semble être une recommandation appropriée dans ce cas.
Jon Purdy
Je suppose que je devrais dire que c'est la bonne approche pour ce genre de problème, mais cela dépend de la personne qui effectue la mise en œuvre étant quelqu'un avec des compétences suffisantes. Pour l'apprentissage, les DSL sont parfaits pour les juniors, mais pour un produit réellement libérable, je ne voudrais jamais voir quelqu'un de niveau inférieur écrire un DSL, et pour un junior, un problème résoluble DSL devrait être résolu d'une manière différente.
Jimmy Hoffa
Après avoir lu ceci, je pense que je pourrais simplement évaluer les scripts lua pour cela. L'inconvénient ici serait qu'un utilisateur doit être capable d'écrire des scripts lua. Mon objectif personnel est d'écrire une interface qui peut être utilisée sans connaissances en programmation, comme le générateur de règles dans magento (application de commerce électronique). Parce que je veux que les gens puissent ajouter leurs propres règles. Je n'implémente rien de commercial, juste un outil pour me permettre à mes amis d'entrer dans les règles du système RPG que nous jouons sur une base irrégulière et revenir aux règles et les appliquer est une douleur après un certain temps ...
Burzum
1
@burzum: Et si votre interface générait les scripts lua?
TMN
3

Je commencerais par déterminer les différentes "phases" de chaque action.

Par exemple, une phase de combat peut impliquer:

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

Chacune de ces méthodes aurait accès à certains objets assez génériques, tels que le Playeret le Monster, et effectuerait des vérifications assez génériques que d'autres entités peuvent utiliser pour modifier les valeurs.

Par exemple, vous pourriez avoir quelque chose qui ressemble à ceci inclus dans votre GetPlayerCombatStats()méthode:

GetPlayerCombatStats()
{
    Stats tempStats = player.BaseStats;

    player.GetCombatStats(player, monster, tempStats);

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

Cela vous permet d'ajouter facilement n'importe quelle entité avec des règles spécifiques, telles qu'une classe de joueur, un monstre ou une pièce d'équipement.

Comme autre exemple, supposons que vous vouliez une épée de tout tuer sauf Squid , ce qui vous donne +4 contre tout, sauf si cette chose a des tentacules, auquel cas vous devez laisser tomber votre épée et obtenir un -10 au combat.

Votre classe d'équipement pour cette épée pourrait avoir un GetCombatStatsqui ressemble à ceci:

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

Cela vous permet de modifier facilement les valeurs de combat sans avoir besoin de connaître le reste de la logique de combat, et cela vous permet d'ajouter facilement de nouvelles pièces à l'application parce que les détails et la logique d'implémentation de votre équipement (ou de n'importe quelle entité) ne sont que doivent exister dans la classe d'entité elle-même.

Les éléments clés à déterminer sont à quels points les valeurs peuvent-elles changer et quels éléments influencent ces valeurs. Une fois que vous les avez, la création de vos composants individuels devrait être facile :)

Rachel
la source
C'est la voie à suivre. Dans la plupart des RPG Pen & Paper, il y a des phases dans les calculs, qui sont généralement écrites dans les guides. Vous pouvez également placer l'ordre des étapes dans une liste ordonnée pour la rendre plus générique.
Hakan Deryal du
Cela me semble assez statique et ne permet pas à un utilisateur de simplement entrer / construire les règles requises dans une interface utilisateur? Ce que vous décrivez ressemble plus à des règles codées en dur. Cela devrait également être possible en ayant une liste de règles imbriquées. Je ne veux coder en dur aucune règle. Si je pouvais tout faire dans le code, je n'aurais pas besoin de poser cette question, ce serait facile. :)
burzum
@burzum Oui, cela signifie que les règles seraient définies par le code, mais cela le rend très extensible à partir du code. Par exemple, si vous souhaitez ajouter un nouveau type de classe, ou une nouvelle pièce d'équipement, ou un nouveau type de monstre, il vous suffit de créer les objets de classe pour cette entité et de remplir les méthodes appropriées de votre classe avec votre logique.
Rachel
@burzum Je viens de lire la modification de votre question. Si vous voulez un moteur de règles que pour l' interface utilisateur, j'envisager de faire une piscine d'entités ( Player, Monster, Dice, etc.), et la mise en place quelque chose qui permet aux utilisateurs de pièces d'entités glisser / déposer dans une zone « équation », remplissant les paramètres de l'entité (comme le remplissage player.base_attack) et spécifiez des opérateurs simples sur la façon dont les pièces s'emboîtent. J'ai en fait publié quelque chose sur mon blog qui analyse une équation mathématique que vous pourriez utiliser.
Rachel
@Rachel, ce que vous décrivez est une POO extrêmement simple, il existe même de nombreux exemples dans la nature qui utilisent des trucs comme les RPG comme exemples pour enseigner la POO. Avoir ces objets et travailler avec eux est la partie facile, je pourrais les construire à la volée sur la base des données de la base de données. Le problème dans votre approche réside dans les règles enregistrées comme GetEnemyCombatStats (), quelle que soit la méthode utilisée, elle devrait être définie quelque part via une interface utilisateur et stockée dans une base de données. Votre article semble être similaire à celui de github.com/bobthecow/Ruler ou à celui de github.com/Trismegiste/PhpRules .
burzum
0

Je jetterais un coup d'œil à maptool en particulier au framework 4e éd . C'est le meilleur système que j'ai vu pour configurer ce dont vous parlez. Malheureusement, le meilleur est encore horriblement cruel. Leur système "macro" a ... disons ... évolué avec le temps.

Quant à un "analyseur de règles", je m'en tiendrai au langage de programmation avec lequel vous êtes à l'aise, même si c'est PHP. Il n'y aura aucun moyen de contourner toutes les règles de votre système.

Maintenant, si vous voulez que vos utilisateurs puissent écrire LEUR PROPRE ensemble de règles, alors vous envisagez d'implémenter votre propre langage de script. Les utilisateurs écrivent leurs propres actions de haut niveau, votre php interprète cela en quelque chose qui affecte réellement les valeurs de la base de données, puis il jette un tas d'erreurs car c'est un système horriblement cru qui a été mis en place au fil des ans. Vraiment, la réponse de Jon Purdy est juste sur le ballon.

Philippe
la source
0

Je pense que vous devez être en mesure de penser de manière abstraite à ce qui va se passer dans votre espace problématique, de trouver une sorte de modèle, puis de baser votre DSL sur cela.

Par exemple, vous pourriez avoir l'entité entités, l'action et l'événement au niveau supérieur. Les jets de dé sont des événements qui se produisent à la suite d'actions. Les actions auraient des conditions qui déterminent si elles sont disponibles dans une situation donnée et un "script" des choses qui se produisent lorsque l'action est entreprise. Des choses plus complexes seraient la capacité de définir une séquence de phases où différentes actions peuvent se produire.

Une fois que vous avez une sorte de modèle conceptuel (et je vous suggère de l'écrire et / ou de dessiner des diagrammes pour le représenter), vous pouvez commencer à examiner différents moyens de le mettre en œuvre.

Une voie consiste à définir ce qu'on appelle un DSL externe où vous définissez votre syntaxe et utilisez un outil tel que antlr pour l'analyser et appeler votre logique. Une autre voie consiste à utiliser les fonctionnalités présentes dans un langage de programmation pour définir votre DSL. Des langues telles que Groovy et Ruby sont particulièrement bonnes dans cet espace.

Un piège que vous devez éviter est de mélanger votre logique d'affichage avec votre modèle de jeu implémenté. Je voterais pour que l'affichage lise votre modèle et s'affiche correctement plutôt que de mélanger votre code d'affichage mélangé avec votre modèle.

Peter Kelley
la source