Aller au contenu

0 : Issues de base

Les issues de ce groupe vont nous permettre de consituer une base raisonnablement jouable pour le programme.

0.1 : une question

Le programme pose une question à l'utilisateur, et propose 4 choix de réponse possibles. L'utilisateur réponds. Si c'est la bonne réponse, le programme affiche "Gagné"

Implémentons le programme décris dans l'issue. On va faire au plus simple.

Voici deux exemples de traces d'exécution :

En quelle année a eu lieu la prise de la Bastille ? (1988, 1789, 1987, 1452) : 1789
Gagné !
En quelle année a eu lieu la prise de la Bastille ? (1988, 1789, 1987, 1452) : 1452
Perdu !
En quelle année a eu lieu la prise de la Bastille ? (1988, 1789, 1987, 1452) : la réponse D
Perdu !
Aide

Utilisez la fonction input et une variable pour la réponse.

Ne testez que la bonne réponse avec un if, qui affichera Gagné !, et affichez Perdu ! dans son else.

Aussi, pas besoin de convertir la date en entier, vous pouvez directement tester des chaînes de caractères !

Solution (programme complet)
1
2
3
4
5
reponse = input("En quelle année a eu lieu la prise de la Bastille ? (1988, 1789, 1987, 1452) : ")
if reponse == "1789":
    print("Gagné !")
else:
    print("Perdu !")

0.2 : 3 questions

Le programme pose 3 questions à l'utilisateur. A chaque réponse à une question, le programme affiche si l'utilisateur a eu juste ou faux, et quelle était la bonne réponse. Quand l'utilisateur a répondu à toutes les questions, le programme affiche le nombre de questions, et le nombre de bonnes réponses.

Voici un exemple de trace :

En quelle année a eu lieu la prise de la Bastille ? (1988, 1789, 1987, 1452) : 1789
Vrai !
La SNT est un cours dispensé en classe de ? (Première, Seconde, Terminale, 3eme) : Terminale
Faux : Seconde
Le terme cortinaire désigne en général un ? (végétal, animal, champignon, minéral) : champignon
Vrai !
Nombre de questions : 3
Bonnes réponses : 2
Aide

Procédez en deux temps :

Commencez par copier-coller et modifier la question créée à l'issue 0.1 pour ajouter deux questions.

Puis servez-vous d'une variable pour compter les bonnes réponses. Au debut du programme, la valeur de cette variable est 0, puis à chaque bonne réponse, ajoutez-lui 1.

Remarque : pour ajouter 1 à une variable a, au lieu de faire

a = a + 1

on peut faire

a += 1
Solution (programme complet)
bonnes_reponses = 0

reponse = input("En quelle année a eu lieu la prise de la Bastille ? (1988, 1789, 1987, 1452) : ")
if reponse == "1789":
    print("Vrai !")
    bonnes_reponses += 1
else:
    print("Faux : 1789")

reponse = input("La SNT est un cours dispensé en classe de ? (Première, Seconde, Terminale, 3eme) : ")
if reponse == "Seconde":
    print("Vrai !")
    bonnes_reponses += 1
else:
    print("Faux : Seconde")

reponse = input("Le terme cortinaire désigne en général un ? (végétal, animal, champignon, minéral) : ")
if reponse == "champignon":
    print("Vrai !")
    bonnes_reponses += 1
else:
    print("Faux : champignon")

print("Nombre de questions : 3")
print(f"Bonnes réponses : {bonnes_reponses}")

On peut clairement améliorer ce code, qui est très redondant : on a fait des copiers-collers. Notre code a cette forme :

une question
une question
une question

Où chaque une question corresponds a un bloc de code de la forme :

1
2
3
4
5
6
reponse = input("La question ? (les réponses):")
if reponse == "La bonne réponse":
    print("Vrai !")
    bonne_reponses += 1
else:
    print("Faux : Seconde")

C'est peu pratique, si on veut ajouter encore des questions, notre code va vite devenir très long, puisque chaque question demande 6 lignes de code !

De la même manière, si on veut changer notre manière de poser des questions, par exemple mettre les réponses possibles entre [] au lieu des (), on devra aller modifier chaque question une par une, et on veut éviter ça.

On définit donc une fonction poser_question :

def poser_question(question, r1, r2, r3, r4):
    """question une chaine de caractères, la question a poser
    r1, r2, r3, r4, les réponses possibles. r1 est la bonne réponse.

    pose la question à l'utilisateur. Retourne 1 si la réponse est la bonne, 0 sinon.
    """
    reponse = input(f"{question} ({r1}, {r2}, {r3}, {r4}) : ")
    if reponse == r1:
        print("Vrai !")
        return 1
    else:
        print(f"Faux : {r1}")
        return 0

On peut maintenant réécrire notre programme sous une forme bien plus concise à l'aide de cette fonction. Pensez bien à modifier l'ordre des choix dans les questions, le premier choix doit être la bonne réponse !

Code complet
def poser_question(question, r1, r2, r3, r4):
    """question une chaine de caractères, la question a poser
    r1, r2, r3, r4, les réponses possibles. r1 est la bonne réponse.

    pose la question à l'utilisateur. Retourne 1 si la réponse est la bonne, 0 sinon.
    """
    reponse = input(f"{question} ({r1}, {r2}, {r3}, {r4}) : ")
    if reponse == r1:
        print("Vrai !")
        return 1
    else:
        print(f"Faux : {r1}")
        return 0

bonnes_reponses = 0
bonnes_reponses += poser_question("En quelle année a eu lieu la prise de la Bastille ?", "1789", "1988",  "1987", "1452")
bonnes_reponses += poser_question("La SNT est un cours dispensé en classe de ?", "Seconde", "Première",  "Terminale", "3eme")
bonnes_reponses += poser_question("Le terme cortinaire désigne en général un ?", "champignon", "végétal", "animal",  "minéral")
print("Nombre de questions : 3")
print(f"Bonnes réponses : {bonnes_reponses}")

0.3 : Erreurs de saisie

Tant que la réponse de l'utilisateur n'est pas une des réponses proposées, le programme redemande à l'utilisateur de répondre.

