Outils Conditions

Identification

Infoforall

11 - Conditions


Nous abordons aujourd'hui une autre notion très importante pour réaliser des choses intéressantes : les instructions conditionnelles.

En une question : comment réaliser des choses différentes en fonction de la situation ?

Evaluation ✎ : questions 08-14-16-18-19

1 - Booléens

Booléens

Pour comprendre les tests logiques, il faut savoir que les ordinateurs n'ont que deux choix possibles lorsqu'on leur donne une proposition à tester (du style "est-on en 2025 ?"). Il s'agit d'un booléen, d'après George Boole, fondateur de l'algèbre de Boole dans le milieu du 19ème siècle.

Un booléen ne peut valoir que True (pour VRAI) ou False (pour FAUX). Dans les faits, Python considère que 0 correspond à False et le reste à True.

  • Si nous étions en 2025, le résultat de "Sommes-nous en 2025 ?" donnerait True.
  • Sinon, le résultat donnerait False.

D'un point de vue informatique, cela donne :

>>> annee = 2025 >>> annee == 2025 True >>> annee != 2025 False >>> annee > 2025 False >>> annee >= 2025 True >>> annee < 2025 False >>> annee <= 2025 True

01° Utiliser ces instructions dans la console pour comprendre le principe de l'évaluation du booléen obtenu.

>>> a = 12 >>> b = 20 >>> b > a True >>> b < a False >>> b == a False >>> b != a True

On peut même stocker une évaluation dans une variable.

02° Trouver le contenu stocké dans les différentes variables c, d, e et f.

Après avoir obtenu vos réponses, vérifier à l'aide de la console.

>>> a = 12 >>> b = 20 >>> c = b > a >>> d = b < a >>> e = b == a >>> f = b != a

...CORRECTION...

>>> a = 12 >>> b = 20 >>> c = b > a >>> c True >>> d = b < a >>> d False >>> e = b == a >>> e False >>> f = b != a >>> f True

Nous allons pouvoir utiliser ces booléens pour réaliser des instructions conditionnelles : des instructions qui vont être réalisées uniquement si la condition est évaluée à VRAI.

2 - Instruction conditionnelle SI

Structure générale des instructions conditionnelles

Quelque soit le langage, on retrouve toujours une structure qui ressemble à ceci :

1 2 3 4 5 6 7 8 9 10 11
SI condition est vraie Instruction Instruction SINON SI autre condition est vraie Instruction Instruction SINON (dans tous les autres cas) Instruction Instruction

03° Tester la fonction suivante en lui fournisant diiférents paramètres entre 1980 et 2010 par exemple.

1 2 3 4 5 6 7 8 9 10
def creer_message(reponse): '''Renvoie un string en fonction de la réponse de l'utilisateur''' annee_creation_python = 1991 if reponse > annee_creation_python : message = f"Python a été créé avant {reponse}" elif reponse < annee_creation_python : message = f"Python a été créé après {reponse}" else : message = f"Oui, Python est sorti pour la première fois en {reponse}" return message
>>> creer_message(2000) ???

Questions :

  1. La fonction renvoie-t-elle systématiquement la même réponse pour par exemple 1980, 1991 et 2050 ?
  2. Ligne 4 : comment est évaluée l'expression reponse > annee_creation_python si le paramètre reponse contient 1987 ? Du coup, va-t-on exécuter la ligne 5 ?
  3. Ligne 6 : comment est évaluée l'expression reponse < annee_creation_python si le paramètre reponse contient 1987 ? Va-t-on exécuter la ligne 7 ?
  4. Avec quel mot-clé se code le SI en Python ?
  5. Avec quel mot-clé se code le SINON SI en Python ?
  6. Avec quel mot-clé se code le SINON en Python ?

...CORRECTION...

On constate bien que la fonction renvoie des réponses différentes en fonction de la valeur que reçoit la fonction en entrée :

>>> creer_message(2000) 'Python a été créé avant 2000' >>> creer_message(1980) 'Python a été créé après 1980' >>> creer_message(1991) 'Oui, Python est sorti pour la première fois en 1991'

L'expression reponse > annee_creation_python est évaluée progressivement de cette façon :

  • reponse > annee_creation_python
  • 1987 > annee_creation_python
  • 1987 > 1991
  • False

On n'exécute donc pas la ligne 5 de ce bloc.

