Python - Boucles : corrigé des applications
L'écho
for i in range(20) :
print("Echo !")
Compte à rebours
for i in range(20, -1, -1) : # i varie de 20 à 0 ( -1 exclus ! ) par pas de -1
print(i, end = ' ')
Table de multiplication
Table de 3
for i in range(1, 11) : # i varie de 1 à 10 ( 11 exclus ! ) par pas de 1 ( sous-entendu )
print(i*3, end = ' ')
Fonction pour n'importe quelle table
def table_multiplication(n):
table = "" # chaîne, initialement vide, et que l'on construira peu à peu en lui concaténant les multiples calculés
for i in range(1, 11) :
table = table + " " + str(i*n) # un espace pour séparer les multiples
return table
print(table_multiplication(7))
En renvoyant la table sous forme de chaîne de caractères, on évite ainsi d'utiliser des instructions print() dans la fonction.
Ne pas oublier ( ligne 5 ) de transtyper le résultat du calcul de i*n ( un entier ) vers le type chaîne de caractères, sinon la concaténation est impossible ( Python signale une erreur.)
TableS de multiplication
Première idée : deux boucles imbriquées
Il faut ici reprendre le script précédent, en s'arrangeant pour le faire "tourner" autant de fois que l'on veut de tables différentes ( ici, 10 ), tout en changeant à chaque fois la valeur du nombre dont
on veut la table : au lieu de i*3, il faudrait pouvoir "écrire" automatiquement :
print(i*1)pour la première table- puis
print(i*2)pour la deuxième, - puis
print(i*3), - etc......
La solution est de faire "tourner" la boucle de l'application 2 à l'intérieur d'une autre boucle : c'est celle-ci qui nous permettra de faire varier le nombre dont on veut la table...
On parle dans ce cas de deux boucles imbriquées; c'est une structure très commune en programmation, et pas toujours évidente à comprendre...Il faut notamment bien faire attention à l'indentation des instructions indiquant les blocs logiques de chacune des deux boucles.
Proposition de script
for j in range(1,11) : # le compteur j contient le nombre dont on veut la table ( table de 1, table de 2,...)
for i in range(1,11): # la boucle i crée chacune des tables
print(i*j, end = ' ')
print()
Remarques
- ligne 3 : la boucle i est imbriquée dans la boucle j, l'indentation indique donc que la boucle i est dans le bloc logique de la boucle j
- ligne 4 : le produit des deux compteurs
i*jnous donne la valeur à afficher; remarquer que cette instruction est indentée par rapport auforde la boucle i, car elle doit être exécutée à chaque tour de celle-ci. - ligne 5 : par contre, le retour à la ligne ne doit se faire qu'après l'écriture de la table complète, donc quand la boucle i est terminée : la dernière instruction n'est donc indentée que par rapport au
forde la boucle j; autrement dit, elle appartient au même bloc logique que la boucle i...
Pour éviter les print() dans la fonction, on peut là aussi construire la chaîne représentant les différentes tables; pour revenir à la ligne,
on utilisera alors le caractère '\n' qui signifie "retour à la ligne" :
def tableS_multiplication():
tables = '' # cette chaîne contiendra TOUTES les tables
for j in range(1,11) :
table = '' # et celle-ci ne contiendra QUE la table en train d'être construite
for i in range(1,11):
table += str(i*j)
tables += table + '\n'
return tables
Une autre possibilité : deux fonctions
On peut également reprendre la fonction précédente qui crée une seule table, et écrire une deuxième qui fait appel à elle pour construire la "table des tables" :
def table_multiplication(n):
table = ""
for i in range(1, 11) :
table = table + " " + str(i*n)
return table
def tableS_multiplication():
tables = ""
for j in range(1, 11):
table = table_multiplication(j) " on appelle la première fonction pour lui faire construire la table de j
tables += table + '\n'
return tables
Nombre de bits
L'idée
D'après le principe proposé, on va comparer chaque puissance de 2 croissante moins 1 au nombre, tant que l'on n'a pas dépassé ce nombre.
Cela nous donne donc le principe du code à écrire :
- utilisation d'une boucle
while - utilisation d'une variable n, initialisée à 0,pour tester chaque puissance de 2 croissante
- la condition à évaluer est une comparaison entre N ( le nombre à convertir ) et 2n-1 ( n = le nombre de bits pour cette conversion ).
- il faudra bien penser à incrémenter n dans la boucle !!
Proposition de script
def nombre_bits(N):
n_bits = 0 # initialisation du nombre de bits
while 2**n_bits - 1 < N: # tant que 2**n_bits - 1 est plus petit que N,
n_bits = n_bits + 1 # alors on incrémente n_bits
return n_bits # en sortie de boucle, 'n_bits' contient le nombre de bits
print(nombre_bits(3789147)) # 22 bits !
Remarque
Ligne 5 : attention à la condition à évaluer. Il ne faut pas confondre 2n qui est égal au nombre total de valeurs différentes que l'on peut coder avec n bits, et 2n - 1 qui est la valeur la plus grande que l'on peut coder avec n bits ( c'est elle qui nous intéresse ici ).
- l'instruction
whilesignifie "TANT QUE", et pas "JUSQU'A CE QUE"...
Le jeu du nombre à deviner
Proposition de script
from random import randint
nombre = randint( 1 , 100 )
entree = 0
while ( entree != nombre ) :
entree = int(input('Entrez votre proposition :'))
if ( entree > nombre ) :
print('Trop grand !')
elif ( entree < nombre ) :
print('Trop petit !')
print('Bravo !')
Remarques
- Ligne 5 : il est indispensable d'initialiser la variable entree avant d'y faire référence ( à la ligne 7 ); pour cela, on lui donne une valeur ( 0 ) qui soit forcément différente du nombre à deviner ( qui se trouve entre 1 et 100 ).
- Ligne 8 : il faut que le nombre proposé par le joueur varie à chaque tour de boucle
while; l'entrée utilisateur doit donc être faite à l'intérieur de cette boucle, et logiquement au début de celle-ci, avant l'évaluation des conditions. - Ligne 14 : lorsque le joueur a deviné le nombre, la condition
entree != nombredevient alors fausse et on sort donc de la boucle; l'affichage deGagné !doit donc se faire en dehors de la boucle.
Palindrome
De nombreuses façons différentes existent pour résoudre ce problème, en voici deux.
Réutilisation du code de la fonction "miroir" de chaîne de caractères
Finalement, un mot est un palindrome si il est identique à son mot "en miroir".
D'où l'idée qui consiste à :
- créer la chaîne en miroir de celle passée en paramètre
- tester ensuite si les deux chaînes sont identiques
On peut ( on doit ! ) bien sûr réutiliser le code la fonction envers() écrit au chapitre sur les fonctions :
def envers(chaine):
miroir = ''
for car in chaine :
miroir = car + miroir
return miroir
def est_palindrome(chaine):
# 1. Construction de la chaîne "miroir" en appelant la fonction précédente
chaine2 = envers(chaine)
# 2. Comparaison des deux chaînes
if chaine == chaine2:
return True
else:
return False
print(est_palindrome('kayak')) # True
print(est_palindrome('elle')) # True
print(est_palindrome('bonjour')) # False
Comparaison directe des caractères de la chaîne
On rappelle que pour adresser un caractère d'indice i dans une chaîne, on utilise la notation : chaine[i]
Or :
- le 1er caractère d'indice
0est le "symétrique" du dernier, d'indice- 1( oulen(chaine) - 1, c'est égal...) - le 2ème caractère d'indice
1est le "symétrique" de l'avant-dernier, d'indice- 2=- 1 - 1 - le 3ème caractère d'indice
2est le "symétrique" de l'avant-dernier, d'indice- 3=- 1 - 2 - ...
- le caractère d'indice i est donc le "symétrique" de celui d'indice
- 1 - i
il faut donc ici tester, si, pour chacun des caractères de la chaîne, l'égalité
chaine[i] == chaine[- 1 - i] est vérifiée ou pas.
Ce qui impose donc, pour parcourir les caractères de la chaîne, de ne pas utiliser un parcours par valeur comme on le faisait jusqu'à présent ( for lettre in chaine ), mais un parcours par indice
utilisant une boucle for i in range() pour faire varier la valeur de i, de 0 ( 1er caractère ) jusqu'à len(chaine) - 1 ( dernier caractère ) :
def est_palindrome(chaine):
for i in range(len(chaine)): # pour i variant de 0 à len(chaine) - 1,
if chaine[i] != chaine[-1-i]: # si l'égalité n'est pas vérifiée,
return False # alors on sort "prématurément" de la fonction en renvoyant False
# sinon on continue la boucle en passant à l'indice suivant
return True # UNE FOIS que tous les caractères ont été parcourus ( et pas avant ! ), l'égalité a toujours été vérifiée, on renvoie donc True
print(est_palindrome('kayak')) # True
print(est_palindrome('elle')) # True
print(est_palindrome('bonjour')) # False
- il était plus simple ici de tester quand l'égalité n'est pas vérifiée, et dans ce cas de sortir prématurément de la fonction en renvoyant
False. - Ligne 9 : attention à l'indentation de l'instruction ! On ne doit renvoyer
Trueque si la boucle est terminée, il ne faut surtout pas mettre cette instruction DANS la boucle !
Encore une possibilité...
Au lieu d'utiliser une boucle for ... in range(...) pour faire varier i, on peut :
- utiliser deux variables, l'une initialisée à 0 ( = indice du premier caractère du mot ) et l'autre à
len(mot) - 1( = indice du dernier ) - faire varier ces deux variables dans une boucle
while, en incrémentant la première et en décrémentant la deuxième - la condition à évaluer dans la boucle est alors : tant que début est inférieure ou égale à fin.
def est_palindrome(chaine):
debut = 0
fin = len(chaine)-1
while debut <= fin:
if chaine[debut] != chaine[fin]:
return False
else:
debut +=1 # on incrémente 'debut'
fin -= fin # on décrémente 'fin'
return True
print(est_palindrome('kayak')) # True
print(est_palindrome('elle')) # True
print(est_palindrome('bonjour')) # False