**** TP 3 **** Dice ==== Tout comme pour le TP_2, créez les deux fichiers dont le code est donné ci après et vérifiez que tous les tests passent en exécutant le fichier :file:`test_dice.py` avec la bibliothèque :code:`py.test`. A faire : * la méthode de classe `number_faces` n'est pas testée. Créez un tet pour cette méthode (par exemple, créez un dé à 20 faces avec la méthode et testez que son nombre de faces est correct) * modifiez la méthode `test_roll` pour que le dé créé soit à une face et simplifiez le test. dice.py ^^^^^^^^ .. code-block:: python import random class Dice: @classmethod def number_faces(cls, number_faces): dice = cls() dice.NUMBER_FACES = number_faces return dice def __init__(self, value=1): self.NUMBER_FACES = 6 self._value = value def get_value(self): return self._value def set_value(self, new_value): self._value = new_value def roll(self): self.set_value(random.randint(1, max(self.NUMBER_FACES, 1))) test_dice.py ^^^^^^^^^^^^ .. code-block:: python from dice import Dice def test_dice_creation_no_argument(): un_de = Dice() assert un_de.get_value() == 1 def test_dice_creation_initial_creation(): un_de = Dice(value=3) assert un_de.get_value() == 3 def test_dice_change_position(): un_de = Dice() un_de.set_value(6) assert un_de.get_value() == 6 def test_roll(): un_de = Dice() un_de.roll() assert 1 <= un_de.get_value() <= un_de.NUMBER_FACES UI == Le code suivant crée un Dé. Il est lancé et le résultat affiché lorsque l'on clique sur le bouton *roll*. .. note:: Si ce code ne fonctionne pas reportez vous au TP2 où vous avez déjà réglé ce problème. .. code-block:: python from appJar import gui from dice import Dice dice = Dice() DICE_LABEL = "dice value" def on_click(button): dice.roll() app.setLabel(DICE_LABEL, dice.get_value()) app = gui() app.setGeometry(400, 200) app.addLabel(DICE_LABEL, dice.get_value(), 0, 0) app.addButton("roll", on_click, 0, 1) app.go() Ajoutez une ligne de texte contenant l'heure et la valeur du nouveau dé à chaque fois que l'on clique. Pour cela, vous pourrez utiliser : * les ``_ pour ajouter les lignes de messages (attention. Les list box ont une hauteur par défaut. En choisissant 200 comme hauteur de la fenêtre, vous devriez pouvoir voir et la 1ère ligne (la valeur du dé et le bouton roll) et la 2nde (la *listbox*)). * Pour le temps, on pourra utiliser les objets datetime (voir ``_) Undo ==== DiceMemento ^^^^^^^^^^^ Créez la classe `DiceMemento` dans le fichier :file:`dice_memento.py` et ses tests dans le fichiers :file:`test_dice_memento.py`. La classe DiceMemento doit avoir : * un `Dice` comme paramètre du constructeur. * une méthode `restore()` qui remet au dé sauvé la valeur qu'il avait à la création du memento. Vous pouvez par exemple transformer le code ci-après en test(s) : .. code-block:: python dice = Dice() dice.set_value(2) memento = DiceMemento(dice) dice.set_value(6) memento.restore() print(dice.get_value()) # doit valoir 2 undo list ^^^^^^^^^ Nous allons (enfin, plutôt : vous allez) créer une classe `Undo` (dans le fichier :file:`undo.py`) qui va nous permettre de sauver des dés (et leurs valeurs) et de les restaurer à la demande. Cette classe doit pouvoir : * sauver un dé avec la méthode : `save(dice)` (un `DiceMemento` sera créé dans la méthode save puis sauvegardé) * restaurer la dernière valeur sauvée avec la méthode `restore()` * connaitre le nombre d'item sauvegardé avec la commande `len` (il faut donc implémenter une méthode `__len__`) Bien sur vous créerez un fichier de test :file:`test_undo.py` qui testera les 3 fonctionnalités ci-dessus. UI : Undo ========= Ajoutez à l'UI un bouton undo. A chaque fois que l'on clique sur le bouton *roll*, la position du dé doit être sauvée. Cette position doit être restaurée lorsque l'on clique sur le bouton *undo*. De plus, on doit ajouter un message à la listbox qui prévient que la valeur du dé à été undoué.