Vous êtes ici:   accueil  / programmes  / Lanceur de dés virtuel


Lanceur de dés virtuel

Écrit le : Mercredi 15 Juin 2005
Dernière mise à jour : Samedi 14 Juin 2008

Contexte

Lorsque l'on participe à des jeux de rôle, on doit presque toujours se munir de dés au nombre de faces surprenant.

Bien que les lancers de dés fassent partie du plaisir de ces jeux, il arrive que, lors d'une partie, les joueurs n'aient pas les dés qu'il faut, ou n'en aient pas suffisamment. Pour résoudre ce problème, voici le lanceur de dé virtuel ! (applaudissements)

Extrêmement polyvalent, ce programme a été conçu pour être le plus simple possible : pour reproduire le lancer de deux dés à 12 faces, par exemple, il vous suffira de taper "2d12".

Il est également possible de joindre à votre demande un modificateur, tel que "2d12+10", ou "2d12-3"; La somme des lancers de dés sera ajustée en conséquence.

Enfin, il est possible de donner au programme plusieurs ordres en même temps, en les séparant par des espaces : l'ordre "1d10 2d6+3" lancera un dé à dix faces, puis fera la somme de deux dés à six faces, plus 3.

Si vous voulez jeter un simple dé à six faces, tapez "1D6", et pour simuler le jet d'une pièce, (pour jouer à pile ou face), tapez "1d2".

Détails

Le principal intérêt (ou la principale difficulté, selon comment on voit les choses), de ce programme, était d'arriver à faire comprendre au programme un "ordre" le plus proche possible du langage humain.

A cette occasion, j'ai pu me perfectionner dans l'art ancestral ^^; des expressions rationnelles, qui permettent d'analyser une chaîne de caractères dont on connaît la structure, mais pas le contenu exact. Il s'agit d'un outil très puissant, que j'aimerai vous présenter.

Un exemple valant mieux qu'un long discours, voici comment j'ai créé l'expression rationnelle utilisée dans ce programme :

Naissance d'une expression rationnelle

les expressions rationnelles doivent être encadrées par un caractère; je choisis le dièse '#':
$expresion = '##';


je sais qu'une demande faite par l'utilisateur doit commencer par un chiffre, ce qui est représenté par le symbole '\d':
$expresion = '#\d#';


Mais il peut également s'agir d'un nombre, c'est-à-dire d'une suite de chiffres ; je rajoute donc le symbole '+', qui signifie 'il y a au moins une occurrence du terme précédent'.
$expresion = '#\d+#';


Le premier nombre doit être suivi de la lettre 'd':
$expresion = '#\d+d#';


Afin de ne pas faire de distinction entre le 'd' miniscule et le 'D' majuscule, je rajoute une option: la lettre i. L'expression devient ainsi insensible à la casse, l'utilisateur final pourra taper indifféremment "1d2" et "1D2".
$expresion = '#\d+d#i';


Après la lettre, il y aura un autre chiffre ou nombre:
$expresion = '#\d+d\d+#i';


Il convient ici d'aborder la notion de "capture" des chaînes de caractères : en encadrant certaines parties de parenthèses, je demande à PHP de "séparer" en différentes parties ce qui est demandé par l'utilisateur : d'un coté le nombre de dés, de l'autre le nombre de faces...
$expresion = '#(\d+)d(\d+)#i';


Laissons de coté cette partie de l'expression pour le moment, et intéressons-nous à la partie qui définira le modificateur ("+" ou "-" ; suivi d'un nombre). Cette partie peut donc commencer par le symbole "+"...
(\+)
Notez que, ce symbole ayant une signification particulière dans une expression rationnelle (voir plus haut), il convient de rajouter le signe "\", signifiant "le caractère suivant est le caractère "+" lui même, pas une option".

Nous l'avons vu, le premier symbole de cette partie sera soit un "plus", soit un "moins". On représente cette situation à l'aide des crochets, qui définissent une "classe de caractères", et du symbole "|", qui veut dire "ou" :
([\+|-])


Le signe "plus" ou "moins" doit être suivi d'un nombre, nous ajoutons donc :
(([\+|-])(\d+))


Enfin, afin d'indiquer au programme que cette partie de l'expression est optionnelle, nous ajoutons encore un symbole "|" :
(([\+|-])(\d+)|)
L'expression se lit alors "je recherche soit le signe + ou - suivis d'un chiffre, soit rien du tout".

Nous pouvons maintenant lier les deux morceaux de l'expression :
$expresion = '#(\d+)d(\d+)(([\+|-])(\d+)|)#i';


Et, cerise sur le gâteau, ajouter les caractères "?:", qui indiquent au programme que ces parenthèses-là ne définissent pas une expression à capturer séparément (comme c'est le cas avec les "(\d+)"), mais simplement la définition de motifs alternatifs, ici : "soit le signe + ou - suivis d'un chiffre, soit rien du tout".

Nous obtenons enfin :
$expresion = '#(\d+)d(\d+)(?:([\+|-])(\d+)|)#i';
Trop facile. smiley: sourire

Le futur de ce programme

Dans un futur que j'espère proche, j'aimerai parvenir à lui faire comprendre des ordres plus complexes, tels que "2d3+1d6 +4d10 -1 - 1D7+1d2smiley: grand sourire

Code source

<?php

function faire($commande)
 {
    
srand((double) microtime() * 1000000);

    
$commande trim($commande);
    
$ordres explode(" ",$commande);

    echo 
"<pre>\n";
    foreach(
$ordres as $ordre)
        if (!empty(
$ordre)) afficher($ordre);
    echo 
"</pre>\n";
 }




function 
afficher($ordre)
 {
    
$pattern "#(\d+)d(\d+)(?:([\+|-])(\d+)|)#i";
    
$test preg_match($pattern,$ordre,$out);

    
/*************************************
        $out[0]:    "aDb+c"
        $out[1]:    "a"
        $out[2]:    "b"
        $out[3]:    signe: "+" ou "-"
        $out[4]:    "c"
    *************************************/

    
echo '<span style="text-decoration: underline;">'$ordre"</span>:\n";

    if ( empty(
$test) )
        echo 
"Je n'ai pas compris la demande :(\n\n";
    else
     {
        
$resultat 0;
        
$valeurs = Array();
        
        for (
$j=0;$j<$out[1];$j++)
            
$valeurs[] = rand(1,$out[2]);
        
$resultat array_sum($valeurs);

        if ((
$out[1]!=1) || ($out[4]!=""))
            foreach (
$valeurs as $val)
                echo 
"$val ";
         
        elseif (
$out[1] == 1)
            
$resultat += rand(1,$out[2]);
            
        if (!empty(
$out[4]))
         {
            if (
$out[3] == "+")
                
$resultat += $out[4];
            elseif (
$out[3] == "-")
                
$resultat -= $out[4];
            echo 
"("$out[3], $out[4], ")";
         }

        echo 
"\n<strong>$resultat</strong>\n\n";
     }

 }
?>
manu