L'expression reponse < annee_creation_python est évaluée progressivement de cette façon :

  • reponse < annee_creation_python
  • 1987 < annee_creation_python
  • 1987 < 1991
  • True

Du coup, on va exécuter la ligne 7 qui appartient à ce bloc.

Le SI se code avec le mot-clé if.

Le SINON SI se code avec le mot-clé elif.

Le SINON (tout court) se code avec le mot-clé else.

04° Que trouve-t-on à la fin de chacune des lignes contenant if, elif ou else ?

Comment sont positionnées les instructions conditionnelles par rapport aux mots-clés précédents ?

A quelle autre syntaxe cela vous fait-il penser ?

...CORRECTION...

On retrouve la structure d'une fonction.

On finit chaque condition par  : .

On tabule chaque instruction liée à une condition.

C'est l'indentation vers la droite qui permet à Python de comprendre les actions que vous voulez qu'il réalise si une condition est vérifiée. Il faut donc placer une tabulation ou 4 espaces de suite pour savoir qu’elles sont les instructions rattachées au bloc. De plus, on remarquera qu’on met un double point [ : ] après la condition de if, else if (elif en Python) ou else. Sans ce symbole, vous déclenchez une erreur. Ce double point permet de dire à l'interpréteur que la déclaration de la condition est finie.

Dans Thonny ou tout autre éditeur spécialisé dans Python, la tabulation est équivalente à 4 espaces. Attention par contre aux éditeurs multi-langages. La tabulation est parfois de 2 ou 3 espaces. Dans ce cas, votre code ne sera pas compris par l'interpréteur Python. Dans ce cas de figure, préférez les 4 espaces ou configurez votre éditeur pour forcer une tabulation équivalente à 4 espaces.

05° Utiliser l'animation ci-dessous en utilisant les trois paramètres qu'on demande à la fonction de traiter.

Question :

Que fait l'interpréteur à partir du moment où il valide l'une des conditions à évaluer ?

1 2 3 4 5 6 7 8 9 10
def creer_message(reponse): '''Renvoie un string en fonction de la réponse de l'utilisateur''' annee_creation_python = 1991 if reponse > annee_creation_python : message = f"Python a été créé avant {reponse}" elif reponse < annee_creation_python : message = f"Python a été créé après {reponse}" else : message = f"Oui, Python est sorti pour la première fois en {reponse}" return message

CLIQUEZ SUR UN BOUTON-REPONSE :

reponse :

annee_creation :

condition :

...CORRECTION...

L'interpréteur ne traitera que l'un des blocs.

Dès qu'il rencontre une condition valide, il exécute les instructions correspondantes puis quitte la structure conditionnelle SANS tester les possibilités restantes.

Déroulement d'une séquence if-elif-else

A SAVOIR IMPERATIVEMENT

L'interpréteur Python ne va exécuter que l'un des blocs d'une structure if-elif-else.

Python commence par évaluer la condition du premier bloc.

Si la condtion est vraie, il exécute les instructions 2-3-4 de ce bloc et ne regardera absolument pas les autres conditions et blocs. Il passera directement à la ligne Instruction 9.

Instruction 1 (avant les instructions conditionnelles)
if reponse > annee_creation_python : Instruction 2 Instruction 3 Instruction 4
elif reponse < annee_creation_python : Instruction 5 Instruction 6 Instruction 7
else : Instruction 8 Instruction 9
Instruction 10 (après les instructions conditionnelles)

Si la première condtion est fausse, il va évaluer la deuxième condition. Si elle est vraie, il exécute les instructions 5-6-7 de ce bloc et ne regardera absolument pas le dernier bloc. Il passera directement à la ligne Instruction 9.

Si aucune des conditions précédentes n'est vraie, il va sinon réaliser les instructions 8-9 du dernier bloc. Le ELSE est donc le bloc par défaut. Celui qu'on exécute si aucune des conditions précédentes n'a pas être validée.

Je répète : La chose à bien comprendre : l'interpréteur Python ne va exécuter que l'un des blocs. Il s'arrête au premier test correct et ne s'occupe pas des autres situés en dessous, même si les conditions sont vraies également.

06° Compléter la fonction appreciation ci-dessous. Elle doit renvoyer "Bien" si le paramètre note est supérieur à 13, "Insuffisant" si le paramètre est inférieur à 9 et "Moyen" sinon.

1 2 3 4 5 6 7 8
def appreciation(note): '''Renvoie un string correspondant à l'appréciation voulue :: param note(str) :: une note dans [0;20] :: return (str) :: l'appréciation correspondante ''' pass

