Consignes

Vous devrez utiliser l'interface TPLab pour envoyer vos TP aux encadrants de TP.

La note ne valide pas seulement le résultat de votre programme, mais également son style :

Vérifiez ces points avant de demander à votre intervenant de TP pour valider votre code.

Liens utiles

Objectifs du TP

Travailler avec :

1. Préliminaires (20 minutes)

Pour ouvrir un fichier texte en écriture, il suffit de faire

f = open(nom_fichier, mode="w")

On peut ensuite écrire des chaînes de caractères dans le fichier, en faisant attention à bien mettre le caractère « saut de ligne » ("\n") lorsque c'est nécessaire :

f.write("Ceci est")
f.write(" une seule ligne")
f.write(" dans le fichier.\n")
f.write("Et ceci est la deuxième ligne...\n")

Écrivez une procédure sauvegarde_nom_score qui sauvegarde le nom et le score de quelqu'un dans un fichier :

def sauvegarde_nom_score(nom_fichier, nom, score):
    """sauvegarde un nom et un score dans un fichier :

    Paramètres :
      - nom_fichier, de type chaîne de caractères : nom du fichier où sauvegarder le score
      - nom, de type chaîne de caractères : nom du joueur
      - score, de type flottant : score du joueur"""

Écrivez une fonction lire_score qui récupère le score dans un fichier :

def lire_score(nom_fichier):
    """lit et renvoie le score (deuxième ligne) dans un fichier

    paramètre : nom_fichier, de type chaîne de caractères : nom du fichier à ouvrir

    valeur de retour : flottant"""

Pour ceci, il faudra ouvrir le fichier en lecture:

f = open(nom_fichier, mode="r")

et utiliser la méthode f.readline() qui renvoie les lignes successives du fichier. (Attention, deux appels successifs à f.write() donnent deux résultats différents : le premier renvoie la première ligne et le second renvoie la deuxième ligne du fichier.)

La méthode f.readline() renvoie une chaine de caractères, qu'il faudra convertir en nombre. Vous devrez donc utiliser la fonction int(...) ou float(...) pour transformer une chaine en nombre entier ou flottant.

2. Quizz (1 heure 45 minutes)

Dans ce TP, nous allons écrire un petit programme de QCM. Le logiciel pose des questions à l'utilisateur, qui choisit une réponse parmi celles proposées.

2.1. Question à 2 choix

Dans un premier temps, chaque question est représentée par un dictionnaire q contenant trois cases :

Par exemple :

q_test1 = {'question': "Quelle est la couleur des bananes ?",
           'correcte': "jaune",
           'incorrecte': "bleue"}

Si q est un tel dictionnaire, on peut accéder aux différentes cases avec la notation

Avec l'exemple précédent, on aura par exemple :

>>> print(q_test1['question'])
Quelle est la couleur des bananes ?

Écrivez une procédure question(q) qui prend une question en argument, et qui :

Par exemple :

>>> question(q_test2)
Quelle est la couleur du cheval blanc d'Henry IV ?
1 -  blanc
2 -  gris
Entrez votre choix: 1
Bonne réponse !

2.2. Questionnaire

Un questionnaire est une liste de plusieurs questions, c'est à dire une liste de dictionnaires.

Voici un exemple de code python définissant un tel questionnaire :

qs_test = [{'question': "Quelle est la couleur du cheval blanc d'Henry IV ?",
            'correcte': "blanc",
            'incorrecte': "gris"},
           {'question': "2 + 2 = ?",
            'correcte': "4",
            'incorrecte': "42"},
           {'question': "Un brelan de rois gagne une couleur.",
            'correcte': "faux",
            'incorrecte': "vrai"}]

Vous pouvez maintenant poser toutes les questions d'un questionnaire grâce à la procédure suivante

def questionnaire(qs):
    """Pose toutes les questions du questionnaire "qs" passé en argument."""
    for i in range(len(qs)):
        print("Question", i+1, ":", end="  ")
        question(qs[i])
        print()
    print("Fin du questionnaire.")

Testez la procédure questionnaire ci-dessus.

2.3. Score final

Le score à un questionnaire est calculé de la manière suivante : on compte 1 point par bonne réponse et -1 point par mauvaise réponse. Ceci fait qu'un utilisateur qui répond au hasard aura, en moyenne, un score de 0.

  1. Transformez votre procédure "question" en une fonction qui renvoie un +1 ou -1.

  2. Transformez la procédure "questionnaire" en une fonction pour qu'elle calcule le score et le renvoie, comme une note sur 100 :

    >>> score = questionnaire(qs)
    Question 1 :  Quelle est la couleur du cheval blanc d'Henry IV ?
    1 -  gris
    2 -  blanc
    Entrez votre choix: 2
    Bonne réponse !
    
    Question 2 :  Combienfait 2 + 2 ?
    1 -  4
    2 -  42
    Entrez votre choix: 2
    Mauvaise réponse !
    
    Fin du questionnaire.
    >>> print("Votre score est de {}%.".format(score))
    Votre score est de 0%.
    

2.4. Questionnaire dans un fichier

Plutôt que d'écrire tout le questionnaire dans votre fichier Python, il peut être pratique de stocker le questionnaire dans un fichier. Ceci permet d'avoir plusieurs questionnaires : "culture_generale.qcm", "mathematiques.qcm", "cinema.qcm", ...

On peut utiliser des fichiers de la forme suivante :

Par exemple :

Quelle est la couleur du cheval blanc d'Henry IV ?
+ blanc
- gris

