# Solutions du chapitre 3
# Activité 1
Cet exercice est relativement simple. Il suffit de reprendre l'exemple 4 de la
page 8 en utilisant une boucle repeat au lieu de faire du copier-coller pour
dessiner chaque côté du polygone.
On obtient alors
Pour faire un polygone à 15 côtés de longueur 30, c'est presque le même
programme en modifiant juste le nombre de répétitions et le paramètre du
forward:
Pour le dernier, c'est le même refrain
# Activité 2
# Partie A
# Partie B
Remarque
Vous pouvez remarquer que le dessin d'une étoile à 360 branches permet en fait
de colorier un disque plein. Pour que cela ressemble vraiment à un disque, il
faut augmenter un peu l'épaisseur du trait avec setPenColor(2). On peut aussi
peindre le disque en rouge avec setPenColor("red") et accélérer le dessin avec
hideTurtle():
Vous utiliserez cette technique pour réaliser une animation d'un système solaire à l'exercice 6, page 41, en fin de chapitre.
# Activité 3
On sait que la tortue doit tourner de à chaque sommet car elle fait deux tours complets sur elle-même pour dessiner toute l'étoile. Pour vous en convaincre, il vous suffit de dessiner l'étoile à la main. Elle doit donc tourner à chaque sommet de .
Pour que l'étoile soit bien orientée, il suffit de commencer par tourner de à droite pour partir à l'horizontale.
Remarque
Notez que la commande right(90) ne se trouve pas dans la commande
etoile_5_branches() car elle ne fait pas partie du dessin de l'étoile à
proprement parler. Elle a pour unique vocation d'orienter la tortue correctement
avant de commencer le dessin.
# Activité 4
Uniquement le corrigé du premier est donné. Vous remarquerez que l'on définit
deux commandes différentes, marche() et escalier() pour bien décomposer le
problème et rendre le programme plus clair.
Remarque
La commande setPos() est facultative et ne sert qu'à positionner la tortue
correctement avant d'effectuer le dessin pour que l'escalier soit visible en
entier dans la fenêtre de dessin.
# Activité 5
Le programme à modifier est le suivant:
Il ne suffit pas de diminuer le nombre de répétitions de la boucle. Il faut encore que le programme dessine toujours le même cercle. Pour cela, il faut respecter les conditions suivantes:
Le périmètre doit être le même
L'angle total doit être le même
On obtient donc le programme suivant :
Remarque : performances
Vous remarquez que le programme est ainsi bien plus performant car il fait dix fois moins d'opérations. Il n'y a cependant presque aucune différence perceptible à l'écran.
# Activité 6
# Activité 7
Il suffit de modifier le nombre de répétitions et répéter 180 fois au lieu de 360.
# Activité 8
Pour cet exercice, reprenons le code de l'activité 5 qui est plus performant que celui de l'exemple 5. Il suffit de diviser par 4 le nombre de répétitions en ne changeant pas le reste.
Remarque
Au chapitre 4, nous verrons comment passer des paramètres aux fonctions pour éviter de devoir écrire 3 fois la même commande pour faire presque la même chose, ce qui simplifie beaucoup le programme.
# Activité 9
# Activité 10
On voit par contre que la fleur n'est pas vraiment orientée comme sur la consigne, avec le premier pétale bien à la verticale. Pour remédier à cela, il suffit de tourner le tortue un peu vers la gauche avant de commencer le dessin.
# Activité 11
Conseil d'apprentissage
Cet exercice peut se révéler plus périlleux qu'il n'y paraît. Le but n'est simplement de trouver une solution bancale en tâtonnant pendant des heures mais d'élaborer une stratégie réfléchie. Ce qui est attendu de vous à ce stade, c'est que vous ayez le réflexe de prendre une feuille de papier et un crayon et que vous élaboriez vos programmes et votre stratégie de manière réfléchie.
# Partie A
Ce problème n'est pas très difficile à décomposer intelligemment. Il s'agit clairement de définir d'abord une commande qui dessine un demi-cercle
On remarque cependant que cette commande demi_cercle() est assez lente. Pour
l'optimiser, il suffit de dessiner un demi-polygone avec moins de côtés :
qui ressemble encore tout autant à un cercle. Il suffit ensuite de répéter cette commande 8 fois pour dessiner la figure tout en veillant à replacer la tortue dans le bon sens pour qu'elle puisse dessiner le prochain motif (demi-cercle).
Attention
Les plus attentifs auront remarqué que la tortue ne dessine pas vraiment ce qui est demandé dans la consigne. On le voit mieux si l'on diminue encore le nombre et la taille des côtés.
La raison pour laquelle la tortue monte est assez subtile! Pour bien comprendre ce qui se passe, il faut encore diminuer le nombre de segments utilisés pour dessiner le demi-cercle et agrandir leur longueur.
Pour que le demi-cercle se dessine correctement, il faut en fait modifier la manière de dessiner le demi-cercle. Voyez-vous comment le faire?
Il faut essentiellement répéter le motif
forward(20)
right(30)
forward(20)
2
3
au lieu de
forward(40)
right(30)
2
On obtient donc le code suivant pour dessiner le demi-cercle de manière symétrique :
En augmentant de nouveau le nombre de côtés, on obtient la forme désirée :
# Partie B
Il y a plusieurs manières intelligentes de dessiner cette figure. Il s'agit dans tous les cas d'identifier les motifs qui se répètent.
Le premier motif consiste à répéter trois carrés :
Remarque
Pour raccourcir le programme, on se permet de dessiner le carré de manière un peu spéciale, en répétant 6 fois au lieu de 4. Ceci permet de placer la tortue directement au sommet supérieur droit du carré.
La commande
setPos(x, y)permet de placer la tortue au pixel de coordonnées dans la fenêtre de dessin. Elle permet d'éviter de devoir écrire plein de commandes avecpenUp(),penDown()etc.On voit que la commande
carre()est une sortie de "sous-motif" de la commandemotif(). La logique pour répéter un motif est toujours la même :def dessine_figure(): repeat NOMBRE_DE_REPETITIONS: dessine_motif() repositionne_tortue()1
2
3
4
La même logique s'applique pour dessiner la figure en entier. Il suffit de faire
def figure():
repeat 2:
# répétition du motif
motif()
# repositionnement de la tortue pour
# dessiner le motif suivant
right(90)
back(50)
2
3
4
5
6
7
8
Cela donne au final le programme suivant :
# Variante
Il est également possible de dessiner le motif en escalier de la manière suivante:
En répétant deux fois cet escalier avec une rotation de entre les deux, on obtient à nouveau le motif présenté dans la première version:
Ce programme est même plus naturel que celui qui utilise le carré comme motif de
base pour réaliser la commande motif().
# Partie C
Il y a beaucoup de motifs que l'on peut répéter pour obtenir le dessin souhaité. Voici les plus évidents:
# Variante 1
La première variante consiste à répéter une rangée de trois carrés:
que l'on peut dessiner avec la commande
def motif():
repeat 3:
carre()
penUp()
right(90)
forward(2 * 50)
left(90)
penDown()
2
3
4
5
6
7
8
La figure entière s'obtient en répétant ce motif deux fois et en dessinant
encore un carré supplémentaire. Il faut bien évidemment repositionner la tortue
avec la commande deplacement() entre
# Variante 2
Une deuxième variante consiste à utiliser le motif suivant composé de deux carrés "décalés":
que se dessine avec la commande
def motif():
repeat 2:
# sous-motif
carre()
# repositionnement pour dessiner
# le motif suivant
penUp()
right(180)
forward(50)
penDown()
2
3
4
5
6
7
8
9
10
Voici un exemple de programme qui dessine la figure en entier:
Remarque générale
Vous pouvez constater que les programmes présentés sont bien structurés avec
différentes commandes. Pour les parties B et C, on a tout d'abord un sous-motif
carre() qui est répété un certain nombre de fois pour former un motif
motif(), également répété un certain nombre de fois pour réaliser la figure
dans son entier avec la commande figure().
Cette manière de structurer un programme en programmes et sous-programmes est l'essence même de la programmation modulaire et constitue une compétence fondamentale en programmation. Cela permet d'écrire des programmes plus courts, mieux structurés, plus facilement compréhensibles et comportant moins d'erreurs.
# Activité 12 (facultatif)
Aucun corrigé n'est disponible pour cette activité peu importante.
# Activité 13
Exercices 13-16
Les exercices 13 à 16 sont facultatifs dans le cadre de ce chapitre. Ils pourront être réalisés de manière bien plus efficace en définissant des commandes avec paramètres qui permettront de réaliser une seule commande permettant de colorier des rectangles de n'importe quelle dimension.
Nous dessinerons l'échiquier de l'exercice 16 de cette manière bien plus appropriée au chapitre 4. Pour le moment, vous pouvez donc sans problème ignorer les activités 13 à 16 et tout ce qui concerne le coloriage de carrés et de rectangles.
La raison pour laquelle la commande carre_plein() est
def carre_plein():
repeat 99:
ligne_epaisse()
2
3
et répète ainsi 99 fois ligne_epaisse() est que si l'on ne répète
ligne_epaisse() qu'une seule fois, on colorie déjà deux colonnes de pixels
comme le montre le programme suivant :
À chaque fois que la commande ligne_epaisse() est exécutée, une des deux
colonnes de pixels peinte recouvre en fait une autre colonne de pixels déjà
peinte précédemment. Donc si l'on appelle ligne_epaisse() deux fois de suite,
il y a trois colonne de pixels peintes. De ce fait, pour colorier colonnes,
il faut répéter fois la commande ligne_epaisse().
Discussion (facultatif : optimisation)
On pourrait évidemment proposer plusieurs optimisations pour réaliser le dessin de manière plus efficace.
Modifier la commande ligne_epaisse() pour ne pas repasser à chaque fois
sur chaque colonne de pixels. Pour cela, il suffirait de modifier la
commande de la manière suivante:
Le problème avec cette commande est qu'il n'est plus possible de colorier un
nombre impair de colonnes. En revanche, avec cette variante de la commande
ligne_epaisse(), il suffit de répéter fois la boucle repeat. Si l'on
veut colorier un nombre impair de colonnes, il suffit ensuite peindre
uniquement la dernière.
# Activité 14
La solution est donnée ici sans explication car cet exercice sera de toute
manière réalisé de manière plus efficace en utilisant les paramètres au
chapitre. Il faut modifier à la fois la commande ligne_epaisse() et le nombre
de répétitions
# Activité 15 (facultatif)
La solution n'est pas donnée car cet exercice est très similaire au précédent.
# Activité 16 (facultatif)
Conseil
L'exercice 16 est un projet de plus grande envergure qui vise à assembler tous les exercices précédents. Il faut procéder par étapes et identifier les différents motifs à répéter qui constituent un échiquier.
Le problème est facultatif car il sera traité de manière plus détaillée et plus efficace aux pages 53 à 55 du chapitre 4 sur les commandes avec paramètres.
# Activité 17, page 39 (facultatif)
Conseil
Le problème 17 est facultatif. Nous allons plutôt entraîner les animations dans les projets 6 et 7 à la page 41 du livre.
# Questions de compréhension, page 40
Le mot-clé
repeatpermet de répéter des bouts de programmes sans avoir à faire du copier-coller. Cela permet de respecter le principe DRY de l'informatique.DRY
En programmation, principe DRY = Don't Repeat Yoursel est fondamental. Il s'agit en quelque sorte du "premier commandement" de la programmation. Le code ci-dessous pour dessiner un hexagone n'est par exemple pas DRY car il s'obtient par copier-coller.
forward(50) right(60) forward(50) right(60) forward(50) right(60) forward(50) right(60) forward(50) right(60) forward(50) right(60)1
2
3
4
5
6
7
8
9
10
11
12Une manière DRY d'écrire le même code avec la boucle
repeatest la suivante:repeat 6: forward(50) right(60)1
2
3L'utilisation des boucles
repeatéconomise donc beaucoup de temps dans les situations suivantes:- Dessin de formes qui présentent des régularités (motifs récurrents)
- Dessin de polygones réguliers
- De manière générale, pour effectuer des actions répétitives
- Bien d'autres situations que nous traiterons plus tard, notamment la lecture de données depuis le capteur d'un robot ou d'une carte de développement Oxocard ou la gestion des événements (clavier, souris et autres).
Remarque
La boucle
repeatpermet uniquement de répéter un bout de code qui est toujours identique. Il exsite en Python encore deux autres types de boucles permettant de répéter des bouts de codes et qui s'utilisent dans des situations différents : la boucleforqui permet d'exécuter un programme pour chaque élément d'une liste et la bouclewhilequi permet de répéter un programme tant qu'une condition reste vraie.La syntaxe de la boucle
repeatest la suivante:repeat NOMBRE_DE_REPETITIONS: corps_de_la_boucle()1
2Le corps de la boucle est décalé par rapport au
repeatet indique ce qui doit être répété. Le corps de la boucle doit être décalé par rapport à l'en-tête de la boucle.Pour dessiner des animations, il faut dessiner et effacer successivement et un grand nombre de fois une forme qui se déplace légèrement d'une fois à l'autre. Sans les boucles, il faudrait recopier des centaines de lignes de code qui peuvent simplement être répétées avec la boucle
repeat. `Oui, il est tout-à-fait possible d'utiliser une boucle
repeatdans le corps d'une autre bouclerepeat. On parle dans ce cas de boucle imbriquée. L'exemple 7 à la page 36 montre un bon exemple de boucle imbriquée.Bien qu'il soit possible d'imbriquer les boucles les unes dans les autres, il vaut généralement la peine d'inclure la boucle imbriquée dans une commande qui lui est propre. Cette commande pourra ensuite être utilisée dans le corps de la boucle
repeatprincipale. Cela permet de rendre le programme plus compréhenisble.L'exemple 8 fait la même chose que l'exemple 7 mais il est bien plus compréhensible car la boucle interne est insérée dans la commande
quart_cercle()Non. Mathématiquement, on peut définir un cercle comme la limite lorsque (Prononcer "lorsque tend vers l'infini") d'un polygone régulier à côté. Dit plus simplement pour le commun des mortels, un cercle est un polygone régulier possédant "une infinité de côtés". Le problème est qu'il est absolument impossible de stocker une infinité de choses dans un ordinateur ni d'ailleurs de lui faire faire une infinité de choses. L'ordinateur peut donc au mieux dessiner de manière approximative un cercle par un polygone régulier à côtés.
Plus le nombre de côtés du polygone régulier est grand, plus il ressemblera à un cercle mais plus cela demandera de travail à l'ordinateur. Puisque l'oeil humain a des capacités finies également et que l'écran de l'ordinateur ne possède de toute manière qu'un nombre limité de pixels, on pourra généralement se contenter de dessiner un cercle par un polygone régulier de 36 côtés. Cela dépend toutefois du rayon du cercle. Plus le rayon du cercle est grand, plus le nombre de côtés nécessaire sera élevé pour que les côtés ne puissent pas être distingués à l'oeil.
# Exercice 1, page 41
Pour répondre à la question sans ordinateur il faut se munir d'une feuille de papier et d'un crayon en faisant attention aux éléments suivants:
Où se trouve la tortue avant et après l'exécution d'un bout de code (par exemple avant et après chaque répétition de la boucle
repeat 4)Il faut aussi faire bien attention à l'orientation de la tortue avant et après un dessin.
Commande setPos(x,y)
Comme l'indique la documentation de WebTigerJython, la commande setPos(x, y)
permet de positionner la tortue à une coordonnée absolue de la fenêtre de
dessin. Elle est utilisée ici pour que le dessin tienne dans la partie visible
de la fenêtre mais elle ne change rien au dessin.
# Exercice 2, page 41
La conception modulaire consiste à décomposer le problème en sous-problèmes plus
simples qu'il est ensuite facile d'assembler pour résoudre le problème dans son
ensemble. Dans notre cas, la boucle interne repeat 4: gagnerait à se trouver
dans une commande à part qui décrit ce que cette boucle fait. Elle dessine un
carré. Il vaut donc mieux la placer au sein d'une commande carre()
def carre30():
repeat 4:
forward(30)
right(90)
2
3
4
Cela donne au final le programme suivant bien plus compréhensible:
Note
La commande setPos(x, y) utilisée à la ligne 13 ne sert qu'à centrer l'image
dans le fenêtre de dessin pour que tout le dessin soit visible lorsque la
fenêtre est réduite.
# Exercice 3, page 41
L'exercice 3 n'est pas d'une importance capitale dans ce chapitre. Il mêle cependant deux manière de répéter du texte:
- Utiliser l'instruction
repeat - Utiliser l'opérateur
*qui "multiplie du texte par un nombre" en répétant le texte en question.
Fondamentalement, le programme est équivalent à
print 5 * "pomme "
print 5 * "pomme "
print 5 * "pomme "
print 2 * "pomme ", "ver ", 2 * "pomme "
print 5 * "pomme "
print 5 * "pomme "
2
3
4
5
6
Remarque
Pour bien effectuer cet exercice, il faut procéder petit-à-petit pour chacune des commandes.
La commande print 5 * "pomme " donne par exemple le résultat
pomme pomme pomme pomme pomme
et la commande print 2 * "pomme ", "ver ", 2 * "pomme " est équivalente à la
commade
print "pomme pomme ", "ver ", "pomme pomme "
qui donne la sortie
pomme pomme ver pomme pomme
Le programme dans son ensemble
donne donc la sortie
pomme pomme pomme pomme pomme
pomme pomme pomme pomme pomme
pomme pomme pomme pomme pomme
pomme pomme ver pomme pomme
pomme pomme pomme pomme pomme
pomme pomme pomme pomme pomme
2
3
4
5
6
# Exercice 4, page 41
Le motif de base à répéter dans cet exercice est assez évident. Il s'agit d'une "branche" du flocon de neige. Pour que l'on puisse facilement dessiner tout le flocon de neige en répétant la branche et en tournant de , il faut que la tortue débute et termine la branche au centre du flocon et dans la même orientation.
Remarque
Remarquez que la tortue débute et termine le dessin au même endroit, au centre
du flocon, à savoir en bas de la branche, en regardant dans la même direction.
Cela permet ensuite de simplement répéter plusieurs fois la commande branche()
depuis le centre du flocon en tournant simplement de entre chaque branche.
def branche():
forward(40)
left(45)
repeat 3:
forward(40)
back(40)
right(45)
left(90)
back(40)
2
3
4
5
6
7
8
9
Voici le programme en entier.
# Exercice 5, page 41
Comme pour l'activité 11, page 37, il faut utiliser le motif suivant pour dessiner un demi-cercle si l'on veut qu'il soit symétrique:
repeat NOMBRE_DE_SEGMENTS:
forward(LONGUEUR_SEGMENT / 2)
right(180 / NOMBRE_DE_SEGMENTS)
forward(LONGUEUR_SEGMENT / 2)
2
3
4
et non le motif
repeat NOMBRE_DE_SEGMENTS:
forward(LONGUEUR_SEGMENT)
right(180 / NOMBRE_DE_SEGMENTS)
2
3
qui ne donne pas un beau demi-cercle. Le programme complet est donc
Remarque
Nous verrons dans le prochain chapitre comment écrire un tel programme de
manière plus élégante et succincte en n'écrivant qu'une seule commande
arc_cercle(angle, perimetre) qui permet de dessiner tous les arcs de cercles
qui apparaissent dans ce problème.
# Exercice 6, page 41 (Projet)
Information
La solution du projet n'est pas donnée sur cette page. Il est important que vous fassiez votre maximum pour résoudre ce problème par vous-mêmes. Si vous avez l'occasion de travailler ce problème en classe, mettez-vous par deux pour le réaliser.
Une solution détaillée sera livrée ultérieurement dans la partie "Travaux pratiques et projets" du site.
# Exercice 7, page 41 (Projet)
Information
La solution du projet n'est pas donnée sur cette page. Il est important que vous fassiez votre maximum pour résoudre ce problème par vous-mêmes. Si vous avez l'occasion de travailler ce problème en classe, mettez-vous par deux pour le réaliser.
Une solution détaillée sera livrée ultérieurement dans la partie "Travaux pratiques et projets" du site.