Activité pratique
Duration2h30Présentation & objectifs
Lors de cette séance, vous écrirez et exécuterez vos premiers tests unitaires.
Le but de cette séance est de vous aider à maîtriser des notions importantes en informatique. Un assistant de programmation intelligent tel que GitHub Copilot, que vous avez peut-être déjà installé, pourra vous fournir une solution à ces exercices uniquement à partir d’un nom de fichier judicieusement choisi.
Pour des raisons de formation, nous vous conseillons de désactiver d’abord ces outils.
À la fin de l’activité pratique, nous vous suggérons de retravailler l’exercice avec ces outils activés. Suivre ces deux étapes améliorera vos compétences à la fois fondamentalement et pratiquement.
De plus, nous vous fournissons les solutions des exercices. Assurez-vous de ne les consulter qu’après avoir une solution aux exercices, à des fins de comparaison ! Même si vous êtes sûr que votre solution est correcte, veuillez les consulter, car elles fournissent parfois des éléments supplémentaires que vous auriez pu manquer.
Contenu de l’activité
1 — Argmax
La fonction argmax
retourne l’indice de la (première occurrence de la) valeur maximale apparaissant dans une liste de valeurs, si la liste est vide ou nulle (None
ou null
), elle retourne -1
.
Écrivons des tests unitaires pour cette fonction.
Voici un exemple de test pour la fonction (copiez-collez-le dans un fichier tests_argmax.py
), en supposant que argmax
se trouve dans un fichier argmax.py
:
# Needed imports
import unittest
from argmax import argmax
# Define a class for unit tests
class TestArgmax (unittest.TestCase):
# Here, we define a method with a simple test
# You will have to write new tests, possibly in new methods
def test_argmax_standardcase (self):
self.assertEqual(1, argmax([1, 5, 3, 4, 2, 0]))
# Run the tests
if __name__ == '__main__':
_ = unittest.main(argv=[""], verbosity=2, exit=False)
Vous allez coder la fonction argmax(lst)
et écrire d’autres tests pour vous assurer qu’elle fonctionne correctement.
Avant de coder, vous devez lister quelques exemples uniques que vous pourrez également utiliser pour vos tests.
Vous devez aussi documenter la fonction et, si nécessaire, commenter le code.
L’instruction unittest.main()
exécute les tests définis dans le fichier.
La bonne pratique est de séparer les fonctions et les tests.
N’oubliez donc pas d’importer le fichier (et les fonctions) dans le module contenant les tests.
2 — Année bissextile
Dans cet exercice, vous devrez écrire une fonction is_leap(year)
qui prend une année en paramètre sous forme d’entier positif, et retourne une valeur booléenne qui est vraie si l’année est bissextile et fausse sinon.
Toute année divisible exactement par quatre est une année bissextile, sauf les années divisibles exactement par 100, mais ces années séculaires sont bissextiles si elles sont divisibles exactement par 400 (Wikipedia).
Nous ajoutons une règle supplémentaire qui précise que si l’entier passé en paramètre est strictement négatif, alors la valeur retournée est False
.
2.1 — Écrire les tests
Commençons par écrire un placeholder pour la fonction, qui sert juste à ce que la fonction soit définie :
def is_leap (year: int) -> bool:
"""
The function returns True if the input is a leap year and False otherwise.
This function only works for positive integers.
In:
* year: The year to be checked.
Out:
* True if the year is a leap year, False otherwise.
"""
return False
Avant de coder le corps de la fonction, vous écrirez les tests. Suivant le principe d’un test par concept, vous créerez les six tests suivants :
- La valeur retournée est
False
pour une valeur négative (donnée en exemple). - Si la valeur d’entrée est impaire, la valeur retournée est
False
. - Si la valeur d’entrée est paire et non divisible par 4, alors le résultat attendu est
False
. - Si la valeur d’entrée est divisible par 4 et par 100, alors le résultat attendu est
False
. - Si la valeur d’entrée est divisible par 4 et non divisible par 100, alors le résultat attendu est
True
. - Si la valeur d’entrée est divisible par 400, alors le résultat attendu est
True
.
Voici un code de base pour commencer (en supposant que is_leap
est dans un fichier isleap.py
) :
# Needed imports
import unittest
from isleap import is_leap
class TestIsLeap (unittest.TestCase):
def test_negative_value (self):
self.assertFalse(is_leap(-1000))
# Run the tests
if __name__ == '__main__':
_ = unittest.main(argv=[""], verbosity=2, exit=False)
2.2 — Écrire la fonction
Vous pouvez maintenant coder la logique de la fonction conformément aux spécifications.
Vous devez commenter les lignes de manière significative pour rendre le code plus clair, en utilisant #
.
Assurez-vous que tous les tests passent !
3 — Mot de passe valide
Pour être considéré comme suffisamment sécurisé, un mot de passe doit respecter les règles suivantes :
- Doit contenir au moins 8 caractères.
- Doit contenir au moins une lettre majuscule.
- Doit contenir au moins une lettre minuscule.
- Doit contenir au moins un chiffre.
- Doit contenir au moins un caractère spécial (parmi
!@#$%^&*()
).
Écrivez la fonction is_strong_password(password)
qui prend en entrée une chaîne de caractères (a.k.a., séquence de caractères) et retourne un booléen indiquant si le mot de passe entré est fort.
Pour aider à concevoir la logique de la fonction, vous pouvez la décomposer en sous-fonctions, chacune étant testée indépendamment.
Un squelette de la fonction est fourni ci-dessous, divisé en sous-fonctions.
Vous devez aussi documenter et commenter votre code.
Enfin, vous devez vérifier que les règles exprimées dans le cahier des charges sont bien prises en compte en écrivant des tests unitaires. La classe de test n’est pas fournie, vous devrez donc l’écrire vous-même. Chaque sous-fonction doit être testée indépendamment avec une variété d’exemples. Une fois chaque sous-fonction testée, vous pouvez tester la fonction principale.
Cette dernière étape peut être réalisée en binôme : chaque personne écrit les tests pour l’autre. Ensuite, vous pouvez évaluer la justesse de votre fonction en lançant les tests. Possiblement, soit la fonction, soit les tests devront être modifiés pour garantir que la fonction fonctionne correctement.
Voici un fichier pour vous lancer :
4 — Vérificateur Takuzu
Takuzu est un jeu de logique où vous devez compléter une grille pré-remplie $n\times n$ en utilisant uniquement des 0 et des 1. Une grille est correctement complétée si elle respecte les trois règles :
- Chaque ligne et chaque colonne doit contenir un nombre égal de 0 et de 1.
- Pas plus de deux nombres similaires consécutifs sont autorisés.
- Chaque paire de lignes est différente, et chaque paire de colonnes est différente.
Un exemple de grille $4\times 4$ correctement complétée :
0 1 1 0
1 0 0 1
0 0 1 1
1 1 0 0
Vous êtes invité à coder un vérificateur de grille Takuzu. Un squelette de module servira de base à votre travail. Vous devez respecter la partition des fonctions et implémenter chacune d’elles. Bien sûr, vous devrez aussi créer et compléter une classe de test.
Voici un fichier pour vous lancer :
5 — Mastermind
Préparez-vous à coder le jeu Mastermind. Dans ce jeu, un codeur crée un code utilisant 4 chiffres de 1 à 6. Un décodeur doit faire jusqu’à dix essais pour casser le code. Pour chaque essai, le codeur donne des indices au décodeur. Les indices sont composés de 2 chiffres :
- Le premier chiffre indique le nombre de bons chiffres à la bonne position.
- Le second chiffre indique le nombre de bons chiffres à la mauvaise position.
Les occurrences multiples d’une valeur sont autorisées.
S’il y a des valeurs en double, elles ne peuvent pas toutes recevoir un indice à moins
qu’elles correspondent au même nombre de couleurs dupliquées dans le code caché.
Par exemple, si le code est [6, 5, 1, 4]
et la proposition est [1, 1, 2, 2]
, les indices sont (0, 1)
.
En fait, la valeur 1
apparaît deux fois dans la proposition, mais une seule fois dans le code.
Puisqu’elle n’est pas à la bonne place, elle compte pour une dans la mauvaise place.
De plus, la valeur 2
apparaît aussi deux fois dans la proposition, mais pas dans le code.
Elle n’apparaît pas dans les indices.
Pour avancer progressivement, nous allons décomposer la logique du jeu en fonctions et les coder au fur et à mesure. Nous utiliserons la description fournie pour documenter le code et écrire des tests.
Nous fournissons un projet composé de plusieurs classes (Mastermind
, Player
) partiellement implémentées.
Des commentaires sont fournis pour toutes les méthodes présentes, qu’elles soient implémentées ou non.
Des classes de tests sont également fournies pour vous aider à valider votre code.
Vous devrez coder les méthodes check_code(code)
, has_remaining_attempts()
, is_right_answer(hints)
et guess_pattern(code, guess)
.
Nous recommandons de traiter une fonction après l’autre, en écrivant les tests avant ou juste après avoir codé la fonction.
Comme la dernière fonction est la plus compliquée, vous pouvez, si vous le souhaitez, la décomposer en sous-fonctions, chacune testée indépendamment.
Pour commencer, vous devez télécharger le squelette de code fourni dans le dossier compresser mastermind.zip et le décompresser dans un dossier de votre choix.
Puis, depuis VS Code Fichier > Ouvrir Dossier...
sélectionnez le dossier décompressé.
Pour aller plus loin
6 — Algorithme de Knuth pour le Mastermind
L’algorithme de Knuth est une méthode efficace pour résoudre le jeu Mastermind en un nombre minimal de coups.
Il utilise une stratégie d’élimination pour réduire le nombre de possibilités à chaque coup.
L’algorithme commence par générer une liste de tous les codes possibles.
Ensuite, il fait une supposition initiale, généralement [1, 1, 2, 2]
.
Après chaque coup, il utilise les indices fournis pour éliminer les codes qui ne correspondent pas aux indices.
Il continue à faire des suppositions jusqu’à ce qu’il trouve le code secret ou qu’il ait épuisé le nombre de coups autorisés.
L’algorithme de Knuth est connu pour sa capacité à résoudre le jeu en un maximum de 5 coups, ce qui en fait une méthode très efficace pour jouer au Mastermind.
Vous pouvez implémenter cet algorithme en Python, en déclarant une classe KnuthPlayer
qui devra s’intégrer dans le jeu Mastermind.
Dans premier temps, si vous le souhaitez, vous pouvez ne pas implémenter l’algorithme minimax
, mais simplement éliminer les combinaisons ne correspondant pas aux indices.
Bien entendu, il est indispensable de tester chaque fonction que vous implémentez pour vous assurer de leur bon fonctionnement.
Liens utiles :
- The Computer As Master Mind : l’article original de Donald Knuth sur l’algorithme de Mastermind.
- Solving Mastermind With Python : un article de Medium qui explique comment implémenter l’algorithme de Knuth en Python.
- Beating Mastermind: Winning with the help of Donald Knuth by Adam Forsyth : une vidéo explicative sur l’algorithme de Knuth.
- Minimax: How Computers Play Games : une vidéo explicative sur l’algorithme Minimax.