Il est important de se prémunir des erreurs de saisie du joueur, parce qu'il est frustrant de perdre un point sur une erreur de frappe. Par exemple :

La SNT est un cours dispensé en classe de ? (Première, Seconde, Terminale, 3eme) : seconde
Faux : Seconde

Ici, la réponse est comptée fausse, alors qu'on voit bien que le joueur connaissait la bonne réponse.

Pour éviter ce genre d'erreur, il faut qu'on s'assure que la réponse donnée par l'utilisateur est bien une parmi celles proposées, comme suit :

La SNT est un cours dispensé en classe de ? (Première, Seconde, Terminale, 3eme) : seconde
Choisissez (Première, Seconde, Terminale, 3eme) : Seconde
Vrai !

On va créer un remplacement à la fonction input, qui s'appelera demander_choix. Dans poser_question, au lieu de faire :

reponse = input(f"{question} ({r1}, {r2}, {r3}, {r4}) : ")

on fera :

reponse = demander_choix(question, r1, r2, r3, r4)

Implementez la fonction demander_choix :

def demander_choix(question, ch1, ch2, ch3, ch4):
    """question une chaine de caractères, la question
    ch1, ch2, ch3, ch4 des chaines de caratères, les choix possibles.

    Redemande une saisie à l'utilisateur tant que sa réponse n'est pas un des choix
    retourne le choix valide choisi.
    """
    pass
Aide 1

Vous aurez besoin d'une boucle while.

On peut reformuler tant que sa réponse n'est pas un des choix en tant que la réponse est différente de ch1, et que la réponse est différente de ch2, et que la réponse est différente de ch3, et que la réponse est différente de ch4

Aide 2

La condition pour continuer la boucle est :

reponse != ch1 and reponse != ch2 and reponse != ch3 and reponse != ch4

Solution
def demander_choix(question, ch1, ch2, ch3, ch4):
    """question une chaine de caractères, la question
    ch1, ch2, ch3, ch4 des chaines de caratères, les choix possibles.

    Redemande une saisie à l'utilisateur tant que sa réponse n'est pas un des choix
    retourne le choix valide choisi.
    """
    reponse = input(f"{question} ({ch1}, {ch2}, {ch3}, {ch4}) : ")
    while reponse != ch1 and reponse != ch2 and reponse != ch3 and reponse != ch4:
        reponse = input(f"Choisissez ({ch1}, {ch2}, {ch3}, {ch4}) :")
    return reponse   

Modifiez votre code comme mentionné plus haut pour utiliser cette fonction.

Solution (Code complet)
def demander_choix(question, ch1, ch2, ch3, ch4):
    """question une chaine de caractères, la question
    ch1, ch2, ch3, ch4 des chaines de caratères, les choix possibles.

    Redemande une saisie à l'utilisateur tant que sa réponse n'est pas un des choix
    retourne le choix valide choisi.
    """
    reponse = input(f"{question} ({ch1}, {ch2}, {ch3}, {ch4}) : ")
    while reponse != ch1 and reponse != ch2 and reponse != ch3 and reponse != ch4:
        reponse = input(f"Choisissez ({ch1}, {ch2}, {ch3}, {ch4}) :")
    return reponse 


def poser_question(question, r1, r2, r3, r4):
    """question une chaine de caractères, la question a poser
    r1, r2, r3, r4, les réponses possibles. r1 est la bonne réponse.

    pose la question à l'utilisateur. Retourne 1 si la réponse est la bonne, 0 sinon.
    """
    reponse = demander_choix(question, r1, r2, r3, r4)
    if reponse == r1:
        print("Vrai !")
        return 1
    else:
        print(f"Faux : {r1}")
        return 0

bonnes_reponses = 0
bonnes_reponses += poser_question("En quelle année a eu lieu la prise de la Bastille ?", "1789", "1988",  "1987", "1452")
bonnes_reponses += poser_question("La SNT est un cours dispensé en classe de ?", "Seconde", "Première",  "Terminale", "3eme")
bonnes_reponses += poser_question("Le terme cortinaire désigne en général un ?", "champignon", "végétal", "animal",  "minéral")
print("Nombre de questions : 3")
print(f"Bonnes réponses : {bonnes_reponses}")

Parfait. Améliorons notre code maintenant. La fonction demander_choix liste les choix dans ses arguments, ce qui fait beaucoup d'arguments. De plus, comme les choix sont listés explicitement, la condition du while est relativement lourde.

On va à la place passer les choix sous forme d'un tuple. Je vous invite à aller lire le cours correspondant Type séquences : str, tuple, list.

On commence par modifier la spécification de la fonction demander_choix :

def demander_choix(question, choix):
    """question une chaine de caractères, la question
    choix un tuple de chaines, les choix possibles.

    Redemande une saisie à l'utilisateur tant que sa réponse n'est pas un des choix
    retourne le choix valide choisi.
    """

Modifiez le corps de la fonction pour qu'elle suive cette nouvelle spécification.

Aide 1

Vous pouvez directement afficher un tuple dans une f-string :

a = ("1988", "1789", "1987", "1452")
print(f"Voici un tuple dans une f-string : {a}")

affiche

Voici un tuple dans une f-string : ('1988', '1789', '1987', '1452')
Aide 2

Pour savoir si une valeur appartient à un tuple, vous pouvez utiliser l'opérateur in :

a = ("1988", "1789", "1987", "1452")
if "2002" in a:
    print("2002 est dans a")
else :
    print("2002 n'est pas dans a")

Pour savoir si une valeur n'est pas dans le tuple, vous utilisez les opérateurs in et not:

a = ("1988", "1789", "1987", "1452")
if not ("2002" in a) :
    print("2002 n'est pas dans a")
else :
    print("2002 est dans a")
Solution
def demander_choix(question, choix):
    """question une chaine de caractères, la question
    choix un tuple de chaines, les choix possibles.

    Redemande une saisie à l'utilisateur tant que sa réponse n'est pas un des choix
    retourne le choix valide choisi.
    """
    reponse = input(f"{question} {choix} : ")
    while not (reponse in choix):
        reponse = input(f"Choisissez {choix} :")
    return reponse   

