04 - Boucles

Les exercices se font dans Thonny, dans le fichier 04_boucles.py.

Cours associé : 05 - Boucles .

Exercice 0 : QCM – vérification des prérequis

Pour chaque question, une seule réponse est correcte.

1. Quelles valeurs prend i dans la boucle for i in range(3, 7): ?

  • A. 3, 4, 5, 6, 7
  • B. 3, 4, 5, 6
  • C. 4, 5, 6
  • D. 3, 4, 5
Correction

Réponse : B. range(3, 7) génère les entiers de 3 (inclus) à 7 (exclu), soit 3, 4, 5, 6.

  • A est faux : la borne supérieure est exclue (erreur fréquente : oublier que range s’arrête avant la borne).
  • C est faux : la borne inférieure est incluse.
  • D est faux : il manque 6 ; range(3, 7) produit quatre valeurs, pas trois.

2. Combien de fois la boucle suivante s’exécute-t-elle ?

for i in range(5):
    print(i)
  • A. 4 fois
  • B. 5 fois
  • C. 6 fois
  • D. Cela dépend de la valeur de i
Correction

Réponse : B. range(5) produit les valeurs 0, 1, 2, 3, 4, soit cinq itérations.

  • A est faux : c’est l’erreur qui consiste à commencer à compter à 1 (la boucle commence à 0).
  • C est faux : range(5) ne produit pas la valeur 5.
  • D est faux : i est la variable de boucle, elle prend successivement chaque valeur de range(5).

3. Quelle est la différence entre for et while ?

  • A. for est plus rapide que while
  • B. for s’utilise quand on connaît le nombre d’itérations, while quand on ne le connaît pas à l’avance
  • C. while ne peut pas faire de boucles infinies
  • D. for et while sont strictement équivalents et interchangeables dans tous les cas
Correction

Réponse : B. On utilise for lorsqu’on sait combien de fois on veut itérer (parcourir une liste, un range, etc.) et while lorsque le nombre de répétitions dépend d’une condition vérifiée à chaque tour.

  • A est faux : la vitesse dépend du contenu de la boucle, pas du mot-clé.
  • C est faux : while True: crée une boucle infinie.
  • D est faux : bien que l’on puisse souvent réécrire l’une avec l’autre, while est nécessaire quand le nombre d’itérations n’est pas connu à l’avance.

4. Que vaut s après l’exécution du code suivant ?

s = 0
for i in range(1, 4):
    s = s + i
  • A. 3
  • B. 6
  • C. 10
  • D. 4
Correction

Réponse : B. range(1, 4) produit 1, 2, 3. La variable s accumule la somme : 0 + 1 = 1, puis 1 + 2 = 3, puis 3 + 3 = 6.

  • A est faux : c’est la valeur du dernier i, pas de la somme.
  • C est faux : c’est la somme 1 + 2 + 3 + 4, comme si range(1, 4) incluait 4 (erreur de borne).
  • D est faux : c’est 1 + 3, comme si on avait sauté i = 2.

Exercice 1

Sans exécuter les programmes, dire combien de fois chacun affiche le symbole #. Expliquer, puis vérifier.

Programme 1

for i in range(4):
    print("#", end="")
for j in range(6):
    print("#", end="")
print()

Programme 2

for i in range(4):
    for j in range(6):
        print("#", end="")
print()

Programme 3

for i in range(4):
    for j in range(i):
        print("#", end="")
print()
Indice

Compter combien de fois l’instruction print("#", end="") est exécutée. Quand une boucle est placée à l’intérieur d’une autre, elle est exécutée en entier à chaque tour de la boucle extérieure. Dans le programme 3, le nombre de tours de la boucle intérieure change à chaque tour.

Correction

Programme 1 : 10 symboles. Les deux boucles sont à la suite l’une de l’autre, au même niveau d’indentation : la première affiche 4 symboles, la seconde 6, soit \(4 + 6 = 10\).

Programme 2 : 24 symboles. Les boucles sont imbriquées : pour chacune des 4 valeurs de i, la boucle sur j affiche 6 symboles, soit \(4 \times 6 = 24\).

Programme 3 : 6 symboles. La boucle intérieure fait i tours : 0 tour quand i vaut 0, puis 1, 2 et 3 tours, soit \(0 + 1 + 2 + 3 = 6\).

C’est l’indentation de la seconde boucle qui décide si elle est à la suite de la première ou à l’intérieur.

