Projet : Héritage et dés

Nous allons modifier notre classe dé pour pouvoir sereinement jouer à Donjons et dragons.

une implémentation de la classe

fichier dé.py :

import random

class Dé:
    MIN_VALEUR = 1
    MAX_VALEUR = 6

    def __init__(self, valeur=1):
        self.valeur = valeur

    def lancer(self):
        self.valeur = random.randrange(self.MIN_VALEUR, self.MAX_VALEUR + 1)

        return self

fichier test_dé.py :

fromimportdef test_init():
    assert isinstance((),)


def test_valeur():
    assert().valeur == 1
    assert(valeur=4).valeur == 4


def test_lancer():=().lancer()
    assert.MIN_VALEUR <=.valeur <=.MAX_VALEUR

Dés génériques

Si l'on veut pouvoir jouer à Donjons et Dragons il va nous falloir plus que des dés à 6 faces !

Nous allons uniquement implémenter ici les dés à 6 et à 20 faces.

Commençons par faire hériter nos dés :

Implémentez les classes D6 et D20 pour qu'elles respectent le modèle UML suivant :

héritage

On veut également que :

  • les positions possibles d'un objet dé de type D6 soient entre 1 et 6
  • les positions possibles d'un objet dé de type D20 soient entre 1 et 20

corrigé

import random

class DéGénérique:
    MIN_VALEUR = 1

    def __init__(self, max, valeur=1):
        self.MAX_VALEUR = max
        self.valeur = valeur

    def lancer(self):
        self.valeur = random.randrange(self.MIN_VALEUR, self.MAX_VALEUR + 1)


class D6(DéGénérique):
    def __init__(self, position=1):
        super().__init__(6, position)


class D20(DéGénérique):
    def __init__(self, position=1):
        super().__init__(20, position)

Vérifions que tout ceci fonctionne bien :

Créez un fichier main.py qui :

  1. crée un d6 et un d20
  2. affiche les valeurs des dés créés
  3. lance les deux dés
  4. réaffiche les valeurs des dés créés

corrigé

from dés import D6, D20

d6 = D6()
d20 = D20()

print(d6.valeur, d20.valeur)
d6.lancer()
d20.lancer()
print(d6.valeur, d20.valeur)

Dés qui comptent

Il n'y a rien de plus méfiant qu'un rôliste. Pour éviter toute contestation nous allons stocker toutes les valeurs prisent par les dés pour pouvoir vérifier qu'ils sont non pipés.

User Story

Commençons par créer une user story sur la fonctionnalité que l'on veut ajouter :

User Story

  • Nom : "Statistiques descriptives"
  • Utilisateur : un joueur
  • Story : On veut compter les moyennes de jets de dés
  • Actions :
    1. effectuer 1000 jets d'un d6 et d'un d20
    2. calculer la moyenne de ces jets

Codez la user story en utilisant uniquement la classe dans le fichier story_moyenne.py.

corrigé

Fichier story_moyenne.py :

from dés import D6, D20


d6 = D6()
d20 = D20()

for _ in range(1000):
    d6.lancer()
    d20.lancer()

print('1000 lancers :', d6.moyenne(), d20.moyenne())

classe Stat

Nous voulons créer une version particulière d'un dé : un dé permettant de conserver les statistiques de ses lancers.

Pour cela on va utiliser la modélisation UML suivante :

stat

Codez la classe Stat :

  • la méthode Stat.sauve() ajoute la valeur de son attribut valeur à la fin de la liste de son attribut historique.
  • la méthode moyenne renvoie la moyenne de toutes les valeurs de de son attribut historique.

corrigé

Fichier dé.py :

class Stat:
    def __init__(self):
        self.valeur = 1
        self.historique = []

    def sauve(self):
        self.historique.append(self.valeur)

    def moyenne(self):
        return sum(self.historique) / max(1, len(self.historique))

Que faut-il modifier d'autres pour que la user story fonctionne ?

corrigé

Il faut modifier deux choses dans la classe DéGénérique :

  • appeler le constructeur de la classe mère dans le constructeur de DéGénérique
  • appeler la méthode sauve à la fin de la méthode lancer.

Fichier dé.py :

class DéGénérique(Stat):
    MIN_VALEUR = 1

    def __init__(self, max, valeur=1):
        super().__init__()

        self.MAX_VALEUR = max
        self.valeur = valeur

    def lancer(self):
        self.valeur = random.randrange(self.MIN_VALEUR, self.MAX_VALEUR + 1)
        self.sauve()