Modifiez votre appel à demander_choix dans la fonction poser_question, pour l'adapter à cette nouvelle version.

Aide

Vous pouvez créer un tuple en spécifiant les valeurs entre parenthèses, séparées par une virgule :

t = (1,2,3,4)
Solution (Code complet)
def demander_choix(question, choix):
    """question une chaine de caractères, la question
    choix un tuple de chaines, les choix possibles.

    Redemande une saisie à l'utilisateur tant que sa réponse n'est pas un des choix
    retourne le choix valide choisi.
    """
    reponse = input(f"{question} {choix} : ")
    while not (reponse in choix):
        reponse = input(f"Choisissez {choix} :")
    return reponse


def poser_question(question, r1, r2, r3, r4):
    """question une chaine de caractères, la question a poser
    r1, r2, r3, r4, les réponses possibles. r1 est la bonne réponse.

    pose la question à l'utilisateur. Retourne 1 si la réponse est la bonne, 0 sinon.
    """
    reponse = demander_choix(question, (r1, r2, r3, r4))
    if reponse == r1:
        print("Vrai !")
        return 1
    else:
        print(f"Faux : {r1}")
        return 0

bonnes_reponses = 0
bonnes_reponses += poser_question("En quelle année a eu lieu la prise de la Bastille ?", "1789", "1988",  "1987", "1452")
bonnes_reponses += poser_question("La SNT est un cours dispensé en classe de ?", "Seconde", "Première",  "Terminale", "3eme")
bonnes_reponses += poser_question("Le terme cortinaire désigne en général un ?", "champignon", "végétal", "animal",  "minéral")
print("Nombre de questions : 3")
print(f"Bonnes réponses : {bonnes_reponses}")

0.4 : Réponses aléatoires

Le programme change aléatoirement l'ordre des réponses à chaque question.

On veut représenter les choix des questions comme un tuple, dans lequel le premier élément est la bonne réponse. Le problème, c'est qu'à l'heure actuelle, on présente les réponses dans l'ordre où elles sont stockées dans notre programme, et si le joueur peut s'en rendre compte, celà enlèverait beaucoup du fun du jeu.

On va donc mélanger les réponses au moment de les afficher.

Et ça tombe bien, le module random, qui permet de faire de l'aléatoire, nous permet de mélanger une list à l'aide de la fonction shuffle.

Essayons sur une exemple minimaliste :

from random import shuffle
a = [1, 2, 3, 4]
shuffle(a)
print(a)
shuffle(a)
print(a)

Peut afficher :

[2, 1, 4, 3]
[4, 3, 1, 2]

A chaque fois qu'on relance le programme, on a normalement une sortie différente.

Malheureusement, on ne peut pas mélanger les tuples à l'aide de shuffle, parce que les tuples sont immutables, c'est à dire qu'on ne peut pas modifier les valeurs qu'ils contiennent (voir chapitre Immutabilité et mutabilité pour plus de précisions).

On va donc se créer notre propre fonction melange, qui va nous permettre de mélanger un tuple. Essayez d'implanter la fonction suivante, en remplaçant chaque commentaire par une ligne de code.

from random import shuffle
def melange(tu):
    """tu un tuple à mélanger.
    Retourne une copie de tu mélangée aléatoirement.
    """
    # Creer une list l à partir de tu
    # mélanger l avec shuffle
    # Creer un tuple t à partir de l
    # retourner t
Aide

Pour transformer un tuple en list, utilisez la fonction list:

t = (1,2,3)
l = list(t)

Pour transformer une list en tuple, utilisez la fonction tuple:

l = [1,2,3]
t = tuple(l)
Solution
from random import shuffle
def melange(tu):
    """tu un tuple à mélanger.
    Retourne une copie de tu mélangée aléatoirement.
    """
    l = list(tu)
    shuffle(l)
    t = tuple(l)
    return t

Ajoutez le import et cette fonction à votre code, puis utilisez là dans demander_choix pour mélanger l'ordre des réponses. Attention, l'ordre doit rester le même si l'utilisateur fait une erreur de saisie et donne une réponse inexistante !

Aide

Au début de la fonction demander_choix, créez une variable choix_melanges à l'aide de la fonction melange.

Utilisez ensuite choix_melange à la place de choix.

Solution
def demander_choix(question, choix):
    """question une chaine de caractères, la question
    choix un tuple de chaines, les choix possibles.

    Redemande une saisie à l'utilisateur tant que sa réponse n'est pas un des choix
    retourne le choix valide choisi.
    """
    choix_melanges = melange(choix)
    reponse = input(f"{question} {choix_melanges} : ")
    while not (reponse in choix_melanges):
        reponse = input(f"Choisissez {choix_melanges} :")
    return reponse
Solution (Code complet)
from random import shuffle

def melange(tu):
    """tu un tuple à mélanger.
    Retourne une copie de tu mélangée aléatoirement.
    """
    l = list(tu)
    shuffle(l)
    t = tuple(l)
    return t

def demander_choix(question, choix):
    """question une chaine de caractères, la question
    choix un tuple de chaines, les choix possibles.

    Redemande une saisie à l'utilisateur tant que sa réponse n'est pas un des choix
    retourne le choix valide choisi.
    """
    choix_melanges = melange(choix)
    reponse = input(f"{question} {choix_melanges} : ")
    while not (reponse in choix_melanges):
        reponse = input(f"Choisissez {choix_melanges} :")
    return reponse


def poser_question(question, r1, r2, r3, r4):
    """question une chaine de caractères, la question a poser
    r1, r2, r3, r4, les réponses possibles. r1 est la bonne réponse.

    pose la question à l'utilisateur. Retourne 1 si la réponse est la bonne, 0 sinon.
    """
    reponse = demander_choix(question, (r1, r2, r3, r4))
    if reponse == r1:
        print("Vrai !")
        return 1
    else:
        print(f"Faux : {r1}")
        return 0

