Loi de probabilité associée à une combinaison de puces et armes

Loi de probabilité associée à une combinaison de puces et armes

> Programmation

Si vous utilisez un système de calcul de la meilleure combinaison d'items (puces et armes) infligeant des dégâts à votre adversaire, vous avez probablement une façon (personnelle) de calculer les dégâts de la combinaison que vous étudiez : si vous êtes pessimiste, vous prenez par exemple la somme des dégâts minimaux de chaque item, si vous êtes plus neutre vous prenez peut-être la somme des dégâts moyens, ...

Le but de cette page va être de donner des notions de probabilités permettant d'étudier la probabilité associée aux dégâts d'une telle «combo» de manière plus fine.

Warning : cet article demande quelques connaissances en maths. Au moins les notions de lycée de calcul intégral, de préférence quelques notions de probabilités aussi.

Sommaire

> 1. Motivation >2. Tirage aléatoire lors de l'utilisation d'une puce ou d'une arme >3. Approche directe >4. Approche continue >    4.1. Principes >    4.2. Densité de probabilités asociée à un item >    4.3. Convolution >        4.3.1 Introduction : cas discret >        4.3.2 Cas continu >        4.3.3 Quelques propriétés >    4.4. Calcul pratique en LeekScript >        4.4.1 Cas des combos dans Leek Wars : simplifications dues au contexte >        4.4.2 Calcul formel : polynômes >        4.4.3 Fonctions définies par morceaux >        4.4.4 Convolution >        4.4.5 Coups critiques : somme de deux créneaux >5. Gestion de l'armure absolue et des items à dégâts fixes : loi mixte >    5.1. Armure absolue : atome en 0 >        5.1.1 Lois mixtes >        5.1.2 Distribution de Dirac en 0 >    5.2. Items à dégâts fixes et coups critiques : atomes ailleurs >        5.2.1 Coups critiques et atomes >        5.2.2 Distribution de Dirac en un point quelconque >    5.3. Calcul en LeekScript >6. Fonction de répartition et outils de probabilités >    6.1 Définition et calcul >    6.2 Utilisation >7. Remarques

Motivation

Obtenir une valeur moyenne des dégâts faits par une combo n'est pas bien difficile. Cependant, vous pouvez avoir envie d'avoir une information plus précise que la moyenne : si vous cherchez à assurer un minimum de dégâts (par exemple pour avoir de bonnes chances de tuer), la moyenne ne vous aide pas beaucoup.

Prenons un exemple : votre adversaire n'a plus que 430 points de vie, a 155 d'armure absolue, et vous avez 400 de force et pas d'agilité (et donc pas de chances d'obtenir un coup critique). Vous avez sélectionné deux combos qui peuvent tuer l'adversaire : utiliser trois fois votre Rhino, ou utiliser 2 fois votre Fusil.

En effet, les dégâts maximaux infligés avec trois utilisations du Rhino sont donnés par : 3 * (64 * (1 + 400/100) - 155) = 495 et ceux donnés par deux utilisations du fusil sont : 2 * (79 * (1 + 400/100) - 155) = 480 ce qui est supérieur à 430 dans les deux cas, pour un coût en PT similaire (on va supposer que vous en ayez 15, et le rhino en main).

Le calcul des dégâts moyens, qui s'effectue de la même façon, donne 450 pour le rhino comme pour le fusil. Tout ce qu'on peut déduire de la moyenne, c'est que le rhino comme le fusil ont plus de 50% de chances de tuer l'adversaire. Mais cela ne nous aide pas à choisir la combo qui a le plus de chance d'être létale.

On a donc besoin, si l'on veut maximiser les chances de tuer l'adversaire, d'une information plus précise.

> Spoiler : c'est le fusil qui a la meilleure chance, ici, avec 94.4% de chances de tuer, contre 90.4% pour le rhino.

Ce cas, relativement simple, peut paraître sans grand intérêt et peut-être assez intuitif. Les outils présentés ci-dessous permettent de prendre en compte des combos plus variées, ainsi que les chances de coups critiques, qui ont une influence parfois plus obscure sur les probabilités de dégâts.

