Exo Outils Fonctions

Identification

Infoforall

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 ou f, 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.