bonnes_reponses = 0
bonnes_reponses += poser_question("En quelle année a eu lieu la prise de la Bastille ?", "1789", "1988",  "1987", "1452")
bonnes_reponses += poser_question("La SNT est un cours dispensé en classe de ?", "Seconde", "Première",  "Terminale", "3eme")
bonnes_reponses += poser_question("Le terme cortinaire désigne en général un ?", "champignon", "végétal", "animal",  "minéral")
print("Nombre de questions : 3")
print(f"Bonnes réponses : {bonnes_reponses}")

C'est l'heure d'améliorer notre code ! On commence à avoir beaucoup de fonctions, il faut donc qu'on évite de laisser trainer des instructions dans le fichier. On va donc déplacer les instructions qui ne sont pas dans une fonctions dans une fonction main, et l'appeler dans un bloc if main.

On crée un fonction main, et on y déplace le code de notre programme :

def main():
    bonnes_reponses = 0
    bonnes_reponses += poser_question("En quelle année a eu lieu la prise de la Bastille ?", "1789", "1988",  "1987", "1452")
    bonnes_reponses += poser_question("La SNT est un cours dispensé en classe de ?", "Seconde", "Première",  "Terminale", "3eme")
    bonnes_reponses += poser_question("Le terme cortinaire désigne en général un ?", "champignon", "végétal", "animal",  "minéral")
    print("Nombre de questions : 3")
    print(f"Bonnes réponses : {bonnes_reponses}")

Ensuite, a la fin de notre fichier, on ajoute un bloc if main qui appelle cette fonction :

if __name__=="__main__":
    main()

De cette manière, il est plus simple d'identifier où notre programme commence à s'exécuter.

Code complet
--8<-- "questionnaire_cortinaire/versions/questionnaire_cortinaire_04_2.py" 

0.5 : Liste de questions

Le programme pose les questions définies dans une liste dans le code du programme.

Les questions sont des données du programme, et pour le moment elles sont incluses dans les instructions de ce dernier. Ce mélange a deux désavantages :

  • Si on a beaucoup de questions, alors les lignes utilisées pour les questions, mélangées aux autres instructions, vont rendre le programme plus lourd et plus difficile à lire.
  • Si on veut ajouter des questions, on doit comprendre comment le code marche, et en rajoutant des questions, on risque de "casser" le programme, puisqu'on va modifier des instructions et pas juste des données.

On va donc séparer les questions et les instructions qui décrivent le déroulement du jeu. Les questions seront stockées dans une list définie tout en haut du fichier.

Définissons une convention pour représenter les questions.

Une question est une paire entre un texte et un ensemble de réponses proposées. On utilise donc un tuple.

(question, ensemble_reponses)

L'ensemble des réponses d'une question est un quadruplet, le premier élément du quadruplet est la bonne réponse. On utilise donc un tuple.

(bonne_reponse, reponse2, reponse3, reponse4)

Une question est donc représentée par :

(question, (bonne_reponse, reponse2, reponse3, reponse4))

où tous les éléments sont des chaines de caractères.

  • Il y a énormément de questions, on va donc stocker les questions dans une list, même si comme on ne modifie pas les questions, un tuple aurait aussi pu faire l'affaire.

Pour nos trois questions précédentes, ça donne donc :

questions = [
    ("En quelle année a eu lieu la prise de la Bastille ?", ("1789", "1988",  "1987", "1452")),
    ("La SNT est un cours dispensé en classe de ?", ("Seconde", "Première",  "Terminale", "3eme")),
    ("Le terme cortinaire désigne en général un ?", ("champignon", "végétal", "animal",  "minéral"))
    ]

Pour accéder à une la bonne réponse d'une question, on fait :

question[1][0]

Ce n'est pas très explicite ! Pour nous simplifier la tâche, on doit créer des fonctions d'accès.

Implantez les fonctions suivantes :

def texte(question):
    """question une question,
    retourne le texte de la question

    texte(("a", ("b", "c", "d", "e")))
    retourne "a"
    """
    pass

def reponses(question):
    """question une question,
    retourne le tuple des réponses de la question

    reponses(("a", ("b", "c", "d", "e")))
    retourne ("b", "c", "d", "e")
    """
    pass

def bonne_reponse(question):
    """question une question
    retourne la bonne réponse de la question

    bonne_reponse(("a", ("b", "c", "d", "e")))
    retourne "b"
    """
    pass
Aide

Utilisez l'opérateur [i], où i est l'indice de l'élément, pour accéder à un élément d'une paire ou d'un quadruplet ! Attention, les indices sont comptés à partir de 0, l'indice du premier élément est donc 0, celui du second 1, ...

Vous pouvez utiliser la fonction réponse pour implémenter la fonction bonne_reponse.

Solution
def texte(question):
    """question une question,
    retourne le texte de la question

    texte(("a", ("b", "c", "d", "e")))
    retourne "a"
    """
    return question[0]

def reponses(question):
    """question une question,
    retourne le tuple des réponses de la question

    reponses(("a", ("b", "c", "d", "e")))
    retourne ("b", "c", "d", "e")
    """
    return question[1]

def bonne_reponse(question):
    """question une question
    retourne la bonne réponse de la question

    bonne_reponse(("a", ("b", "c", "d", "e")))
    retourne "b"
    """
    return reponses(question)[0]

Ajoutez ces fonctions au programme de questionnaire si ce n'est déjà fait. Ajoutez la list des questions comme définie plus haut dans la variable questions tout en haut du fichier, si ce n'est pas également déjà fait.

Solution (Code complet)
questions = [
    ("En quelle année a eu lieu la prise de la Bastille ?", ("1789", "1988",  "1987", "1452")),
    ("La SNT est un cours dispensé en classe de ?", ("Seconde", "Première",  "Terminale", "3eme")),
    ("Le terme cortinaire désigne en général un ?", ("champignon", "végétal", "animal",  "minéral"))
    ]

from random import shuffle

def texte(question):
    """question une question,
    retourne le texte de la question

    texte(("a", ("b", "c", "d", "e")))
    retourne "a"
    """
    return question[0]

def reponses(question):
    """question une question,
    retourne le tuple des réponses de la question

    reponses(("a", ("b", "c", "d", "e")))
    retourne ("b", "c", "d", "e")
    """
    return question[1]