...CORRECTION...

Version un seul endroit où on gère l'envoi de la réponse.

1 2 3 4 5 6 7 8 9 10 11 12 13 14
def appreciation(note): '''Renvoie un string correspondant à l'appréciation voulue :: param note(str) :: une note dans [0;20] :: return (str) :: l'appréciation correspondante ''' if note > 13 : app = "Bien" elif note < 9 : app = "Insuffisant" else : app = "Moyen" return app

07° Quelqu'un propose cette version 02 (elle est valide) permettant de répondre dès qu'on sait quoi répondre plutôt que de traiter les différents cas et d'envoyer la réponse à la fin.

1 2 3 4 5 6 7 8 9 10 11 12 13
def appreciation(note): '''Renvoie un string correspondant à l'appréciation voulue :: param note(str) :: une note dans [0;20] :: return (str) :: l'appréciation correspondante ''' if note > 13 : return "Bien" elif note < 9 : return "Insuffisant" else : return "Moyen"

Une autre personne pense qu'on peut encore faire plus rapide en supprimant le else final avec cette version 03 (elle est valide également).

1 2 3 4 5 6 7 8 9 10 11 12
def appreciation(note): '''Renvoie un string correspondant à l'appréciation voulue :: param note(str) :: une note dans [0;20] :: return (str) :: l'appréciation correspondante ''' if note > 13 : return "Bien" elif note < 9 : return "Insuffisant" return "Moyen"

Un enthousiaste pense du coup à modifier la première version est propose une version 04 (version fausse cette fois).

1 2 3 4 5 6 7 8 9 10 11 12 13
def appreciation(note): '''Renvoie un string correspondant à l'appréciation voulue :: param note(str) :: une note dans [0;20] :: return (str) :: l'appréciation correspondante ''' if note > 13 : app = "Bien" elif note < 9 : app = "Insuffisant" app = "Moyen" return app

Question

Expliquez pourquoi on peut se passer du else dans la version 3 mais pas dans la version 4.

...CORRECTION...

La version 03 fonctionne car dès qu'on rencontre un return, on répond et on sort de la fonction.

Si on atteint les lignes 9 ou 11, on quitte donc la fonction. Cela veut dire qu'on ne peut arriver à la ligne 12 que si la note n'est ni supérieure à 13, ni inférieure à 9.

Par contre, dans la version 04, il ne place pas de return. Cela veut dire que même si on rentre dans l'un des blocs if ou elif, on affectera la variable app mais on ne sortira pas de la fonction.

Du coup, on va simplement atterir ligne 12 à chaque fois et écraser la version précédente de notre variable !

Ici, le else est donc obligatoire.

✎ 08° Compléter la fonction traduction ci-dessous. Elle doit renvoyer "vert" si le paramètre color est "green", "rouge" pour "red", "bleu" pour "blue", "jaune" pour "yellow". Si la couleur est inconnue, elle doit répondre "Couleur non définie".

Remarque : nous verrons plus tard dans l'année un moyen plus efficace de traiter ceci que comme une succession de tests.

1 2 3 4 5 6 7 8 9
def traduction(color): '''Renvoie un string correspondant à la traduction de la couleur ANG -> FR :: param color(str) :: une couleur en anglais :: return (str) :: la traduction en français du string précédent ''' couleur = "Couleur non définie" return couleur

3 - Fonction booléenne

Nous avons déjà vu le test d'égalité. C'est à dire tester si une variable contient bien 5 par exemple.

Pour tester une égalité en Python, on n'utilise pas a = b qui donne un ordre d'affectation : l'ordinateur comprend dans ce cas qu'il faut stocker b dans la variable a.

Tester une égalité avec Python

Pour tester l'égalité, on utilise un double signe égal a == b. Cette instruction teste réellement si les deux variables sont égales.

Fonction boolèenne

C'est simplement une fonction qui renvoit un booléen.

True ou False en Python.

09° Compléter la fonction comparer pour qu'elle renvoie True si les deux paramètres sont égaux.

1 2 3
def comparer(proposition, mystere): '''Renvoie True si les deux paramètres sont égaux, False sinon''' pass

...CORRECTION...

Il est probable que vous avez tapé quelque chose qui ressemble à cela :

1 2 3 4 5 6
def comparer(proposition, mystere): '''Renvoie True si les deux paramètres sont égaux, False sinon''' if proposition == mystere : return True else : return False