Combien fait 2 + 2 ?
- 42
+ 4

Un brelan de rois gagne une couleur
- vrai
+ faux

Rappel : on peut supprimer les deux premiers caractères d'une chaîne avec

s = s[2:]

Écrivez une fonction "lecture_quizz" qui prend un nom de fichier en argument et renvoie le questionnaire (liste de dictionnaires) correspondant.

Par exemple, le fichier ci-dessus donnera exactement le questionnaire qc donné précédemment.

Chaque question comporte exactement 4 lignes :

  • la question,
  • les deux réponses,
  • une ligne blanche.

Lorsque la ligne blanche devient vide, cela veut dire qu'on a atteint la fin du fichier.

Il est donc possible de récupérer les questions une par une, dans une boucle while : tant qu'on n'a pas trouvé la dernière ligne, on fait quatre readline pour récupérer la question, les deux réponses et la ligne blanche...

2.5. Un peu d'aléatoire

... sur les questions

Toujours poser les questions dans le même ordre n'est pas une très bonne idée. Pour mélanger les questions, vous pouvez utiliser la procédure "shuffle" de la bibliothèque "random". Cette procédure permet de mélanger une liste existante :

>>> from random import shuffle
>>> t = [1,2,3,4,5,6]
>>> shuffle(t)
>>> t
[5, 6, 1, 4, 3, 2]

Modifier la fonction "questionnaire" pour qu'elle affiche les questions dans le désordre.

... sur les réponses

Pour afficher les réponses possibles dans un ordre aléatoire (avec parfois la bonne réponse en premier et parfois la bonne réponse en second), on peut utiliser la fonction "randint(0,1)" du module "random". Elle permet de tirer un bit ("0" ou "1") aléatoirement.

>>> from random import randint
>>> for i in range(10):
>>> for i in range(10):
...     print(randint(0,1))
...
0
1
0
0
0
1
1
1
1
1

Modifiez-votre fonction "question" pour que l'ordre des réponses possibles soit aléatoire.

Vérifiez que le score reste correct...

2.6. Sauvegarde du meilleur score

Meilleur score

On peut utiliser un fichier texte "./score.txt" pour conserver le score et le nom du meilleur joueur. Lorsqu'un utilisateur obtient un nouveau meilleur score, on met ce fichier à jour.

Le plus simple est de mettre le nom du joueur sur la première ligne et le score sur la deuxième ligne. Par exemple :

Tartempion
75.0

En utilisant les fonctions de la partie "Préliminaires", écrivez une procédure "gestion_score(s)" qui prend un score en argument et fait les choses suivantes :

  1. récupère le meilleur score dans le fichier "./score.txt",
  2. si "s" est supérieur au meilleur score, demande le nom du joueur (avec la fonction input),
  3. écrit le nom du joueur et son score dans le fichier "score.txt".

2.7. Fonction principale

Incorporez vos fonctions dans une unique procédure principale "quizz(fichier)" qui :

3. Question à choix multiple (1 heure)

Nous allons maintenant gérer les QCM où le nombre de réponses proposées peut-être supérieur à deux.

Lorsque le nombre de réponses proposées est plus grand que 2, il faut gérer les mauvaises réponses différemment. On remplace le champ "incorrecte" du dictionnaire par une liste de mauvaises réponses. Par symétrie, le champ "correcte" contiendra lui aussi une liste de bonnes réponses. (La plupart du temps, il n'y aura qu'une seule bonne réponse...)

Voici un exemple de code python produisant un questionnaire modifié :

qcm = [{'question': "Quelle est la couleur du cheval blanc d'Henry IV ?",
        'correctes': ["blanc"],
        'incorrectes': ["gris","rouge à pois vert","transparent"]},
       {'question': "0 + 0 = ?",
        'correctes': ["0", "la tête à Toto"],
        'incorrectes': ["42", "c'est trop dur"]}]

Attention : le score est calculé de la manière suivante : s'il y a n bonnes réponses et m mauvaises réponses, le joueur

Ceci permet d'assurer qu'en moyenne un joueur répondant au hasard à 0pt.

Écrivez une fonction "question_qcm" similaire à la fonction "question" pour prendre les réponses multiples en compte.

Pour mélanger les réponses, le plus simple est de :

4. Questionnaire dans un fichier

Le format de fichier pour les QCM est le même que pour les quizz. La seule différence est qu'il peut y avoir plusieurs bonnes / mauvaises réponses. Par exemple :

Quelle est la couleur du cheval blanc d'Henry IV ?
+ blanc
- gris
- transparent
- rouge à pois verts


Combien fait 0 + 0 ?
+ 0
- c'est trop dur
- 42
+ la tête à Toto
- rouge à pois verts

4.1. Lecture du fichier

Écrivez une fonction "lecture_qcm()" qui prend un nom de fichier en argument et renvoie le questionnaire (liste de dictionnaires) correspondant.

Par exemple :

>>> lecture_questionnaire("questions.qcm")
[{'incorrectes': ['gris', 'transparent', 'rouge à pois verts'],
  'correctes': ['blanc'], 
  'question': "Quelle est la couleur du cheval blanc d'Henry IV ?"}, 
 {'incorrectes': ["c'est trop dur"', '42', 'rouge à pois verts'], 
  'correctes': ['0', 'la tête à Toto'], 
  'question': 'Combien fait 2 + 2 ?'}]

(Un fichier exemple questions.qcm est disponible ici.)

4.2. Fonction QCM à partir d'un fichier

Écrivez une variante de la procédure quizz() pour utiliser les fonctions précédentes.