def bonne_reponse(question):
    """question une question
    retourne la bonne réponse de la question

    bonne_reponse(("a", ("b", "c", "d", "e")))
    retourne "b"
    """
    return reponses(question)[0]

def melange(tu):
    """tu un tuple à mélanger.
    Retourne une copie de tu mélangée aléatoirement.
    """
    l = list(tu)
    shuffle(l)
    t = tuple(l)
    return t

def demander_choix(question, choix):
    """question une chaine de caractères, la question
    choix un tuple de chaines, les choix possibles.

    Redemande une saisie à l'utilisateur tant que sa réponse n'est pas un des choix
    retourne le choix valide choisi.
    """
    choix_melanges = melange(choix)
    reponse = input(f"{question} {choix_melanges} : ")
    while not (reponse in choix_melanges):
        reponse = input(f"Choisissez {choix_melanges} :")
    return reponse


def poser_question(question, r1, r2, r3, r4):
    """question une chaine de caractères, la question a poser
    r1, r2, r3, r4, les réponses possibles. r1 est la bonne réponse.

    pose la question à l'utilisateur. Retourne 1 si la réponse est la bonne, 0 sinon.
    """
    reponse = demander_choix(question, (r1, r2, r3, r4))
    if reponse == r1:
        print("Vrai !")
        return 1
    else:
        print(f"Faux : {r1}")
        return 0

def main():
    bonnes_reponses = 0
    bonnes_reponses += poser_question("En quelle année a eu lieu la prise de la Bastille ?", "1789", "1988",  "1987", "1452")
    bonnes_reponses += poser_question("La SNT est un cours dispensé en classe de ?", "Seconde", "Première",  "Terminale", "3eme")
    bonnes_reponses += poser_question("Le terme cortinaire désigne en général un ?", "champignon", "végétal", "animal",  "minéral")
    print("Nombre de questions : 3")
    print(f"Bonnes réponses : {bonnes_reponses}")

if __name__=="__main__":
    main()

Nous allons maintenant modifier le code de la fonction poser_question pour qu'elle ne prenne qu'un seul argument : la question.

def poser_question(question, r1, r2, r3, r4):
    """question une chaine de caractères, la question a poser
    r1, r2, r3, r4, les réponses possibles. r1 est la bonne réponse.

    pose la question à l'utilisateur. Retourne 1 si la réponse est la bonne, 0 sinon.
    """

devient

def poser_question(question):
    """question une question

    pose la question à l'utilisateur. Retourne 1 si la réponse est la bonne, 0 sinon.
    """

Modifiez le code de la fonction pour qu'elle corresponde à cette nouvelle spécification. Aidez-vous des fonctions texte, reponses et bonne_reponse définies plus haut.

Attention

Pour tester votre code, vous aurez sans doute besoin de modifier dans la fonction main les appels à poser_question.

Les lignes

bonnes_reponses += poser_question("En quelle année a eu lieu la prise de la Bastille ?", "1789", "1988",  "1987", "1452")
bonnes_reponses += poser_question("La SNT est un cours dispensé en classe de ?", "Seconde", "Première",  "Terminale", "3eme")
bonnes_reponses += poser_question("Le terme cortinaire désigne en général un ?", "champignon", "végétal", "animal",  "minéral")

deviennent :

bonnes_reponses += poser_question(questions[0])
bonnes_reponses += poser_question(questions[1])
bonnes_reponses += poser_question(questions[2])
Solution