Si vous avez mémorisé l'histoire du return qui provoque une sortie de la fonction, vous avez même surement tapé ceci :

1 2 3 4 5
def comparer(proposition, mystere): '''Renvoie True si les deux paramètres sont égaux, False sinon''' if proposition == mystere : return True return False

Et pourtant, il a eu encore une manière plus courte de répondre (les explications sont ci-dessous si vous ne comprennez pas bien comment ça fonctionne) :

1 2 3
def comparer(proposition, mystere): '''Renvoie True si les deux paramètres sont égaux, False sinon''' return proposition == mystere

Ce cas de figure est très courant en informatique : créer une fonction booléenne (une fonction qui renvoie True ou True) ne requiert donc pas d'utiliser un if la plupart du temps : il suffit de renvoyer l'expression qu'on veut évaluer.

Exemple avec une expression qui évalue si une note de 10 permet de valider un semestre :

>>> note = 9 >>> note >= 10 False >>> note = 12 >>> note >= 10 True

Du coup, la fonction donnerait simplement ceci :

1 2 3
def valider(note): '''Renvoie True si la note est supérieure ou égale à 10''' return note >= 10

10° Evaluer note >= 10 si le paramètre note vaut 7. Que va renvoyer la fonction valider ?

...CORRECTION...

note >= 10

7 >= 10

False

11° Un élève propose cette version : est-elle bonne, fausse, correcte mais inutilement longue ?

1 2 3 4 5 6
def valider(note): '''Renvoie True si la note est supérieure ou égale à 10''' if note >= 10 : return True else : return False

...CORRECTION...

Bonne mais inutilement longue.

Si vous préférez cette version pendant quelques temps, utilisez la. Vous aurez les points.

Mais dès que vous serez à l'aise, passez plutôt à la version courte.

4 - Inversion d'un booléen avec not

Nous allons voir comment utiliser ces fonctions booléennes de manière élégante.

Tester une évaluation sur VRAI

Globalement, si on veut faire des choses si cette fonction renvoie True, il suffit de faire ceci :

1 2 3 4
if comparer(choix, m): instruction1 instruction2 ...

Cela revient à réaliser si l'expression est évaluée à True. Nous aurions pu écrire ceci (mais c'est plus long)

1 2 3 4
if comparer(choix, m) == True : instruction1 instruction2 ...

Imaginons qu'on veuille tester si une moyenne est bien validée avec la fonction valider.

1 2 3
def valider(note): '''Renvoie True si la note est supérieure ou égale à 10''' return note >= 10

Il suffit de taper ceci :

Ok et élégant
if valider(15) :

Par défaut, Python évalue la condition et valide si la réponse est True. Mais comme ici nous obtenons directement un booléen, pas la peine d'en rajouter.

C'est comme si nous avions tapé ceci :

Ok mais bof bof
if valider(15) == True :
Tester une évaluation sur FAUX

Par contre, si on veut agir lorsque cette fonction renvoie False, on peut donc faire :

1 2 3 4
if comparer(choix, m) == False : instruction1 instruction2 ...

Et bien, on peut faire plus simple et plus clair en utilisant le mot-clé not : ce mot-clé inverse la valeur du booléen situé derrière lui.

>>> condition = False >>> condition False >>> not condition True

Du coup, on peut écrire plus proprement le fait d'agir si la fonction comparer renvoie False.

1 2 3 4
if not comparer(choix, m): instruction1 instruction2 ...

Imaginons qu'on veuille tester si une moyenne n'est pas validée avec la fonction valider.

Par défaut, Python évalue la condition et valide si la réponse est True. Comme la fonction renvoie un booléen, nous pourrions faire ceci :

Ok mais bof bof
if valider(15) == False :

Mais en fait, il suffit d'inverser la réponse de la fonction avec not

Ok et élégant
if not valider(15) :

12° Quelle va être l'instruction réalisée si comparer renvoie False.

1 2 3 4
if not comparer(choix, m): tache_1() else : tache_2()

...CORRECTION...

not comparer(choix, m)

not False

True

Comme la condition de la ligne 1 donne True, on effectue la fonction tache_1.

5 - ET / OU

Imaginons qu'on veuille créer une fonction est_valide qui vérifie qu'une note est bien comprise entre entre 0 et 20.