Exercice 2

Le programme suivant lance un dé à six faces une seule fois :

import random

de = random.randint(1, 6)
print(f"Le dé affiche {de}")

Le modifier pour qu’il relance le dé tant que le 6 n’est pas sorti, en affichant chaque lancer, puis qu’il affiche le nombre de lancers qu’il a fallu.

Indice

On ne sait pas à l’avance combien de lancers il faudra : c’est le cas d’une boucle while. Pour que la condition de != 6 puisse être testée dès le premier tour, donner d’abord à de une valeur qui n’est pas 6, par exemple 0. Un compteur, qui vaut 0 avant la boucle, augmente de 1 à chaque lancer.

Code à copier puis compléter
import random

de = 0
lancers = 0
while ...:
    de = random.randint(1, 6)
    lancers = ...
    print(f"Le dé affiche {de}")
print(f"Le 6 est sorti au bout de {lancers} lancer(s)")
Correction
import random

de = 0
lancers = 0
while de != 6:
    de = random.randint(1, 6)
    lancers = lancers + 1
    print(f"Le dé affiche {de}")
print(f"Le 6 est sorti au bout de {lancers} lancer(s)")

La boucle while répète le lancer tant que le dé n’affiche pas 6. La valeur de départ de = 0 garantit qu’on entre dans la boucle au moins une fois. En relançant le programme plusieurs fois, le nombre de lancers change : il vaut 6 en moyenne.

Exercice 3

On lance deux dés et on additionne leurs valeurs. Écrire un programme qui affiche le tableau de toutes les sommes possibles : une ligne pour chaque valeur du premier dé, une colonne pour chaque valeur du second.

2 3 4 5 6 7
3 4 5 6 7 8
4 5 6 7 8 9
5 6 7 8 9 10
6 7 8 9 10 11
7 8 9 10 11 12
Indice

Deux boucles for imbriquées : la boucle extérieure choisit la valeur du premier dé, la boucle intérieure parcourt celle du second. print(..., end=" ") affiche sans aller à la ligne, et un print() vide termine la ligne.

Correction
for de1 in range(1, 7):
    for de2 in range(1, 7):
        print(de1 + de2, end=" ")
    print()

Le print() vide est placé dans la boucle extérieure, après la boucle intérieure : il termine chaque ligne du tableau.

Exercice 4

Écrire un programme qui affiche les puissances de 2, de \(2^0\) à \(2^{16}\), sous la forme 2 puissance 10 = 1024. Quelle puissance de 2 correspond au nombre de valeurs différentes d’un octet ?

Indice

Une seule boucle for suffit ; l’opérateur ** calcule une puissance. Combien de valeurs range doit-il produire pour aller de 0 à 16 ?

Correction
for n in range(17):
    print(f"2 puissance {n} = {2 ** n}")

range(17) produit les entiers de 0 à 16. Un octet compte 8 bits : il peut prendre \(2^8 = 256\) valeurs différentes.

Exercice 5

Une culture contient 100 bactéries, et leur nombre double toutes les 20 minutes. Écrire un programme qui affiche, toutes les 20 minutes, le temps écoulé et le nombre de bactéries, tant que ce nombre ne dépasse pas un million. Il affiche ensuite au bout de combien de minutes le million est dépassé.

Indice

On ne sait pas à l’avance combien de lignes il y aura : utiliser une boucle while dont la condition porte sur le nombre de bactéries. À chaque tour, le nombre de bactéries double et le temps augmente de 20 minutes.

Correction
bacteries = 100
minutes = 0
while bacteries <= 1000000:
    print(f"{minutes} min : {bacteries} bactéries")
    bacteries = bacteries * 2
    minutes = minutes + 20
print(f"Le million est dépassé au bout de {minutes} minutes : {bacteries} bactéries")

Le programme affiche 14 lignes, de 100 à 819 200 bactéries, puis indique que le million est dépassé au bout de 280 minutes, soit 4 h 40, avec 1 638 400 bactéries.

Exercice 6

Une balle lâchée d’une hauteur de 2 mètres remonte, à chaque rebond, à 80 % de la hauteur précédente. Écrire un programme qui affiche la hauteur atteinte après chacun des 10 premiers rebonds, arrondie au centimètre.

Indice

Remonter à 80 % de la hauteur, c’est la multiplier par 0,8. Une boucle for qui fait 10 tours suffit ; round(h, 2) arrondit h à deux chiffres après la virgule.

