22 - Exos Outils & fonctions 3
Vous pouvez le rendre en markdown sur le site ou en version papier.
Attention, le soin est noté et les codes markdown identiques seront sanctionnés à moins de noter clairement que vous avez travaillé avec un autre élève de la classe.
1 - Boucle FOR et mathématiques
01° Analyser la fonction suivante et expliquer pas à pas pourquoi elle renvoie un résultat de 6.
1
2
3
4
5 | def question1():
nombre = 0
for x in range(4):
nombre = nombre + x
return nombre
|
On désire connaitre le nombre de cubes nécessaires pour réaliser une pyramide 2D de n étages.
Par exemple, pour une pyramide de n = 5
étages, il faudra 1+2+3+4+5, soit 15
jetons.
x
x x
x x x
x x x x
x x x x x
02° Compléter les lignes 9 et 12 de la fonction compter_jetons (voir sa documentation)
Elle devra ainsi renvoyer 15 pour 5 étages, 21 pour 6 étages ...
Consigne à respecter : il faudra utiliser la boucle FOR pour réaliser le calcul.
Il convient donc de réflechir à la meilleur façon de compléter les lignes 9 et 12.
La ligne 9 doit vous permettre de réflechir à comment définir la borne_maximum en fonction du nombre d'etages voulu.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 | def compter_jetons(etages):
"""Fonction qui renvoie le nombre de jetons nécessaires pour créer la pyramide 2D
::param etages (int) :: nombre d'étages, supérieur ou égal à 1
::return (int) :: nombre de jetons nécessaires à la construction
"""
nombre = 0
borne_maximum = ???
for x in range(borne_maximum):
nombre = nombre + x
return ???
print(compter_jetons(5))
print(compter_jetons(6))
|
03° Combien de fois va-t-on réaliser le calcul de la ligne 11 pour une pyramide de 100 étages ? pour 1 million d'étages ?
Rajouter la ligne suivante sous votre fonction. Noter le nombre de jetons obtenus.
print(compter_jetons(1000000))
04° Faire de même en utilisant la fonction ci-dessous. Combien de fois va-t-on réaliser le calcul de la ligne 8 ? Les mathématiques semblent-elles utiles à l'informatique ?
1
2
3
4
5
6
7
8
9
10
11 | def compter_jetons2(etages):
"""Fonction qui renvoie le nombre de jetons nécessaire pour créer la pyramide 2D
::param etages (int) :: nombre d'étages, supérieur ou égal à 1
::return (int) :: nombre de jetons nécessaires à la construction
"""
nombre = etages * (etages+1) // 2
return nombre
print(compter_jetons2(1000000))
|
Cette formule sera démontrée dans le cours de NSI car nous allons rencontrer la suite 1 + 2 + 3 + 4 ... très souvent.
2 - While et sciences physiques
On cherche ici à évaluer la vitesse de chute maximale d'un parachutiste sur Terre.
Cette partie ne nécessite aucune connaissance particulière en sciences physiques. Il s'agit simplement d'utiliser les résultats des fonctions.
Pour cela, on vous fournit deux fonctions
- poids vous renvoie le poids en fonction de la masse du parachutiste
- frott vous renvoie la valeur des forces de frottements de l'air sur le parachutiste.
05° Modifier les appels des lignes 22 et 23 pour connaitre (et noter sur votre copie) le poids d'un parachutiste de 90 kg et la force de frottement en cas de chute avec un coefficient de frottement de 0.13 et une vitesse de 5 mètres par seconde.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 | def poids(masse):
"""Renvoie la valeur du poids en considérant que l'objet est sur Terre
::param masse (int/float) :: La masse m exprimée en kg
::return (float) :: Le poids P exprimé en Newton
.. note :: On considère que g = 9.81 N.kg-1
"""
g = 9.8 # Intensité de la pesanteur terrestre
return masse * g
def frott(coeff, vit):
"""Renvoie la valeur de la force de frottements fluides
::param coeff (int/float :: Le coefficient de frottements (dépend de la géométrie de l'objet) et du fluide
::param vit (int/float) :: La vitesse de l'objet en m par s (m.s-1)
::return (int/float) :: La force de frottements en Newton
"""
return coeff * vit ** 2
p = poids(50) # poids pour un parachutiste de 50 kg
ff = frott(0.6, 2) # frottements pour un coef de 0.6 à 2 m.s-1
print(f"Poids : {p:.2f} N")
print(f"Force de frottements fluides : {ff:.2f} N")
|
Les caractères :.2f
dans le string servent juste à formater l'affichage : on ne veut que 2 chiffres après la virgule.
La vitesse maximale du parachutiste est atteinte lorsque la valeur du poids P est égale à la valeur des forces de frottements. Il faudrait donc faire une égalité entre deux floats ...
Comme on ne peut pas tester l'égalité de deux floats, nous allons utiliser une simple comparaison : le poids est toujours plus grand que les frottements, jusqu'à ce que les frottements augmentent et parviennent à atteindre le poids.
Nous allons donc utiliser un algorithme simple qui remplace l'égalité stricte pour une comparaison :
Algorithme de comparaison simpliste entre deux floats
- Etape 1 : On déclare une vitesse nulle (ligne 32)
- Etape 2 : On calcule le poids et les frottements (lignes 35 et 36).
- Etape 3 :
Tant que
le poids est supérieur aux frottements (ligne 39 à compléter) on fait ceci : - On calcule à nouveau le poids et les frottements (lignes 40 et 41)
- On augmente la vitesse de 0.1 (ligne 42)
- Etape 4 : On affiche la vitesse finale en m.s-1 et en km.h-1
06° Compléter la ligne 39 du programme ci-dessous pour qu'il suive l'étape 3 de l'algorithme proposé juste au dessus.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48 | # 1 - Déclaration des variables CONSTANTES globales
MASSE = 90 # Masse du parachutiste en kg
COEF = 0.13 # Coefficient de frottements du parachutiste dans l'air
# 2 - Déclaration des fonctions
def poids(masse):
"""Renvoie la valeur du poids P = mg en considérant que l'objet est sur Terre
::param masse (int/float) :: La masse m exprimée en kg
::return (float) :: Le poids P exprimé en Newton
.. note :: On considère que g = 9.81 N.kg-1
"""
g = 9.81 # Intensité de la pesanteur terrestre
return masse * g
def frott(coeff, vit):
"""Renvoie la valeur de la force de frottements fluides
::param coeff (int/float :: Le coefficient de frottements (dépend de la géométrie de l'objet) et du fluide
::param vit (int/float) :: La vitesse de l'objet en m par s (m.s-1)
::return (int/float) :: La force de frottements en Newton
"""
return coeff * vit ** 2
# 3 - Corps du programme
# ETAPE 1 - Vitesse de chute initiale du parachutiste
vit_chute = 0
# ETAPE 2
p = poids(MASSE)
ff = frott(COEF, vit_chute)
# ETAPE 3
while ??? :
p = poids(MASSE)
ff = frott(COEF, vit_chute)
vit_chute = vit_chute + 0.1
# ETAPE 4
print(f"La vitesse finale est {vit_chute:.2f} m.s-1 !")
print(f"La vitesse finale est {vit_chute*3.6:.2f} km.h-1 !")
print(f"Poids : {p:.2f} N")
print(f"Frottements : {ff:.2f} N")
|
Pour convertir une vitesse en m.s-1 en km.h-1, il suffit de la multiplier par 3,6.
07° Lancer le programme. Que vaut la vitesse maximale du parachutiste ?
08° Le parachutiste peut limiter cette vitesse en changeant sa position : il peut s'allonger face à l'air pour rencontrer plus de résistance possible. Son coefficient de frottement passe alors à environ 0.3
. Modifier la ligne 4. Que vaut la nouvelle vitesse ?
09° Après ouverture du parachute, on veut limiter la vitesse à 8 m.s-1, soit environ 30 km.h-1. Modifier manuellement le coefficient de frottement jusqu'à atteindre le coefficient que doit procurer la toile du parachute. Noter le résultat sur votre copie.
Comme vous le voyez, un simple programme de modélisation permet d'obtenir pas mal de valeurs exploitables.
3 - IF et Jeu
Nous allons utiliser les tests conditionnelles (if, elif et else) pour réaliser jeu interactif avec Turtle.
Il est hors de propos de réaliser un tel jeu dans le cadre d'un simple DM pour l'instant. Vous n'aurez qu'à réaliser le test final.
Le code peut paraître impressionnant mais vous n'aurez qu'à modifier une seule fonction : case_finale. Il s'agit de vous montrer le genre de prototype qu'il faudra réaliser en début de projet.
Les règles sont simples :
- Le joueur commence dans la case bleue et doit attendre la case rouge.
- Le joueur peut se diriger avec les 4 flèches du clavier
- Le joueur doit appuyer sur ENTREE pour valider son niveau une fois arrivé sur la case rouge.
- S'il est bien sur la sortie lorsqu'il appuie sur ENTREE, on lui donne un point et on relance un nouveau niveau.
- Sinon, on lui enlève un point.
- En appuyant sur la touche
F
ouf
, on quitte le jeu et on voit le nombre de points obtenus.
10° Utiliser le code ci-dessous pour vérifier que les touches précisées permettent bien de faire bouger le curseur sur le plateau. Survoler très rapidement le code et trouver dans la fonction activer_jeu
la ligne qui indique ce que le programme doit faire lorsqu'on appuie sur la flèche gauche (Left
en anglais).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206 | # 1 - Importation de modules
import turtle as trt
import random as rd
# 2 - Déclaration des variables globales
points = 0 # nombre de points du joueur
plateau = trt.Screen()
crayon = trt.Turtle()
taille_plateau = 500
nbr_cases = 10
largeur = taille_plateau // nbr_cases
# Contenu des cases : 0 pour case vide, 1 pour mur, 2 pour départ et 3 pour arrivée
laby = [
[1,1,1,1,1,1,1,1,1,1],
[1,0,0,0,0,0,0,0,0,1],
[1,1,1,0,0,0,0,0,0,1],
[1,0,0,0,0,1,1,0,1,1],
[1,0,1,0,0,1,1,0,1,1],
[1,0,1,0,0,1,1,0,1,1],
[1,0,1,0,0,1,1,0,1,1],
[1,0,0,0,0,0,0,0,0,1],
[1,0,0,0,1,1,1,0,0,1],
[1,1,1,1,1,1,1,1,1,1]]
# 3 - Déclaration des fonctions et procédures
def init_plateau():
"""Procédure permettant d'initialiser le plateau (couleur, position du départ et de fin ..."""
plateau.bgcolor("yellow")
plateau.setup(width=taille_plateau, height=taille_plateau, startx=50, starty=50)
plateau.setworldcoordinates(0,0, taille_plateau,taille_plateau)
for ligne in range(nbr_cases):
for colonne in range(nbr_cases):
if laby[ligne][colonne] != 1 :
laby[ligne][colonne] = 0
entree = False # Choix aléatoire de l'entrée
while entree == False :
ligne = rd.randint(1,nbr_cases-2)
colonne = rd.randint(1, nbr_cases-2)
if laby[ligne][colonne] == 0:
laby[ligne][colonne] = 2
entree = True
sortie = False # Choix aléatoire de la sortie
while sortie == False :
ligne = rd.randint(1,nbr_cases-2)
colonne = rd.randint(1, nbr_cases-2)
if laby[ligne][colonne] == 0:
laby[ligne][colonne] = 3
sortie = True
def init_crayon():
"""Procédure permettant d'initialiser le crayon"""
crayon.speed(0)
crayon.penup()
def carre(x,y,taille, couleur):
"""Procédure qui trace un carré de fond coloré couleur, de la bonne taille en partant de x,y
:: x (int) :: la coordonnée x du début du carré ; en pixels
:: y (int) :: la coordonnée y du début du carré ; en pixels
:: taille (int) :: la largeur du carré, en pixels
:: couleur (str) :: un string permettant de définir une couleur avec Turtle
"""
crayon.setposition(x,y)
crayon.setheading(0)
crayon.pendown()
crayon.fillcolor(couleur)
crayon.begin_fill()
for etape in range(4): # Création du carré
crayon.forward(taille)
crayon.right(90)
crayon.end_fill()
crayon.penup()
def creation_cases():
"""Fonction qui crée les cases et renvoie les coordonnées de la case initiale
::return (tuple) :: les deux coordonnées x et y du centre de la case initiale (en pixels)
"""
xo = 0
yo = 0
for ligne in range(nbr_cases):
for colonne in range(nbr_cases):
if laby[ligne][colonne] == 1 :
couleur = 'grey'
elif laby[ligne][colonne] == 0 :
couleur = 'white'
elif laby[ligne][colonne] == 2 :
couleur = "blue"
xo = largeur // 2 + largeur * colonne
yo = taille_plateau - largeur // 2 - largeur * ligne
else :
couleur = "red"
xd = colonne * largeur
yd = taille_plateau - ligne*largeur
carre(xd, yd, largeur, couleur)
return (xo, yo)
def pas_de_mur():
"""Fonction qui teste la position du crayon et renvoie True si le crayon a le droit d'être à sa position actuelle
::return (bool) :: True si la position est autorisée, False si le crayon est dans un mur (case contient 1)
"""
x_px, y_px = crayon.position()
colonne = recupC(x_px)
ligne = recupL(y_px)
case = laby[ligne][colonne]
if case == 1 :
return False
else :
return True
def dans_le_mur():
"""Fonction qui renvoie True si le crayon est actuellement positionné dans un mur
::return (bool) :: Renvoie True si le crayon est dans un mur (case contient 1), False sinon
"""
return not(pas_de_mur())
def avance():
"""Procédure qui fait avancer le crayon de 2 pixels et qui le fera ensuite reculer si la destination n'est pas autorisée"""
crayon.pendown()
if pas_de_mur(): # si le crayon n'est pas initialement dans un mur, on autorise le déplacement
crayon.forward(2)
if dans_le_mur(): # si le crayon est maintenant dans un mur, on le refait reculer
crayon.forward(-2)
crayon.penup()
def recule():
"""Procédure qui fait reculer le crayon de 2 pixels et qui le fera ensuite reculer si la destination n'est pas autorisée"""
crayon.pendown()
if pas_de_mur(): # si le crayon n'est pas initialement dans un mur, on autorise le déplacement
crayon.forward(-2)
if dans_le_mur(): # si le crayon est maintenant dans un mur, on le refait avancer
crayon.forward(2)
crayon.penup()
def tourne_g():
"""Procédure qui fait tourner le crayon vers la gauche de 45°"""
crayon.pendown()
crayon.left(45)
crayon.penup()
def tourne_d():
"""Procédure qui fait tourner le crayon vers la droite de 45°"""
crayon.pendown()
crayon.right(45)
crayon.penup()
def recupC(x_pix):
numero_colonne = int(x_pix // largeur)
return numero_colonne
def recupL(y_pix):
numero_ligne = int(nbr_cases - 1 - y_pix // largeur)
return numero_ligne
def fin_jeu():
print(f"FIN DU JEU. Vous avez {points} points")
def activer_jeu():
xo, yo = creation_cases()
crayon.fillcolor("black")
crayon.setposition(xo,yo)
plateau.onkeypress(avance, 'Up') # Evénement Flèche Up relié au lancement de avance
plateau.onkeypress(recule, "Down")
plateau.onkeypress(tourne_g, "Left")
plateau.onkeypress(tourne_d, "Right")
plateau.onkeypress(fin_niveau, "Return")
plateau.onkeypress(fin_jeu, 'f')
plateau.onkeypress(fin_jeu,'F')
plateau.listen() # Surveillance des événements sur plateau
def creer_jeu():
init_plateau()
init_crayon()
activer_jeu()
def case_finale():
"""Fonction qui teste la position du crayon et renvoie True si le crayon est dans la case finale
::return (bool) :: True si le crayon est à l'arrivée (case contient 3), False sinone contient 3)
"""
x_px, y_px = crayon.position()
colonne = recupC(x_px)
ligne = recupL(y_px)
case = laby[ligne][colonne] # La case contient 0, 1, 2 ou 3
return False
def fin_niveau():
"""Procedure qui teste la position du crayon et relance un labyrinthe si le crayon est sur la case de sortie
Si le crayon est bien sur la case de sortie, on gagne un point.
Si le crayon n'est pas sur la case de sortie, on perd un point.
"""
global points
if case_finale() == True :
points = points + 1
crayon.clear()
creer_jeu()
else :
points = points - 1
# 4 - Programme principal
creer_jeu()
|
11° Modifier la fonction case_finale pour qu'elle fonctionne réellement. Voir l'attendu dans la documentation de la fonction. En l'état actuel, elle renvoie toujours False
. Rajoutez un if de façon à gérer la réponse en fonction du contenu de la case.
- Si la case contient 3 : True
- Sinon : False
Activité publiée le 13 09 2020
Dernière modification : 15 09 2020
Auteur : ows. h.