1 2 3 4 5 6 7 8 9 10 11 12
def est_valide(n): '''Fonction qui renvoie True si n est un entier dans [0;20] :: param n(int) :: un entier quelconque :: return (bool) :: True si n est dans [0;20], False sinon ''' if n > 20 : return False elif n < 0 : return False return True

13° Expliquer pourquoi la fonction est_valide ne renvoie pas systématiquement True alors qu'il s'agit de la dernière ligne de cette fonction.

...CORRECTION...

Tout simplement car on sort de la fonction dès qu'on rencontre un return.

Si l'un des deux tests précédents renvoie True, on va donc exécuter le return False et sortir de la fonction.

✎ 14° Un élève propose la fonction ci-dessous. Expliquer clairement pourquoi sa fonction n'est pas correcte alors qu'elle ne déclenche pas d'erreur et qu'elle renvoie bien True pour une note de 15 par exemple.

1 2 3 4 5 6 7 8 9 10 11 12
def est_valide(n): '''Fonction qui renvoie True si n est un entier dans [0;20] :: param n(int) :: un entier quelconque :: return (bool) :: True si n est dans [0;20], False sinon ''' if n <= 20 : return True elif n >= 0 : return True return False

Si vous ne trouvez pas, demandez-vous ce qu'elle renvoie pour une note de -15.

Pour obtenir un code plus lisible et concis, il existe un moyen d'associer la réponse de plusieurs tests logiques.

Voyons comment cela fonctionne.

15° Tapez les instructions ci-dessous dans le Shell.

>>> note = 15 >>> note >= 0 True >>> note < 0 False >>> note <=20 True >>> note > 20 False >>> note >= 0 and note <= 20 True >>> note = 25 >>> note >= 0 and note <= 20 False

Question : lorsque deux conditions sont reliées par un and, dans quel cas l'expression totale va-t-elle évaluée à True ?

...CORRECTION...

L'expression n'est évaluée à True qui si les deux conditions sont également évaluées à True. Il s'agit d'un ET logique.

Voici donc une manière plus simple de créer notre fonction est_valide. Cela ne change en rien son utilisation : pour l'utilisateur, le changement est totalement invisible.

1 2 3 4 5 6 7 8
def est_valide(n): '''Fonction qui renvoie True si n est un entier dans [0;20] :: param n(int) :: un entier quelconque :: return (bool) :: True si n est dans [0;20], False sinon ''' return n >= 0 and n <= 20

Une seule ligne, hors documentation. Pas mal non ?

✎ 16° Un élève propose la fonction ci-dessous. Expliquer clairement pourquoi vous pensez que sa fonction est correcte ou fausse (pensez à regarder les préconditions sur le paramètre n).

1 2 3 4 5 6 7 8
def est_valide(n): '''Fonction qui renvoie True si n est un entier dans [0;20] :: param n(int) :: un entier quelconque :: return (bool) :: True si n est dans [0;20], False sinon ''' return n > -1 and n < 21

Nous allons revoir en détail le ET dans d'autres activités. Voici simplement ce qu'on nomme la table de vérité d'un ET :

Valeur de a Valeur de b a ET b
VRAI VRAI VRAI
FAUX VRAI FAUX
VRAI FAUX FAUX
FAUX FAUX FAUX

Il existe également le OU

Un ET répond VRAI lorsque toutes les entrées sont VRAIES.

Le OU répond VRAI lorsqu'une des entrées au moins est VRAIE.

17° Compléter la table de vérité du OU :

Valeur de a Valeur de b a OU b
VRAI VRAI ?
FAUX VRAI ?
VRAI FAUX ?
FAUX FAUX ?

Cela revient à chercher cela avec Python :

a or b

...CORRECTION...

Valeur de a Valeur de b a OU b
VRAI VRAI VRAI
FAUX VRAI VRAI
VRAI FAUX VRAI
FAUX FAUX FAUX

✎ 18° QCM : On demande à quatre élèves de créer une fonction note_invalide. Elle doit renvoyer True si la note n n'est pas dans [0;20].

On vous fournit ci-dessous la réponse de leur fonction. Quel élève fournit la bonne façon de repondre ?

  • A : return n >= 0 or n <= 20
  • B : return n <= 0 or n >= 20
  • C : return n > 0 or n < 20
  • D : return n < 0 or n > 20

6 - Jeu, Hasard et Interface

Nous allons finir avec une petite application graphique Turtle qui permet de réaliser une animation : une balle rebondit sur les parois.

