10. Éviter absolument les répétitions

Préparez-vous : cette leçon est plutôt longue. Nous allons voir comment définir de nouvelles commandes de robot. Nous verrons aussi une troisième règle utile pour l'écriture de programmes :

Règle N°3
Quand vous écrivez des programmes, ne vous répétez pas.
Je répète : Ne vous répétez pas !

Trois gauches peuvent faire une droite

Si vous y réfléchissez attentivement, vous pourrez trouver que faire faire à Reeborg trois rotations à gauche à la suite donne le même résultat que s'il faisait une seule rotation à droite. Essayez de comprendre, en dessinant sur une feuille de papier, ce que le programme suivant ferait faire à Reeborg. sans utiliser votre ordinateur :

turn_left()
move()
turn_left()
turn_left()
turn_left()
move()
move()
turn_left()
turn_left()
turn_left()
move()
turn_left()
turn_left()
turn_left()
move()
move()
turn_left()
turn_left()
turn_off()

À votre tour

Écrivez et enregistrez le programme ci-dessus, et voyez si ce que Reeborg fait est ce à quoi vous vous attendiez.

Encore à vous !

Changez le programme que vous venez d'enregistrer pour qu'il fasse tourner Reeborg dans le sens des aiguilles d'une montre autour d'un carré comme dans l'image ci-dessous :

carré en tournant à droite


Définir ce qu'est la droite

Nous avons déjà vu comment Reeborg peut tourner à droite en combinant trois rotations à gauche à la suite. Si nous voulons faire une série de rotations à droite, il devient plutôt ennuyeux d'écrire et lire le code obtenu. C'est parce que nous nous répétons ; en d'autres mots, la même suite d'instructions apparaît à différents endroits dans le programme. Pour éviter de telles duplications, la possibilité de programmer Reeborg en Python est très utile.

En Python, on peut donner un nom simple à une série d'instructions. Par exemple, nous pouvons définir la commande qui permet de faire tourner à droite (en anglais turn right) Reeborg comme ceci :

définition de turn_right()

Au moins cinq points importants sont à noter :

Cela fait pas mal d'informations présentées en une fois. C'est probablement le bon moment pour vérifier si vous avez bien compris comment utiliser ce mot-clé.

À votre tour

Écrivez un programme qui 1) définit cette nouvelle commande pour tourner à droite et 2) l'utilise pour faire tracer à Reeborg un carré dans le sens des aiguilles d'une montre comme précédemment. Remarquez que le programme final est plus court que l'original et qu'il est plus facile de comprendre le chemin que suit Reeborg.

Encore à votre tour !

Définissez l'instruction pas_en_arriere() pour que le programme suivant :

# pas_en_arriere() défini ci-dessus
move()
pas_en_arriere()
turn_off()

fasse avancer Reeborg d'un pas en avant puis revenir à sa position de départ face à la même direction qu'au début, comme dans l'image suivante :

marche arrière

Conseil : Soyez sûr de ne pas oublier d'indenter les commandes qui font partie de votre nouvelle définition.

[NdT Attention : Comme pour les synonymes que nous avons vus dans une leçon précédente et comme pour les noms de variables que nous verrons par la suite, les noms de fonctions doivent utiliser l'alphabet anglais et donc ne peuvent pas contenir de lettres accentuées. C'est pourquoi le nom de la fonction pas_en_arriere()ne comporte pas d'accent (eh non ! ce n'était pas un oubli...).]

À votre tour, encore une fois !

Définissez l'instruction demi_tour() pour que les nouvelles commandes suivantes puissent fonctionner comme prévu :

def demi_tour():
demi_tour()
move()
demi_tour()

def turn_right():
demi_tour()
turn_left()

Livraison du journal, revisitée

Dans le chapitre précédent, un des derniers exercices que vous aviez à faire était d'écrire un programme pour que Reeborg livre un journal. Voici un rappel en image de ce que Reeborg devait faire :

newspaper start
lead to newspaper end

Votre solution à cet exercice ressemblait probablement à ceci :

move()
# monter une marche
turn_left()
move()
turn_left()
turn_left()
turn_left()
move()
move()
# monter une marche
turn_left()
move()
turn_left()
turn_left()
turn_left()
move()
move()
# monter une marche
turn_left()
move()
turn_left()
turn_left()
turn_left()
move()
move()
# monter une marche
turn_left()
move()
turn_left()
turn_left()
turn_left()
move()
move()
# poser le journal et faire demi-tour
put_beeper()
turn_left()
turn_left()
# descendre une marche
move()
move()
turn_left()
move()
turn_left()
turn_left()
turn_left()
# descendre une marche
move()
move()
turn_left()
move()
turn_left()
turn_left()
turn_left()
# descendre une marche
move()
move()
turn_left()
move()
turn_left()
turn_left()
turn_left()
# descendre une marche
move()
move()
turn_left()
move()
turn_left()
turn_left()
turn_left()
# avancer et s'arrêter
move()
turn_off()

C'est beaucoup de frappe au clavier... et il y a beaucoup de répétitions. Quand vous arriviez à la fin du programme, vous ne pouviez plus voir son début à l'écran. Vous avez peut-être remarqué que j'ai ajouté quelques commentaires qui m'ont aidé à repérer où je suis dans le travail à faire. Ces commentaires sont plus proches de ce qu'on pense quand on pose le plan d'une solution :

Essayons d'écrire ce plan d'une forme Pythonique :
 
monter_quatre_marches()
put_beeper()
demi_tour()
descendre_quatre_marches()

Ce n'est pas une solution tout à fait complète [par exemple, il manque une instruction  turn_off()], mais cela en est assez proche et c'est beaucoup plus facile à lire que ce que nous avions avant, en supposant que ces nouvelles instructions soient définies. Voici quelques unes des définitions dont on a besoin :

def demi_tour():
turn_left()
turn_left()

def turn_right():
turn_left()
turn_left()
turn_left()

def monter_une_marche():
turn_left()
move()
turn_right()
move()
move()

def monter_quatre_marches():
monter_une_marche()
monter_une_marche()
monter_une_marche()
monter_une_marche()

À votre tour

Ajoutez les définitions manquantes pour que le programme final ressemble à ce que j'ai appelé la version Pythonique. Vous aurez besoin d'ajouter quelques instructions simples en plus, dont un turn_off() à la fin. Rappelez-vous d'enregistrer votre programme en utilisant un nom différent de celui de votre solution d'origine.

Encore à votre tour !

Prenez le temps de comparer votre solution d'origine au programme de livraison de journal ainsi qu'à ce dernier programme. Lequel est le plus facile à lire ?


Exercice de lecture

Des noms bien choisis peuvent vraiment aider à comprendre ce que fait un programme. De même, des noms mal choisis peuvent le rendre vraiment difficile à comprendre [Voir la Règle N°4]. Essayez de comprendre le sens du programme suivant sans utiliser l'ordinateur pour l'exécuter.

def a():
turn_left()
turn_left()

def b():
turn_left()
a()

def c():
move()
move()

def d():
c()
b()

def e():
d()
d()
d()
d()

turn_left()
e()
b()
turn_off()

Vous pourrez trouver utile de donner des noms plus significatifs aux commandes a(), b(), c(), d() et e().

précédent Construction des murs - début - Éviter les répétitions, encore une fois ! suivant