Correction
hauteur = 2
for rebond in range(1, 11):
    hauteur = hauteur * 0.8
    print(f"Rebond {rebond} : {round(hauteur, 2)} m")

Les hauteurs affichées vont de 1,6 m après le premier rebond à environ 0,21 m après le dixième. Chaque valeur est calculée à partir de la précédente : c’est une suite dont chaque terme vaut 0,8 fois le précédent.

Exercice 7

On rappelle qu’une année est bissextile si elle est divisible par 4 sans être divisible par 100, ou si elle est divisible par 400. Écrire un programme qui affiche toutes les années bissextiles de 2000 à 2100, puis leur nombre.

Indice

Parcourir les années avec une boucle for, n’afficher que celles qui vérifient la condition, et augmenter un compteur à chaque année affichée.

Correction
nombre = 0
for annee in range(2000, 2101):
    if (annee % 4 == 0 and annee % 100 != 0) or annee % 400 == 0:
        print(annee)
        nombre = nombre + 1
print(f"{nombre} années bissextiles")

Le programme affiche 2000, 2004, …, 2096, soit 25 années. 2000 est bissextile, car divisible par 400 ; 2100 ne l’est pas, car divisible par 100 sans l’être par 400.

Exercice 8

Écrire un programme qui affiche le motif suivant :

1
12
123
1234
12345
Indice

La ligne numéro i contient les chiffres de 1 à i. On peut utiliser deux boucles imbriquées, avec print(..., end=""), ou une seule boucle qui ajoute un chiffre à une chaîne à chaque tour.

Correction

Avec deux boucles imbriquées :

for i in range(1, 6):
    for chiffre in range(1, i + 1):
        print(chiffre, end="")
    print()

Avec une seule boucle : la chaîne ligne s’allonge d’un chiffre à chaque tour, puis on l’affiche.

ligne = ""
for i in range(1, 6):
    ligne = ligne + str(i)
    print(ligne)

Exercice 9

Écrire un programme qui demande combien de notes un élève a obtenues, puis demande ces notes une par une, et affiche leur moyenne et la meilleure note.

Indice

Avant la boucle, une variable somme vaut 0 et une variable meilleure vaut une note impossible, comme -1. À chaque note saisie, on l’ajoute à somme, et on remplace meilleure si la nouvelle note est plus grande.

Code à copier puis compléter
nombre = int(input("Nombre de notes : "))
somme = 0
meilleure = -1
for k in range(1, nombre + 1):
    note = float(input(f"Note {k} : "))
    somme = ...
    if ...:
        meilleure = note
print(f"Moyenne : {round(somme / nombre, 2)}")
print(f"Meilleure note : {meilleure}")
Correction
nombre = int(input("Nombre de notes : "))
somme = 0
meilleure = -1
for k in range(1, nombre + 1):
    note = float(input(f"Note {k} : "))
    somme = somme + note
    if note > meilleure:
        meilleure = note
print(f"Moyenne : {round(somme / nombre, 2)}")
print(f"Meilleure note : {meilleure}")

somme est un accumulateur : elle part de 0 et reçoit chaque note. meilleure garde la plus grande note vue jusqu’ici ; partir de -1, plus petit que toute note, garantit que la première note la remplace.

Test : avec les notes 12, 15 et 9, le programme affiche une moyenne de 12.0 et une meilleure note de 15.0.

Exercice 10

On s’intéresse à la fonction \(f(x) = x^2 - 2\), qui s’annule pour \(x = \sqrt{2}\).

  1. Écrire un programme qui affiche \(f(x)\) pour les entiers \(x\) de -3 à 3.

  2. Écrire un programme qui affiche \(f(x)\) pour \(x\) allant de -10 à 10 avec un pas de 2.

    Indice

    Le troisième paramètre de range est le pas : range(debut, fin, pas). La valeur de fin est exclue.

  3. Écrire un programme qui affiche \(f(x)\) pour \(x\) allant de 0 à 2 avec un pas de 0,1. Entre quelles valeurs de \(x\) le signe de \(f(x)\) change-t-il ? Qu’en déduit-on pour \(\sqrt{2}\) ?

    Indice

    range ne produit que des entiers : parcourir les entiers de 0 à 20, puis diviser chacun par 10.

  4. Écrire la même chose avec une boucle while : x part de 0 et augmente de 0,1 à chaque tour, tant que x <= 2. Comparer les valeurs de x affichées et le nombre de lignes avec la question 3. Que remarque-t-on ?

    Indice

    Afficher x sans arrondi : vaut-il exactement 0.3 au troisième tour ? Le cours sur les nombres réels explique pourquoi.