```python def poser_question(question): """question une question

pose la question à l'utilisateur. Retourne 1 si la réponse est la bonne, 0 sinon.
"""
bonne_rep = bonne_reponse(question)
reponse = demander_choix(texte(question), reponses(question))
if reponse == bonne_rep:
    print("Vrai !")
    return 1
else:
    print(f"Faux : {bonne_rep}")
    return 0
Solution (Code complet)
questions = [
    ("En quelle année a eu lieu la prise de la Bastille ?", ("1789", "1988",  "1987", "1452")),
    ("La SNT est un cours dispensé en classe de ?", ("Seconde", "Première",  "Terminale", "3eme")),
    ("Le terme cortinaire désigne en général un ?", ("champignon", "végétal", "animal",  "minéral"))
    ]

from random import shuffle

def texte(question):
    """question une question,
    retourne le texte de la question

    texte(("a", ("b", "c", "d", "e")))
    retourne "a"
    """
    return question[0]

def reponses(question):
    """question une question,
    retourne le tuple des réponses de la question

    reponses(("a", ("b", "c", "d", "e")))
    retourne ("b", "c", "d", "e")
    """
    return question[1]

def bonne_reponse(question):
    """question une question
    retourne la bonne réponse de la question

    bonne_reponse(("a", ("b", "c", "d", "e")))
    retourne "b"
    """
    return reponses(question)[0]

def melange(tu):
    """tu un tuple à mélanger.
    Retourne une copie de tu mélangée aléatoirement.
    """
    l = list(tu)
    shuffle(l)
    t = tuple(l)
    return t

def demander_choix(question, choix):
    """question une chaine de caractères, la question
    choix un tuple de chaines, les choix possibles.

    Redemande une saisie à l'utilisateur tant que sa réponse n'est pas un des choix
    retourne le choix valide choisi.
    """
    choix_melanges = melange(choix)
    reponse = input(f"{question} {choix_melanges} : ")
    while not (reponse in choix_melanges):
        reponse = input(f"Choisissez {choix_melanges} :")
    return reponse


def poser_question(question):
    """question une question

    pose la question à l'utilisateur. Retourne 1 si la réponse est la bonne, 0 sinon.
    """
    bonne_rep = bonne_reponse(question)
    reponse = demander_choix(texte(question), reponses(question))
    if reponse == bonne_rep:
        print("Vrai !")
        return 1
    else:
        print(f"Faux : {bonne_rep}")
        return 0

def main():
    bonnes_reponses = 0
    bonnes_reponses += poser_question(questions[0])
    bonnes_reponses += poser_question(questions[1])
    bonnes_reponses += poser_question(questions[2])
    print("Nombre de questions : 3")
    print(f"Bonnes réponses : {bonnes_reponses}")

if __name__=="__main__":
    main()

Il nous reste un dernier changement à faire. Pour le moment, dans la fonction main, on pose les trois premières questions de la liste. Modifiez la fonction pour qu'elle pose toutes les questions de la liste.

Aide 1

Remplacez les répétitions de ligne

bonnes_reponses += poser_question(questions[0])
bonnes_reponses += poser_question(questions[1])
bonnes_reponses += poser_question(questions[2])

par une boucle for.

Utilisez la fonction len() pour connaître le nombre total de questions.

Aide 2

La boucle for doit ressembler au code suivant. Complétez les ....

for question in questions:
    ... += poser_question(...)
Solution
def main():
    bonnes_reponses = 0
    for question in questions:
        bonnes_reponses += poser_question(question)
    print(f"Nombre de questions : {len(questions)}")
    print(f"Bonnes réponses : {bonnes_reponses}")
Solution (Code complet)
questions = [
    ("En quelle année a eu lieu la prise de la Bastille ?", ("1789", "1988",  "1987", "1452")),
    ("La SNT est un cours dispensé en classe de ?", ("Seconde", "Première",  "Terminale", "3eme")),
    ("Le terme cortinaire désigne en général un ?", ("champignon", "végétal", "animal",  "minéral"))
    ]

from random import shuffle

def texte(question):
    """question une question,
    retourne le texte de la question

    texte(("a", ("b", "c", "d", "e")))
    retourne "a"
    """
    return question[0]

def reponses(question):
    """question une question,
    retourne le tuple des réponses de la question

    reponses(("a", ("b", "c", "d", "e")))
    retourne ("b", "c", "d", "e")
    """
    return question[1]

def bonne_reponse(question):
    """question une question
    retourne la bonne réponse de la question

    bonne_reponse(("a", ("b", "c", "d", "e")))
    retourne "b"
    """
    return reponses(question)[0]

def melange(tu):
    """tu un tuple à mélanger.
    Retourne une copie de tu mélangée aléatoirement.
    """
    l = list(tu)
    shuffle(l)
    t = tuple(l)
    return t

def demander_choix(question, choix):
    """question une chaine de caractères, la question
    choix un tuple de chaines, les choix possibles.

    Redemande une saisie à l'utilisateur tant que sa réponse n'est pas un des choix
    retourne le choix valide choisi.
    """
    choix_melanges = melange(choix)
    reponse = input(f"{question} {choix_melanges} : ")
    while not (reponse in choix_melanges):
        reponse = input(f"Choisissez {choix_melanges} :")
    return reponse


def poser_question(question):
    """question une question

    pose la question à l'utilisateur. Retourne 1 si la réponse est la bonne, 0 sinon.
    """
    bonne_rep = bonne_reponse(question)
    reponse = demander_choix(texte(question), reponses(question))
    if reponse == bonne_rep:
        print("Vrai !")
        return 1
    else:
        print(f"Faux : {bonne_rep}")
        return 0

def main():
    bonnes_reponses = 0
    for question in questions:
        bonnes_reponses += poser_question(question)
    print(f"Nombre de questions : {len(questions)}")
    print(f"Bonnes réponses : {bonnes_reponses}")

if __name__=="__main__":
    main()

Ajoutez maintenant quelques questions dans la list des questions, pour que sa taille soit de au moins 10. Sans aucune autre modification du code, le programme s'adapte automatiquement et pose toutes les questions !

Code complet
questions = [
    ("En quelle année a eu lieu la prise de la Bastille ?", ("1789", "1988",  "1987", "1452")),
    ("La SNT est un cours dispensé en classe de ?", ("Seconde", "Première",  "Terminale", "3eme")),
    ("Le terme cortinaire désigne en général un ?", ("champignon", "végétal", "animal",  "minéral")),
    ("Le genre de manga qui consiste à plonger un personnage dans un univers inconnu est ? ", ("isekai", "seinen", "shonen",  "shojo")),
    ("Le MMORPG français qui consiste en une quête de recherche d'oeufs de dragons est ?", ("Dofus", "World Of Warcraft", "Dragon Nest",  "PlanetSide 2")),
    ("Le personnage d'animé qui bat tous ses adversaire d'un coup de poing est ?", ("Saitama", "One Punch Man", "Genos",  "Tatsumaki")),
    ("L'ustensile de cuisine qui utilise la pression pour augmenter la température de la vapeur d'eau et cuire plus rapidement les aliments, est ?", ("Un autocuiseur", "Un cuit-vapeur", "Une cocotte",  "Une Marmite")),
    ("Dans quelle bande dessinée les occupants d'un train s'arrêtent dans une centrale nucléaire défaillante ?", ("Le Transperceneige", "Kabaneri of the Iron Fortress", "Nuclear Train",  "Yoko Tsuno")),
    ("Parmi ces 4 serpents, lequel est aussi un langage de programmation très utilisé ?", ("Python", "Cobra", "Vipère", "Mamba")),
    ("Quel théorème énonce une relation entre les longueurs des côtés et de l'hypothènuse d'un triangle rectangle ?", ("Pythagore", "Thalès", "Godel", "Haskell")),
    ("Une trottinette avec des roues a rayons et des pneus gonflables s'appelle ?", ("kickbike", "trottivelo", "velotinette", "kickcycle"))
    ]

from random import shuffle

def texte(question):
    """question une question,
    retourne le texte de la question

    texte(("a", ("b", "c", "d", "e")))
    retourne "a"
    """
    return question[0]

def reponses(question):
    """question une question,
    retourne le tuple des réponses de la question

    reponses(("a", ("b", "c", "d", "e")))
    retourne ("b", "c", "d", "e")
    """
    return question[1]

def bonne_reponse(question):
    """question une question
    retourne la bonne réponse de la question

    bonne_reponse(("a", ("b", "c", "d", "e")))
    retourne "b"
    """
    return reponses(question)[0]

def melange(tu):
    """tu un tuple à mélanger.
    Retourne une copie de tu mélangée aléatoirement.
    """
    l = list(tu)
    shuffle(l)
    t = tuple(l)
    return t

def demander_choix(question, choix):
    """question une chaine de caractères, la question
    choix un tuple de chaines, les choix possibles.

    Redemande une saisie à l'utilisateur tant que sa réponse n'est pas un des choix
    retourne le choix valide choisi.
    """
    choix_melanges = melange(choix)
    reponse = input(f"{question} {choix_melanges} : ")
    while not (reponse in choix_melanges):
        reponse = input(f"Choisissez {choix_melanges} :")
    return reponse


def poser_question(question):
    """question une question

    pose la question à l'utilisateur. Retourne 1 si la réponse est la bonne, 0 sinon.
    """
    bonne_rep = bonne_reponse(question)
    reponse = demander_choix(texte(question), reponses(question))
    if reponse == bonne_rep:
        print("Vrai !")
        return 1
    else:
        print(f"Faux : {bonne_rep}")
        return 0

def main():
    bonnes_reponses = 0
    for question in questions:
        bonnes_reponses += poser_question(question)
    print(f"Nombre de questions : {len(questions)}")
    print(f"Bonnes réponses : {bonnes_reponses}")

if __name__=="__main__":
    main()

0.6 : Questions aléatoires

Le programme choisit aléatoirement un certain nombre de questions dans la liste des questions.

Comme le nombre de questions disponibles dans le programme va augmenter avec le temps, on va proposer à l'utilisateur de choisir le nombre de questions auxquelles il veut répondre. Le programme choisira alors aléatoirement des questions dans la liste.

On va commencer par choisir aléatoirement un nombre fixe de questions.

Pour ça, on peut s'aider de la fonction random.sample. Cette fonction prends deux paramètres :

  • une list, dans laquelle on va piocher
  • un entier, qui est le nombre d'éléments à piocher

Elle retourne la liste des éléments piochés.

import random

l = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
s = random.sample(l, 4)
print(l)

affichera quelque chose comme :

[7, 5, 3, 9]

Bien entendu, cette sortie changera à chaque execution, puisque sample choisit des éléments aléatoires.

Modifiez la fonction main du programme, en utilisant la fonction sample, de manière à ce que le programme choisisse 4 questions parmi la liste questions et les pose à l'utilisateur.

Aide

Il vous faut créer une variable intermédiaire, questions_choisies, et l'utiliser à la place de questions dans le reste de la fonction main.

N'oubliez pas d'importer sample depuis le module random !

Solution
##plus haut dans le code
from random import sample

##la fonction main
def main():
    bonnes_reponses = 0
    questions_choisies = sample(questions, 4)
    for question in questions_choisies:
        bonnes_reponses += poser_question(question)
    print(f"Nombre de questions : {len(questions_choisies)}")
    print(f"Bonnes réponses : {bonnes_reponses}")
Solution (Code complet)
questions = [
    ("En quelle année a eu lieu la prise de la Bastille ?", ("1789", "1988",  "1987", "1452")),
    ("La SNT est un cours dispensé en classe de ?", ("Seconde", "Première",  "Terminale", "3eme")),
    ("Le terme cortinaire désigne en général un ?", ("champignon", "végétal", "animal",  "minéral")),
    ("Le genre de manga qui consiste à plonger un personnage dans un univers inconnu est ? ", ("isekai", "seinen", "shonen",  "shojo")),
    ("Le MMORPG français qui consiste en une quête de recherche d'oeufs de dragons est ?", ("Dofus", "World Of Warcraft", "Dragon Nest",  "PlanetSide 2")),
    ("Le personnage d'animé qui bat tous ses adversaire d'un coup de poing est ?", ("Saitama", "One Punch Man", "Genos",  "Tatsumaki")),
    ("L'ustensile de cuisine qui utilise la pression pour augmenter la température de la vapeur d'eau et cuire plus rapidement les aliments, est ?", ("Un autocuiseur", "Un cuit-vapeur", "Une cocotte",  "Une Marmite")),
    ("Dans quelle bande dessinée les occupants d'un train s'arrêtent dans une centrale nucléaire défaillante ?", ("Le Transperceneige", "Kabaneri of the Iron Fortress", "Nuclear Train",  "Yoko Tsuno")),
    ("Parmi ces 4 serpents, lequel est aussi un langage de programmation très utilisé ?", ("Python", "Cobra", "Vipère", "Mamba")),
    ("Quel théorème énonce une relation entre les longueurs des côtés et de l'hypothènuse d'un triangle rectangle ?", ("Pythagore", "Thalès", "Godel", "Haskell")),
    ("Une trottinette avec des roues a rayons et des pneus gonflables s'appelle ?", ("kickbike", "trottivelo", "velotinette", "kickcycle"))
    ]

from random import shuffle
from random import sample

def texte(question):
    """question une question,
    retourne le texte de la question

    texte(("a", ("b", "c", "d", "e")))
    retourne "a"
    """
    return question[0]

def reponses(question):
    """question une question,
    retourne le tuple des réponses de la question

    reponses(("a", ("b", "c", "d", "e")))
    retourne ("b", "c", "d", "e")
    """
    return question[1]

def bonne_reponse(question):
    """question une question
    retourne la bonne réponse de la question

    bonne_reponse(("a", ("b", "c", "d", "e")))
    retourne "b"
    """
    return reponses(question)[0]

def melange(tu):
    """tu un tuple à mélanger.
    Retourne une copie de tu mélangée aléatoirement.
    """
    l = list(tu)
    shuffle(l)
    t = tuple(l)
    return t

def demander_choix(question, choix):
    """question une chaine de caractères, la question
    choix un tuple de chaines, les choix possibles.

    Redemande une saisie à l'utilisateur tant que sa réponse n'est pas un des choix
    retourne le choix valide choisi.
    """
    choix_melanges = melange(choix)
    reponse = input(f"{question} {choix_melanges} : ")
    while not (reponse in choix_melanges):
        reponse = input(f"Choisissez {choix_melanges} :")
    return reponse


def poser_question(question):
    """question une question

    pose la question à l'utilisateur. Retourne 1 si la réponse est la bonne, 0 sinon.
    """
    bonne_rep = bonne_reponse(question)
    reponse = demander_choix(texte(question), reponses(question))
    if reponse == bonne_rep:
        print("Vrai !")
        return 1
    else:
        print(f"Faux : {bonne_rep}")
        return 0

def main():
    bonnes_reponses = 0
    questions_choisies = sample(questions, 4)
    for question in questions_choisies:
        bonnes_reponses += poser_question(question)
    print(f"Nombre de questions : {len(questions_choisies)}")
    print(f"Bonnes réponses : {bonnes_reponses}")

if __name__=="__main__":
    main()

Il ne reste plus qu'à demander à l'utilisateur au lieu d'utiliser un nombre fixe. Modifiez la fonction main, de manière à ce qu'au début du programme, le nombre de question soit demandé à l'utilisateur. Ce nombre doit être compris entre 1 et le nombre de questions. Si il est plus petit, forcez-le à 1, si il est plus grand, forcez-le au nombre de questions. Si l'utilisateur n'entre pas un entier, on laisse le programme planter.

Aide 1

N'oubliez de transtyper (caster) l'entrée utilisateur, d'une str vers un int.

Utilisez un if pour vérifier et forcer la valeur d'un nombre

Le nombre de question est len(questions).

Aide 2

Voici comment on force la valeur à 1 si elle est inférieure à 1

##on suppose que nombre_question est déjà déclarée et initialisée
if nombre_questions < 1:
    nombre_questions = 1

Il vous reste à forcer la valeur à len(questions) si elle est supérieure à len(questions).

Solution
def main():
    nombre_questions = int(input(f"Choisissez le nombre de questions (1-{len(questions)}): "))
    if nombre_questions < 1 :
        nombre_questions = 1
    elif nombre_questions > len(questions):
        nombre_questions = len(questions)

    bonnes_reponses = 0
    questions_choisies = sample(questions, nombre_questions)
    for question in questions_choisies:
        bonnes_reponses += poser_question(question)
    print(f"Nombre de questions : {len(questions_choisies)}")
    print(f"Bonnes réponses : {bonnes_reponses}")
Solution (Code complet)
questions = [
    ("En quelle année a eu lieu la prise de la Bastille ?", ("1789", "1988",  "1987", "1452")),
    ("La SNT est un cours dispensé en classe de ?", ("Seconde", "Première",  "Terminale", "3eme")),
    ("Le terme cortinaire désigne en général un ?", ("champignon", "végétal", "animal",  "minéral")),
    ("Le genre de manga qui consiste à plonger un personnage dans un univers inconnu est ? ", ("isekai", "seinen", "shonen",  "shojo")),
    ("Le MMORPG français qui consiste en une quête de recherche d'oeufs de dragons est ?", ("Dofus", "World Of Warcraft", "Dragon Nest",  "PlanetSide 2")),
    ("Le personnage d'animé qui bat tous ses adversaire d'un coup de poing est ?", ("Saitama", "One Punch Man", "Genos",  "Tatsumaki")),
    ("L'ustensile de cuisine qui utilise la pression pour augmenter la température de la vapeur d'eau et cuire plus rapidement les aliments, est ?", ("Un autocuiseur", "Un cuit-vapeur", "Une cocotte",  "Une Marmite")),
    ("Dans quelle bande dessinée les occupants d'un train s'arrêtent dans une centrale nucléaire défaillante ?", ("Le Transperceneige", "Kabaneri of the Iron Fortress", "Nuclear Train",  "Yoko Tsuno")),
    ("Parmi ces 4 serpents, lequel est aussi un langage de programmation très utilisé ?", ("Python", "Cobra", "Vipère", "Mamba")),
    ("Quel théorème énonce une relation entre les longueurs des côtés et de l'hypothènuse d'un triangle rectangle ?", ("Pythagore", "Thalès", "Godel", "Haskell")),
    ("Une trottinette avec des roues a rayons et des pneus gonflables s'appelle ?", ("kickbike", "trottivelo", "velotinette", "kickcycle"))
    ]

from random import shuffle
from random import sample

def texte(question):
    """question une question,
    retourne le texte de la question

    texte(("a", ("b", "c", "d", "e")))
    retourne "a"
    """
    return question[0]

def reponses(question):
    """question une question,
    retourne le tuple des réponses de la question

    reponses(("a", ("b", "c", "d", "e")))
    retourne ("b", "c", "d", "e")
    """
    return question[1]

def bonne_reponse(question):
    """question une question
    retourne la bonne réponse de la question

    bonne_reponse(("a", ("b", "c", "d", "e")))
    retourne "b"
    """
    return reponses(question)[0]

def melange(tu):
    """tu un tuple à mélanger.
    Retourne une copie de tu mélangée aléatoirement.
    """
    l = list(tu)
    shuffle(l)
    t = tuple(l)
    return t

def demander_choix(question, choix):
    """question une chaine de caractères, la question
    choix un tuple de chaines, les choix possibles.

    Redemande une saisie à l'utilisateur tant que sa réponse n'est pas un des choix
    retourne le choix valide choisi.
    """
    choix_melanges = melange(choix)
    reponse = input(f"{question} {choix_melanges} : ")
    while not (reponse in choix_melanges):
        reponse = input(f"Choisissez {choix_melanges} :")
    return reponse


def poser_question(question):
    """question une question

    pose la question à l'utilisateur. Retourne 1 si la réponse est la bonne, 0 sinon.
    """
    bonne_rep = bonne_reponse(question)
    reponse = demander_choix(texte(question), reponses(question))
    if reponse == bonne_rep:
        print("Vrai !")
        return 1
    else:
        print(f"Faux : {bonne_rep}")
        return 0

def main():
    nombre_questions = int(input(f"Choisissez le nombre de questions (1-{len(questions)}): "))
    if nombre_questions < 1 :
        nombre_questions = 1
    elif nombre_questions > len(questions):
        nombre_questions = len(questions)

    bonnes_reponses = 0
    questions_choisies = sample(questions, nombre_questions)
    for question in questions_choisies:
        bonnes_reponses += poser_question(question)
    print(f"Nombre de questions : {len(questions_choisies)}")
    print(f"Bonnes réponses : {bonnes_reponses}")

if __name__=="__main__":
    main()