✎ 19° Mettre le programme en mémoire.

Activer en lançant la fonction lancer_animation dans la console. Cela vous permettra de voir l'animation réalisée pour l'instant.

>>> lancer_animation()

Analyse du code : Répondre aux questions suivantes :

  1. Sur quelle ligne définit-on que (sur cette application) les modifications sur les dessins ne seront pas automatiquement mises à jour à l'écran mais uniquement lorsqu'on en fait une demande d'update ?
  2. Sur quelle ligne donne-t-on la valeur en pixels du terrain de jeu ? On notera que si la valeur est 200, cela veut dire que les balles pourront évoluer en x (axe horizontal, abscisse) et en y (axe vertical, ordonnée) de -200 à +200.
  3. On crée alors les balles avec la fonction balle. A quoi sert la ligne 52 ?
  4. Combien de fois de suite va-t-on mettre les images en jour à l'aide d'une boucle ?
  5. Le principe de l'animation réalisée par la fonction deplacer_image est simple :

    1. Ligne 94 : on efface l'ancienne image qui avait été dessinée par le feutre
    2. Ligne 95 : on bouge le feutre à l'aide de la fonction bouger
    3. Ligne 96 : on dessine la nouvelle image

    L'ancienne image est donc remplacée par la nouvelle.

    Une fois qu'on a fait cela, il ne reste plus qu'à demander à l'application graphique d'afficher les modifications que nous venons de faire.

  6. Sur quelle ligne demande-t-on à l'application de faire cette mise à jour justement ?

...CORRECTION...

  1. LIGNE 33 : fenetre.tracer(0)
  2. LIGNE 101 : dim = 200
  3. La ligne 52 (et sa vitesse 0) permet d'afficher sans délai le dessin : on ne laisse pas l'utilisateur voir la "tortue" dessiner le cercle. Il apparaît point.
  4. Ligne 110 : on voit que la boucle va être réalisée 8000 fois. Après, c'est fini. Ca ne bougera plus.
  5. Ligne 115 : c'est sur cette dernière ligne de la boucle FOR qu'on demande à l'application de mettre à jour l'affichage.
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
'''Description des fonctions d'interface proposées --> Fonctions fournissant une réponse : + application_graphique(dim) : Créé et renvoie la référence d'une application Turtle + bordure(dim) : Crée et renvoie un objet-Turle ayant dessiné la bordure + balle(couleur, epaisseur, dim) : Crée et renvoie un objet-Turtle qui servira à tracer le cercle --> Fonctions sans réponse (modification de l'état par effet de bord) + deplacer(feutre, x, y, angle) : Déplace en (x,y) et réoriente en fonction de angle le feutre + effacer(feutre) : Efface le dessin réalisé avec ce feutre + dessiner(feutre) : Dessine un cercle avec le feutre + gerer_collision_mur(feutre) : Renvoi l'angle d'orientation après cas de contact avec une paroi verticale + gerer_collision_sol(feutre) : Renvoi l'angle d'orientation après cas de contact avec une paroi horizontale + bouger(feutre) : Gère le déplacement d'une des balles + deplacer_image(feutre) : Bouge le dessin associé à ce feutre + lancer_animation() : Crée l'application graphique, les balles et lance l'animation ''' # Partie Importation import turtle as trt import random as rd # Partie Fonctions d'interface def application_graphique(dim): '''Créé et renvoie la référence d'une application Turtle''' fenetre = trt.Screen() # création d'un objet-application fenetre.setup(dim*3,dim*3) fenetre.tracer(0) # NEW: affiche uniquement par update return fenetre def bordure(dim): '''Crée et renvoie un objet-Turle ayant dessiné la bordure''' feutre = trt.Turtle() # Création de l'objet-Turtle feutre.color('black') feutre.pensize(10) deplacer(feutre, -dim, -dim, 0) for etape in range(4): feutre.forward(2*dim) feutre.left(90) return feutre def balle(couleur, epaisseur, dim): '''Crée et renvoie un objet-Turtle qui servira à tracer le cercle''' feutre = trt.Turtle() feutre.color(couleur) feutre.pensize(epaisseur) feutre.speed(0) x0 = rd.randint(-dim,dim) y0 = rd.randint(-dim,dim) angle = rd.randint(0,359) deplacer(feutre, x0, y0, angle) feutre.hideturtle() # on n'affiche que les dessins, pas la tortue return feutre def deplacer(feutre, x, y, angle): '''Déplace en (x,y) et réoriente en fonction de angle le feutre''' feutre.penup() # On lève la pointe feutre.setpos(x, y) # On déplace le crayon feutre.setheading(angle) # On le tourne dans le bon sens feutre.pendown() # On abaisse la pointe def effacer(feutre): '''Efface le dessin réalisé avec ce feutre''' feutre.clear() def dessiner(feutre): '''Dessine un cercle avec le feutre''' feutre.circle(5, 360) def gerer_collision_mur(feutre): '''Renvoi l'angle d'orientation après cas de contact avec une paroi verticale''' angle = feutre.heading() angle = 180 - angle feutre.setheading(angle) def gerer_collision_sol(feutre): '''Renvoi l'angle d'orientation après cas de contact avec une paroi horizontale''' angle = feutre.heading() angle = -angle feutre.setheading(angle) def bouger(feutre): '''Gère le déplacement d'une des balles''' feutre.forward(0.1) def deplacer_image(feutre): '''Bouge le dessin associé à ce feutre''' effacer(feutre) # on efface le dessin précédent réalisé avec ce feutre bouger(feutre) # on déplace le feutre dessiner(feutre) # on réalise le dessin suivant def lancer_animation(): '''Crée l'application graphique, les balles et lance l'animation''' dim = 200 # De base, on veut un terrain de jeu de 200 x 200 app = application_graphique(dim) # création de l'application graphique b = bordure(dim) # création de la bordure s1 = balle('red', 3, dim) # création des balles s2 = balle('blue', 3, dim) s3 = balle('green', 3, dim) s4 = balle('magenta', 3, dim) s5 = balle('orange', 3, dim) for x in range(8000): # 8000 fois de suite deplacer_image(s1) # gère le déplacement de la balle 1 deplacer_image(s2) deplacer_image(s3) deplacer_image(s4) deplacer_image(s5) app.update() # NEW : on affiche le ou les dessins juste à ce moment