Notons enfin que cette étude de probabilités peut avoir d'autres applications (se soigner, par exemple, on peut chercher la meilleure combo de soin avec des conditions comme «ne pas se soigner de plus que le nombre de points de vie manquants»). Je ne fais que présenter l'outil ici, à vous de l'utiliser à votre gré.

Tirage aléatoire lors de l'utilisation d'une puce ou d'une arme

Le jeu utilise, à chaque utilisation d'arme ou de puce, un et un seul tirage aléatoire (entre 0 et 1) pour tous les effets. La valeur de chaque effet est alors donnée par : valeur = valeur_min + tirage * (valeur_max - valeur_min) où tirage est le nombre entre 0 et 1 obtenu.

Ce tirage aléatoire est réalisé en tirant un flottant entre 0 et 1 avec une probabilité uniforme : il n'y a pas de flottant qui ait plus de chances que les autres d'apparaître.

Approche directe

On peut calculer, lors de l'utilisation d'un item, la probabilité d'obtenir chacun des résultats possibles : après tout, comme le tirage est fait de façon uniforme, chaque résultat (sauf les résultats extrémaux, qui ont en fait une probabilité deux fois plus faible que les autres) a la même probabilité d'apparition. En effet, chaque valeur k pourra apparaître si le résultat avant arrondi est compris entre k-0.5 et k+0.5, sauf pour le minimum (le tirage ne peut pas donner de valeur inférieure, donc il y a deux fois moins de flottants qui s'arrondissent au minimum, ceux entre k et k+0.5) et le maximum (le tirage ne peut pas donner de valeur supérieure cette fois, même raisonnement).

Ainsi, en utilisant la puce Étincelle avec 400 de force, on peut obtenir des dégâts entre 40 et 80, chaque entier entre ces valeurs a donc une probabilité 1/40 = 0.025 (sauf 40 et 80 qui ont pour probabilité 0.0125).

Et si l'on veut enchaîner plusieurs items, on peut en théorie calculer la probabilité de chaque résultat possible. Par exemple, sans force, sans agilité et sans bouclier sur la cible, pour une combo composée de deux utilisations du Pistolet, la probabilité d'infliger 33 dégâts peut se calculer en trouvant toutes les façons possibles d'obtenir 33 et en additionnant les probabilités de chacune de ces façons. Le calcul ressemblerait donc à ce qui suit :

Comme vous pouvez vous en douter, même s'il existe des façons d'aller plus vite, cette méthode va être laborieuse. En effet, j'ai pris deux items ayant une plage de dégâts assez petite et je n'ai pas donné de force à mon poireau pour éviter d'avoir à traiter trop de cas. Imaginez (ou calculez !) le nombre de valeurs possibles en tapant à la Hache avec 500 de force !

Cette méthode sera donc délicate à mettre en place en pratique. Algorithmiquement, ça peut se faire, mais le coût risque d'être élevé dès que l'on aura beaucoup d'items ou des plages de dégâts assez grandes.

Approche continue

Une façon de gérer une telle quantité de valeurs possible va être de faire comme si le tirage aléatoire pouvait prendre n'importe quelle valeur réelle entre 0 et 1, et pas seulement des flottants. C'est techniquement faux, mais la différence entre les deux cas est assez minime au vu de la quantité importante de flottants possibles entre 0 et 1 (qui est forcément limitée à un nombre fini du fait de l'encodage utilisé, mais qui est tout de même très conséquente).

L'outil que nous allons pouvoir utiliser s'appelle une fonction de densité : c'est une fonction permettant de décrire le comportement d'une quantité aléatoire prenant des valeurs dans l'ensemble des réels (ou une sous-partie, ici un intervalle).

> Note aux matheux chipoteurs : ok, ok, il faudrait quelques conditions... Je parlerai de lois avec atomes plus loin, et je ne parlerai absolument pas de lois de probas singulières, mais bon... ici c'est peu pertinent.

Principes

Bon... Un peu de maths pour introduire les notions.

Une densité de probabilités est une fonction f toujours positive, d'intégrale 1. Elle représente le comportement d'une variable aléatoire X (ici, les dégâts d'une combo) de la façon suivante :

> La probabilité que X prenne une valeur entre deux nombres a et b est donnée par l'intégrale de f entre a et b. Autrement dit, !defDensité

Exemple (avec la densité associée à la combo de deux Étincelles sans stats) :

!Combo 2 sparks

Notez que la fonction f est bien positive et que son intégrale entre les deux extrémités vaut bien 1.

Le calcul de l'intégrale entre 19.5 et 25.5 nous donne comme information que la combo aura une probabilité de 0.574... (soit 57.4%) de faire entre 19.5 et 25.5 dégâts, donc, avec l'arrondi, entre 20 et 25 dégâts.

Les conditions sur la fonction utilisée s'expliquent ainsi :

Si l'on a un moyen de représenter une telle fonction (ce qui fera l'objet de la suite de cet article) associée à une combo, on pourra alors en déduire pas mal d'informations, par exemple :

!ComboValeurPrécise

!ComboAuMoinsd

L'idée est donc de représenter une loi de probabilités non pas par chacune des valeurs possibles et la proba associée, ce qui est lourd à traiter, mais par une fonction dont on peut déduire les informations. Or, dans le cas des probabilités de Leek Wars, ces fonctions vont s'avérer relativement simple à manipuler (voir la mise en pratique plus bas).

Densité de probabilités associée à un item

Ok, bon, c'est bien gentil tout ça, mais comment trouve-t-on les fonctions de densité dans les cas qui nous intéressent (i.e. celui des probabilités de dégâts dans le jeu) ?

Commençons par le cas d'un unique item, sans prendre pour l'instant en compte les statistiques des poireaux (agilité, force, boucliers).

Puisque tous les flottants (du moins tous ceux qui peuvent apparaître...) sur la plage de dégâts de l'item ont la même probabilité, on va utiliser pour les items des fonctions de densité en créneau :

!CreneauSpark

Remarquez que la hauteur du créneau et sa largeur sont liées : l'intégrale devant valoir 1, la hauteur du créneau est donnée en fonction des valeurs de dégâts de l'item par : hauteur = 1/(valeur_max - valeur_min) ce qui dans le cas d'Étincelle sans force, agilité ni bouclier en face, donne 1 / (16 - 8) = 1/8 = 0.125, comme on peut le constater sur le graphe ci-dessus.

Prendre en compte la force n'est alors pas un gros souci : il suffit de calculer la plage de dégâts possibles et de construire le créneau correspondant. Ainsi, pour Étincelle toujours mais avec 400 de force, on a pour dégâts minimaux 40, pour dégâts maximaux 80, et donc un créneau allant de 40 à 80 et de hauteur 1/40 = 0.025 :

!CreneauSparkStrength

Pour manipuler de tels objets en LeekScript, on aurait besoin de stocker deux données (par exemple valeur minimale et valeur maximale, puisqu'on peut en déduire la hauteur du créneau). Cependant, il va s'avérer utile dans la suite de pouvoir manipuler une classe un peu plus générale de fonctions. Je parlerai des pistes d'implémentation en LS un peu plus loin, donc.

Notez qu'un item à dégâts fixes ne peut pas se représenter par un créneau. Si nous n'avez pas de chance de faire un coup critique, aucun souci : les dégâts sont fixes, on peut juste les traiter à part. Le cas des dégâts fixes mais avec chance de critique sera traité plus loin.

Convolution

Article «Produit de convolution» sur Wikipedia

Le problème qui se pose est alors le suivant : si j'enchaîne plusieurs items, comment puis-je calculer la fonction de densité associée à partir des densités de chacun des items ?

Introduction : cas discret

Revenons pour l'exemple au cas discret, en reprenant pour exemple la combo des deux tirs de Pistolet (sans force, agilité ni bouclier) utilisée précédemment.

Si je représente sur un graphique les probabilités d'apparition des différentes valeurs pour un tir, j'obtiens ceci :

!PistoletDiscret

(Attention : je suis temporairement revenu à une représentation des probabilités valeur par valeur, ceci n'est pas une fonction de densité.)

La probabilité d'obtenir 33 dégâts est alors donnée, comme on l'a vu précédemment, par la somme des probabilités d'obtenir les couples de valeurs (15 ; 18), (16 ; 17), (17 ; 16) et (18 ; 15).

On peut alors présenter le calcul sous la forme graphique suivante :

!ColovutionDiscrete

Le premier graphique indique la probabilité de chaque valeur du premier tir, en mettant en noir celles qui sont trop élevées pour que la somme fasse 33. Le second indique, lui, la probabilité des valeurs de (33 - résultat du second tir) : ainsi, si les tirages font que le premier tir fait 15, et que le second fait 18, les valeurs correspondantes sur mes deux graphes sont à la verticale l'une de l'autre (à l'abscisse 15).

On peut alors, pour faire le calcul, prendre la somme des produits de valeurs alignées :

Le premier graphe était construit directement, mais le second ? Il s'obtient géométriquement par les opérations suivantes : si on veut une somme S (ici 33), on fait le symétrique du premier graphe par rapport à l'axe des ordonnées, puis on décale le graphe obtenu de S unités vers la droite.

!SymétrieConvoDiscrète

!DécalageConvoDiscrète

Cas continu

Et dans le cas des densités de probabilités ? La même méthode va pouvoir répondre à notre problème. Simplement, il faut maintenant la décrire pour les densités et non pour des lois discrètes, mais le principe reste le même.

Si l'on prend deux variables aléatoires X et Y, de fonctions de densité f et g, et un nombre s, et que l'on cherche la probabilité que X+Y prenne pour valeur s, on procède ainsi :

Par exemple, avec deux fonctions de densités représentées ci-dessous, et s = 7 :

!ConvoContinue1

!ConvoContinue2

Bien entendu, le résultat va dépendre de la somme s voulue. On appelle alors produit de convolution de f et de g la fonction f * g qui à un nombre s associe le résultat du calcul précédent.

On peut en donner une formule : !FormuleConvolution mais c'est surtout la construction qui va nous servir en pratique.

On a pour l'instant seulement montré comment calculer la valeur de f * g en un point s. Si on veut se servir de f * g comme fonction de densité pour la somme des deux variables aléatoires considérées, il nous faut une expression de cette fonction valable pour tout s.

Selon l'aspect des fonctions considérées, cette étape peut être plus ou moins ardue. Ici, les fonctions que l'on va être amené à manipuler resteront assez simples, mais auront la particularité d'être définies par morceaux. Dans l'exemple précédent, on peut procéder ainsi :

La propriété cruciale ici (je l'ai déjà plus ou moins dit, mais maintenant c'est clair) :

> Soit X et Y deux variables aléatoires réelles indépendantes, décrites respectivement par des densités f et g. Alors la somme S = X + Y est une variable aléatoire à densité, de densité f * g. (On peut étendre ceci à des lois mixtes quitte à utiliser des distributions, cf plus loin, mais c'est surtout les densités qui nous intéressent ici.)

Le produit de convolution possède quelques propriétés qui peuvent s'avérer utiles.

> Il est commutatif : f * g = g * f.

Vous pouvez donc faire la convolution dans l'ordre que vous préférez, peu importe.

> Il se comporte bien vis-à-vis de l'addition : f * (g+h) = (f * g) + (f * h).

On peut donc décomposer des fonctions en sommes de plusieurs morceaux simples, faire la convolution par chacun des morceaux et faire la somme.

> Il se comporte bien vis-à-vis des produits par des constantes : f * (a x g) = a x (f * g).

On peut donc «sortir» les constantes multiplicatives du produit.

> Il est associatif : (f * g) * h = f * (g * h).

Grâce à l'associativité et à la commutativité, on peut faire une succession de produits de convolution un par un dans l'ordre que l'on veut (dans notre cas, cela revient à dire que les probabilités de dégâts d'une combo ne dépendent pas de l'ordre dans lequel on utilise les items, ce qui est vrai tant que l'on n'utilise pas de buffs au milieu bien entendu).

Calcul en pratique en LS

Cas des combos dans Leek Wars : simplifications dues au contexte

Commençons par une remarque cruciale ici (puisqu'elle permet de grandement simplifier les calculs) : nos items ont chacun pour densité de probabilité une fonction créneau, or la convolution de plusieurs telles fonctions est nécessairement une fonction définie par morceaux dont chaque morceau est polynomial.

Plus précisément, la convolution de k créneaux sera toujours composée de morceaux polynomiaux de degrés au plus k-1.

De plus, lorsque l'on ajoute progressivement des items à notre combos, on réalise des produits de convolution avec des créneaux, ce qui a le bon goût de se faire assez simplement : dans la construction du produit présentée précédemment, on peut «déplacer» le créneau en fonction de la somme s voulue, ce qui fait que les intégrales à calculer ne seront jamais que des intégrales de la densité déjà calculée entre deux bornes dépendant de s, multipliées par la hauteur du créneau :

!Convo3Spark

Exemple ici avec g fonction de densité obtenue pour deux Étincelles sans force et le créneau correspondant à une troisième utilisation de la même puce.

On aura donc besoin, pour le cas de Leek Wars :

Calcul formel : polynomes

Je vais présenter ici des grands principes, pas proposer une implémentation toute prête. Vous pourrez adapter ceci de la façon que vous souhaitez (créer une classe Polynome si vous voulez faire de la POO, manipuler directement les tableaux sinon, ou toute autre façon de faire qui vous semblerait pertinente).

Pour représenter une fonction polynomiale f(x) = a_n * x**n + ... + a_1 * x + a_0, il suffit de stocker ses coefficients. On peut donc représenter f par le tableau [a_0, a_1, ..., a_n].

À partir de là, il n'est pas très difficile de réaliser les opérations mathématiques utiles :

f + g sera représenté par un tableau de la forme [a_0 + b_0, ..., a_p + b_p, a_(p+1), ..., a_n] (j'ai pris ici `p

Les fonctions que l'on obtient lors du calcul des produits de convolution sont définies par morceaux : il va donc falloir représenter de telles fonctions en LS. On peut pour cela stocker une liste des morceaux (qui sont des polynômes dans notre cas) avec les valeurs minimales et maximales des domaines de validité. Il y a à nouveau plusieurs façon de faire cela (POO, tableau directement, ...), je vais juste présenter les opérations qu'il faudra être en mesure d'effectuer :

Enfin, et c'est là la difficulté, il faut pouvoir calculer le produit de convolution d'une telle fonction par un créneau.

Convolution

Si vous avez codé ce qui précède, une bonne part du boulot est fait. La difficulté pour calculer la convolution d'une fonction polynomiale par morceaux par un créneau va reposer principalement sur la détermination des points de recollements de la fonction résultante.

Donnons un exemple de calcul (du moins le début...) dans un cas encore simple : on a la densité de probabilité g pour deux utilisations d'Étincelle et on ajoute un tir de Pistolet (sans force), dont la densité est un créneau f. Calculons, étape par étape, la nouvelle densité g * f (ou f * g, c'est pareil) associée à la combo 2 Étincelles + 1 Pistolet :

Les coups critiques ne posent pas vraiment de problème. En effet, la densité de probabilités associée à un item pouvant faire un coup critique est composée de deux créneaux.

Plus précisément : considérons un item qui a une probabilité p de faire un coup critique. Soit f la fonction créneau associée à cet item sans chances de critique, avec un minimum a et un maximumb. Alors la densité de probabilité avec critique est donnée par (1-p)f + pg, où g est le créneau ayant pour minimum CRITICAL_FACTOR * a et pour maximum CRITICAL_FACTOR * b.

Or la convolution avec une fonction de densité h s'écrit alors : !critFormula ce qui permet de s'en sortir en faisant deux convolutions de h par des créneaux, puis une somme de deux fonctions définies par morceaux.

Gestion de l'armure absolue et des items à dégâts fixes : loi mixte

Jusqu'ici, je n'ai pas parlé de ce qui se passe si l'adversaire a de l'armure. L'armure relative ne pose aucun problème, elle crée juste un multiplicateur sur les dégâts, tout comme la force, et se traite de la même façon (les créneaux seront plus proches de 0 et de plus faibles amplitudes, c'est tout). L'armure absolue pose, elle, un réel problème.

En effet, elle va nous obliger à considérer des probas où un nombre exact a une probabilité non-nulle d'apparaître. Pour ceux qui ne sont pas habitués : oui, c'est un peu étrange à première vue, mais avec les densités de probabilités, un nombre précis a toujours une probabilité... nulle. J'ai dit en introduisant l'outil qu'on utilisait, pour obtenir la proba que la combo fasse entre a et b dégâts, l'intégrale de a à b de la densité. Et dans le cas qui nous intéresse, on pouvait prendre comme probabilité que la combo fasse s dégâts après arrondi l'intégrale entre s - 0.5 et s + 0.5. Mais avant l'arrondi, la probabilité de tomber sur une somme précise est l'intégrale... entre s et s, ce qui fait toujours 0.

Pour prendre une image, si je vous donne une planche, une scie et un mètre en vous demandant de couper une longueur de 50 cm, vous allez obtenir une planche qui fera (si vous n'êtes pas trop mauvais) environ 50 cm. Mais si on prend un instrument de mesure plus précis, votre planche a-t-elle une chance de faire précisément 50 cm ? Au millimètre près ? Au micron près ? À moins d'être tombé sur un virtuose de la scie, si je mesure assez finement, je trouverai toujours un petit écart. La même idée s'applique ici : je peux avoir une probabilité non-nulle de tomber, à l'arrondi près, sur une valeur, mais sans l'arrondi, aucune chance.

Armure absolue : atome en 0

Et pourtant, l'armure absolue va avoir le côté désagréable de donner à une valeur précise, 0, une probabilité d'apparition non nulle : si j'utilise une étincelle (sans force) sur un adversaire muni d'un casque (sans résistance), j'aurai de grandes chances de faire 0 dégâts. Pour faire des dégâts (non-nuls), il faudra en effet que le tirage aléatoire du jeu me donne des dégâts entre 15.5 et 16, qui seront arrondis à 16, et en prenant l'armure en compte seront ramenés à 16 - 15 = 1. Pour tous les autres tirages, les dégâts seront de 0.

Nous allons donc devoir nous occuper de ces probabilités non-nulles de faire 0 dégâts, et pour cela, nous n'avons pas de solution avec seulement des densités de probabilités : il n'existe pas de fonction de densité dont l'intégrale entre 0 et 0 donne un nombre non-nul.

> Note aux matheux et aux physiciens : oui, je vais parler de distribution de Dirac, mais ce n'est pas une fonction.

Lois mixtes (partie discrète + partie décrite par une «densité»)

Il va falloir gérer, donc, des lois de probabilités données par une fonction de densité plus des probabilités associées à certaines valeurs (zéro notamment à cause de l'armure, mais on verra que les armes à dégâts fixes causent le même genre de phénomène).

> On dit qu'une loi de probabilités a un atome en un point a si la probabilité de a est non-nulle.

De façon générale, on peut décomposer (je passe sur les quelques hypothèses à vérifier... ici, pas de souci) une loi de probabilités en plusieurs parties : une partie discrète, une partie décrite par une densité, et une partie bizarre qui ne nous concerne pas ici. Si vous êtes motivés... cf le Théorème de Radon-Nikodym (on arrive dans des maths un peu compliquées, mais la compréhension de ce théorème est tout à fait superflue pour la suite, je le signale juste au passage).

Je risque dorénavant de dire «densité» pour une fonction qui n'est pas d'intégrale 1. C'est un abus de langage ! Mais l'idée reste la même : représenter la partie (absolument) continue d'une loi par une fonction.

Bon, sans rentrer dans les détails compliqués... Ici, il va falloir garder, en plus d'une densité qui décrit les probas hors des atomes, les atomes et les probabilités qui y sont associées. Et propager l'information lorsqu'on ajoute un élément à la combo.

Par exemple, prenons le cas de deux étincelles avec 400 de force, contre un adversaire ayant 60 de bouclier absolu (et 0 de relatif). Une étincelle ferait sans bouclier entre 40 et 80 dégâts, représentés par le créneau !1Spark400Strength

Cependant, avec les 60 de bouclier absolu, les dégâts sont diminués de 60, le créneau est donc décalé de 60 vers la gauche. Or on ne peut pas faire de dégâts négatifs : la moitié gauche du créneau se retrouve donc «écrasée» sur la valeur 0. On obtient donc une probabilité qui est représentée par deux choses :

!1Spark400Strength60AS

Ajoutons la seconde étincelle. On va devoir distinguer plusieurs cas :

On garde alors comme information :

!2Spark400Strength60AS

On pourra noter que la fonction obtenue n'est pas continue. Contrairement au cas sans atomes où la régularité de la fonction grandissait au fur et à mesure de l'ajout d'items, ce n'est plus une obligation !

Distribution de Dirac en 0

Mathématiquement, on peut représenter cet objet grâce à un outil étrange : la *distribution de Dirac* en 0, notée δ, qui correspond à un objet (ça ne peut pas être une fonction...) qui vaut 0 partout sauf en 0, et qui a pour intégrale 1. Je ne vais pas formaliser ça ici, mais cette «distribution» permettrait de donner un formalisme plus abouti à cette notion de probabilité de faire 0 : on peut dire que la probabilité est représentée par 0.25δ + g (où g est la fonction tracée ci-dessus).

Cette distribution de Dirac a le bon goût d'avoir une propriété fort utile pour les produits de convolution : pour toute fonction h, on a toujours δ * h = h * δ = h.

Les quatre cas précédents peuvent alors se résumer en une seule formule : !ConvoDiracs On retrouve bien la probabilité 0.25 de faire 0, et on obtient une formule simple pour calculer la fonction associée au reste des cas.

Notez que lorsque vous calculez la probabilité des égâts liée à une combo, la probabilité de faire 0 dégâts disparaît dès que vous ajoutez un item ne pouvant pas faire 0 (logique, non ?). Dès lors, vous n'avez de terme en δ qu'avant d'ajouter un tel item, vous n'avez après qu'une vraie densité (d'intégrale 1).

Items à dégâts fixes et coups critiques : atomes ailleurs

Un autre cas peut faire apparaître des probabilités non-nulles pour une valeur précise : les items à dégâts fixes (Katana, Lance-grenades illicite, Frappe du démon et Châtiment à l'heure où je rédige cet article).

Sans chances de coup critique, on pourrait avoir une approche assez simple : calculer les dégâts fixes de la combo étudiée et décaler la fonction de densité obtenue avec les autres items d'autant. La probabilité de coup critique rend cependant inopérante cette approche, puisque les dégâts «fixes» ne le sont plus vraiment (deux valeurs possibles)... On se retrouve alors avec deux atomes.

Coups critiques et atomes

Une façon de faire va alors d'être, à chaque item à dégâts fixes ajouté, de distinguer deux cas :

et on fait la somme des deux lois de probabilités ainsi obtenues pondérées par la probabilité de coup critique.

Il faut donc gérer la somme de deux lois pouvant avoir des atomes : la loi résultante aura des atomes en tous les points où l'une ou l'autre des lois avait un atome.

Exemple pour tâcher d'y voir plus clair : combo Étincelle + Katana, avec 400 de force, 400 d'agilité (donc proba 0.4 de coup critique), et 50 de bouclier absolu sur le poireau visé.

!SparkCritAS

!SparkKatanaCritAs

Il y a donc, dans la loi de probabilité associée à cette combo, deux atomes. Si on ajoute un troisième item, il faudra donc faire trois cas :

Distribution de Dirac en un point quelconque

À nouveau, on peut formaliser ça mathématiquement par des distributions de Dirac bien placées : un atome situé en un point a avec une probabilité p_a se représente par un pic de Dirac en a, pondéré par la proba p_a, noté p_a δ_a.

Le calcul précédent peut alors se présenter ainsi :

On obtient donc, pour loi de la combo : !SparkKatanaCritASCalc

Or la convolution par un pic de Dirac situé en un point a revient à effectuer un décalage vers la droite de a. On retrouve donc bien la loi de probabilité calculée avant.

Calcul en LS

Le plus dur est déjà fait, normalement, si vous avez codé le produit de convolution. Il va juste falloir ajouter une surcouche ici : une loi de probabilité n'est plus représentée uniquement par une fonction polynomiale par morceaux, mais par un ensemble d'atomes avec la probabilité associée en plus d'une telle fonction.

Tout ce qu'il faudra coder, c'est donc un moyen de garder une trace de ces atomes, ainsi qu'une fonction de convolution qui en tienne compte en séparant plusieurs cas (atome * atome, atome * densité, densité * atome, densité * densité), puis qui fasse la somme des lois obtenues.

Vous devriez donc vous en sortir avec les outils que vous avez déjà coder : translation d'une fonction par un vecteur donné, convolution de deux densités, somme de fonctions polynomiales définies par morceaux.

Fonction de répartition

On a donc un moyen de calculer la loi de probabilité d'une variable aléatoire (qui représente les dégâts faits) sous la forme d'un ensemble d'atomes et d'une fonction de «densité» (pas tout à fait, son intégrale est 1 - probabilités des atomes, il serait plus exact de dire que c'est une combinaison linéaire d'une loi à densité et d'une loi discrète... passons).

À partir de là, on peut extraire plusieurs informations. On a dit qu'avec une densité, la probabilité de faire des dégâts entre a et b était donnée par l'intégrale de la densité entre a et b. Avec des atomes, ici, on fera plutôt la somme de la fonction de l'intégrale de la «densité» entre a et b et des probabilités des atomes situés entre a et b.

Plutôt que de calculer des intégrales à répétition, il peut être utile de calculer ce qu'on appelle la fonction de répartition de la loi

Définition et calcul

> La fonction de répartition de la loi de probabilités sur R d'une variable aléatoire X est la fonction qui à un nombre x associe la probabilité que la variable X prenne une valeur plus petite que x, ou égale à x. Autrement dit : !DéfinitionFonctionRépartition

Si une loi de probabilités est donnée par une densité D, la fonction de répartition est alors simplement la primitive de D dont la limite en -infini est 0. > Pour les matheux chipoteurs : bon... ok, pas une primitive au sens strict. Si la densité est un créneau, la fonction de répartition n'est pas dérivable sur tout R donc ce n'est pas une primitive...

Dans le cas d'une loi de probabilités avec une «densité» et des atomes, il faudra procéder par étapes :

Par exemple, avec la combo Étincelle + Katana de l'exemple précédent, on avait une fonction D : !SparkKatanaCritAs et deux atomes, un en 335 avec probabilité 0.09 et l'autre en 450.5 avec probabilité 0.06. La fonction de répartition se construit donc en prenant :

!SparkKatanaRepart1

!SparkKatanaRepart2

Utilisation

À partir de la fonction de répartition, il est assez simple de calculer des probabilités qui peuvent être pertinentes. Si F est la fonction de répartition d'une loi de probabilités, alors : !ProbasFRepart

Calculer cette fonction de façon formelle évite donc de calculer des intégrales dès que l'on a besoin d'une probabilité.

Remarques

Il est inutilement compliqué de calculer l'espérance des dégâts faits à partir de la loi obtenue : l'espérance des dégâts de la combo entière est juste la somme des espérances des items pris un à un.

De même, les jets successifs lors de l'utilisation d'items étant indépendants, l'écart-type se calcule directement à partir des écarts-type s1, s2, ... des différents items par la formule s = sqrt(s12 + s22 + ...)

L'intérêt d'avoir la loi ne réside donc pas dans ces calculs d'indicateurs.

___ ___ NB : les illustrations ont été réalisées grâce au logiciel Geogebra. ___ Références :

Philippe Barbe et Michel Ledoux, Probabilité, EDP Sciences (2007)

Pour ceux qui auraient déjà un bon niveau en maths, une référence classique pour la théorie de la mesure (attention, c'est un peu rude, hein) : Walter Rudin, Analyse réelle et complexe, édité chez Masson (1975, 1977) ou Dunod (1998) ou en anglais : Walter Rudin, *Real and complex analysis*, McGraw-Hill (1987)