Correction

1.

for x in range(-3, 4):
    print(f"f({x}) = {x * x - 2}")

2.

for x in range(-10, 11, 2):
    print(f"f({x}) = {x * x - 2}")

range(-10, 11, 2) donne \(-10, -8, \ldots, 8, 10\) : la fin, 11, est exclue.

3.

for k in range(0, 21):
    x = k / 10
    print(f"f({x}) = {round(x * x - 2, 4)}")

\(f(1{,}4) \approx -0{,}04\) est négatif et \(f(1{,}5) = 0{,}25\) est positif : la fonction s’annule entre 1,4 et 1,5, donc \(1{,}4 < \sqrt{2} < 1{,}5\).

4.

x = 0
while x <= 2:
    print(f"f({x}) = {round(x * x - 2, 4)}")
    x = x + 0.1

Remarque : la boucle for affiche 21 lignes, de 0.0 à 2.0 ; la boucle while n’en affiche que 20. Les valeurs de x ne sont pas exactes : on lit par exemple f(0.30000000000000004), car 0,1 ne s’écrit pas exactement en binaire et les petites erreurs s’additionnent à chaque tour. Après la valeur 1.9000000000000006, x vaut 2.0000000000000004, plus grand que 2 : la boucle s’arrête sans traiter \(x = 2\). Pour un pas décimal, il vaut mieux compter avec des entiers, comme à la question 3.

Exercice 11

Écrire un programme qui demande un mot et construit, lettre par lettre, la chaîne envers qui contient ce mot écrit à l’envers, puis l’affiche. Par exemple, python donne nohtyp. Tester avec radar : que remarque-t-on ?

Indice

Une boucle for parcourt une chaîne caractère par caractère. Partir d’une chaîne vide et placer chaque nouvelle lettre devant ce qui a déjà été construit : envers = lettre + envers.

Correction
mot = input("Mot : ")
envers = ""
for lettre in mot:
    envers = lettre + envers
print(envers)

Avec python, envers vaut successivement p, yp, typ, htyp, ohtyp, puis nohtyp. Le mot radar reste identique une fois retourné : c’est un palindrome.

Exercice 12 : compte à rebours

Écrire un programme qui demande un entier positif n à l’utilisateur, puis affiche un compte à rebours de n à 0 avec une boucle while. Exemple : pour 5, afficher 5, 4, 3, 2, 1, 0.

Indice

À chaque tour, afficher n, puis le diminuer de 1. Quelle condition doit rester vraie pour continuer jusqu’à 0 inclus ?

Correction
n = int(input("Entrez un entier positif : "))
while n >= 0:
    print(n, end=" ")
    n = n - 1

Exercice 13 : somme des entiers

Écrire un programme qui calcule la somme des entiers de 1 à n (n saisi par l’utilisateur) avec une boucle while. Pour n = 5, la somme vaut $1 + 2 + 3 + 4 + 5 = 15$.

Indice

Deux variables avant la boucle : somme, qui vaut 0, et un compteur i, qui vaut 1. À chaque tour, ajouter i à somme, puis augmenter i de 1.

Correction
n = int(input("Entrez un entier positif : "))
somme = 0
i = 1
while i <= n:
    somme = somme + i
    i = i + 1
print(f"La somme des entiers de 1 à {n} est {somme}")

On initialise somme à 0 et i à 1 avant la boucle ; à chaque tour, on ajoute i puis on l’incrémente.

Exercice 14 : devine le nombre

Écrire un jeu où l’ordinateur choisit un nombre au hasard entre 1 et 100 (random.randint(1, 100), après import random) et où l’utilisateur doit le deviner. À chaque essai, le programme indique si le nombre cherché est plus grand ou plus petit, et s’arrête quand il est trouvé.

Indice

Tant que la proposition est différente du nombre secret, redemander un nombre et comparer. Pour entrer dans la boucle, donner d’abord à la proposition une valeur impossible, comme 0.

Code à copier puis compléter
import random