20° Compléter maintenant la fonction bouger ci-dessous. On remarquera notamment que j'ai changé la valeur du déplacement de façon à accélerer un peu les choses.

Pour l'instant, on ne gère que le contact avec le mur de droite. Vous pouvez tester. Ensuite, c'est à vous de parvenir à gèrer le mur de gauche (une paroi verticale), le sol et le plafond (deux parois horizontales).

N'oubliez pas d'activer l'animation !

>>> lancer_animation()

Voici la fonction à modifier et compléter.

1 2 3 4 5 6 7 8 9 10
def bouger(feutre): '''Gère le déplacement d'une des balles''' # Gestion de la coordonné x et des risques de collisions avec les murs x = feutre.xcor() if x > 200 : gerer_collision_mur(feutre) # Gestion de la coordonné y et des risques de collisions avec plafond / sol y = feutre.ycor() # Déplacement une fois que le feutre a été tourné dans une nouvelle direction feutre.forward(1)

...CORRECTION...

1 2 3 4 5 6 7 8 9 10 11 12
def bouger(feutre): '''Gère le déplacement d'une des balles''' # Gestion de la coordonné x et des risques de collisions avec les murs x = feutre.xcor() if x > 200 or x < -200 : gerer_collision_mur(feutre) # Gestion de la coordonné y et des risques de collisions avec plafond / sol y = feutre.ycor() if y > 200 or y < -200 : gerer_collision_sol(feutre) # Déplacement une fois que le feutre a été tourné dans une nouvelle direction feutre.forward(1)

7 - FAQ

Du coup, on peut tester le type des variables ?

Oui. Les deux manières de faire les plus courantes sont fournies ci-dessous :

Première méthode : tester le type de la variable.

>>> a = 5.0 >>> type(a) == float True >>> type(a) == int False >>> type(a) == str False >>> a = "5.0" >>> type(a) == float False >>> type(a) == int False >>> type(a) == str True

Deuxième façon de faire : utiliser la fonction native isinstance.

>>> a = 5 >>> isinstance(a, float) False >>> isinstance(a, int) True >>> isinstance(a, str) False

Les tests conditionnels, les boucles bornées FOR.

Il nous reste à associer ces deux notions et voir la boucle non bornée : la boucle TANT QUE que va réaliser le travail demandé TANT QUE la condition proposée est évaluée à VRAI.

Activité publiée le 01 11 2020
Dernière modification : 01 11 2020
Auteur : ows. h.