nombre_secret = random.randint(1, 100)
proposition = 0
while ...:
    proposition = int(input("Devinez le nombre (entre 1 et 100) : "))
    if proposition < nombre_secret:
        print("C'est plus grand !")
    elif ...:
        ...
    else:
        print("Bravo, vous avez trouvé !")
Correction
import random

nombre_secret = random.randint(1, 100)
proposition = 0
while proposition != nombre_secret:
    proposition = int(input("Devinez le nombre (entre 1 et 100) : "))
    if proposition < nombre_secret:
        print("C'est plus grand !")
    elif proposition > nombre_secret:
        print("C'est plus petit !")
    else:
        print("Bravo, vous avez trouvé !")

Améliorations possibles : compter les tentatives, en limiter le nombre, vérifier que la saisie est bien entre 1 et 100.

Exercice 15 : suite de Fibonacci

La suite de Fibonacci commence par 0 et 1, puis chaque terme est la somme des deux précédents : 0, 1, 1, 2, 3, 5, 8, 13, 21, 34… Afficher ses n premiers termes (n saisi par l’utilisateur) avec une boucle while. On aura besoin de deux variables pour les deux derniers termes et d’un compteur.

Indice

À chaque tour, afficher a, calculer le terme suivant a + b, puis décaler : a prend la valeur de b, et b celle du nouveau terme. L’ordre des affectations compte.

Code à copier puis compléter
n = int(input("Combien de termes ? "))
a = 0
b = 1
compteur = 0
while compteur < n:
    print(a)
    nouveau = ...
    a = ...
    b = ...
    compteur = compteur + 1
Correction
n = int(input("Combien de termes ? "))
a = 0
b = 1
compteur = 0
while compteur < n:
    print(a)
    nouveau = a + b
    a = b
    b = nouveau
    compteur = compteur + 1

Les trois lignes de décalage se remplacent par une affectation simultanée : a, b = b, a + b.

Exercice 16 : validation de mot de passe

Écrire un programme qui demande un mot de passe. Le mot de passe correct est "NSI2026". Le programme redemande le mot de passe tant qu’il est incorrect, avec au plus trois tentatives, puis affiche « Accès autorisé » ou « Accès refusé ».

Indice

La boucle continue tant que deux conditions sont vraies : le mot de passe est incorrect, et il reste des tentatives. Les combiner avec and.

Correction
mot_de_passe_correct = "NSI2026"
tentatives_restantes = 3
mot_de_passe = ""
while mot_de_passe != mot_de_passe_correct and tentatives_restantes > 0:
    mot_de_passe = input("Entrez le mot de passe : ")
    if mot_de_passe == mot_de_passe_correct:
        print("Accès autorisé")
    else:
        tentatives_restantes = tentatives_restantes - 1
        if tentatives_restantes > 0:
            print(f"Mot de passe incorrect, il reste {tentatives_restantes} tentative(s).")
        else:
            print("Accès refusé")

La condition du while combine deux conditions avec and : le mot de passe est incorrect et il reste des tentatives.

Exercice 17 : jeu du plus ou moins à deux joueurs

Écrire un jeu où le joueur 1 choisit un nombre secret entre 1 et 50, puis où le joueur 2 doit le deviner en sept tentatives au plus. Après chaque proposition, le programme indique « plus grand » ou « plus petit », compte les tentatives et affiche à la fin un message de victoire ou de défaite.

Indice

Même structure qu’à l’exercice 14, avec un compteur de tentatives : la boucle s’arrête quand le nombre est trouvé ou quand sept tentatives ont été faites. Après la boucle, tester si le nombre a été trouvé pour annoncer le vainqueur.

Correction
nombre_secret = int(input("Joueur 1, entrez le nombre secret (1 à 50) : "))
for i in range(50):      # fait défiler l'écran pour cacher le nombre
    print()
tentatives_max = 7
tentatives = 0
proposition = 0
while proposition != nombre_secret and tentatives < tentatives_max:
    print(f"Il reste {tentatives_max - tentatives} tentative(s)")
    proposition = int(input("Joueur 2, votre proposition : "))
    tentatives = tentatives + 1
    if proposition < nombre_secret:
        print("C'est plus grand !")
    elif proposition > nombre_secret:
        print("C'est plus petit !")
    else:
        print(f"Bravo joueur 2, trouvé en {tentatives} tentative(s) !")
if proposition != nombre_secret:
    print(f"Perdu ! Le nombre secret était {nombre_secret}. Victoire du joueur 1.")