Une tortue brownienne: Partie 1

Factorisation du code

En mathématiques lorsqu'une quantité apparaît plusieurs fois ainsi dans $x(x+1) -2(x+1)$, l'expression $x+1$ apparaît deux fois

On factorise $x+1$ et on obtient $x(x+1) -2(x+1) = (x+1)(x-2)$

De même dans un programme lorsqu'un groupe d'instructions apparaît plusieurs fois, comme dans le programme suivant (entouré en rouge), on va le mettre en commun en définissant une fonction

Puisque les instructions que l'on veut mettre en commun servent à calculer le milieu de deux points connaissant les coordonnées des deux points(x1,y1) et (x2,y2) il est naturel de nommer cette fonction milieu

 
 def milieu(x1,y1,x2,y2):
     return (x1+x2)/2,(y1+y2)/2

Cette fonction a en entrée quatre nombres, les coordonnées des points et retourne en sortie les coordonnées du milieu

En plus d'éviter les redondances dans un programme, les fonctions rendent un programme plus compréhensible

On obtient donc

Attention, il faut distinguer la définition d'une fonction, ce qu'elle fait, et l'exécution de la fonction

Pour visualiser cela recopier la fonction milieu dans PythonTutor pour vous aider à visualiser le processus

On pourrait factoriser encore le programme en utilisant un objet très utile en Python, les listes, mais ce sera pour un autre TP!

Exercice

  1. Copier la fonction milieu ci-dessus dans l'interpréteur Python puis faire deux fois entrée pour observer à nouveau le symbole >>>
  2. Exécuter la fonction sur l'exemple suivant en tapant print(milieu(1,2,3,4)) vous devez observez comme résultat dans l'interpréteur (2.0,3.0)

  3. Définir la fonction distance entre deux points dont on connaît les coordonnées (x1,y1) et (x2,y2) dans l'interpréteur, pour cela vous aurez besoin de la fonction racine carrée sqrt() de la bibliothèque math
  4. Tester cette fonction pour calculer la distance entre les points de coordonnée (3;-1) et (-1;2) vous devez obtenir 5.0

Déplacement aléatoire de la tortue

Nous allons simuler un mouvement aléatoire de la tortue ainsi

La tortue quitte l'origine (0,0) et tant qu'elle est à l'intérieur du disque de centre (0,0) et de rayon SEUIL fixé au départ elle avance au hasard toujours d'une même nombre de pixels PAS mais dans une direction aléatoire ainsi

  1. A chaque tour de boucle on tire au hasard un nombre i entre 0 et 35
  2. On multiplie i par 10, on obtient ainsi un nombre entier angle au hasard entre 0 et 350, par pas de 10
  3. On règle la direction de la tortue sur angle
Plus précisément en pseudo-code:
 
 
SEUIL <- 100
PAS   <- 5

Tant que  la tortue est à l'intérieur du disque de centre (0,0) et de rayon SEUIL
    i    <- tirer un nombre au hasard entre 0 et 35
    angle <- i*10
    régler la direction de la tortue sur angle
    avancer de PAS pixels         
 
 

Comment traduire "la tortue est à l'intérieur du disque de centre (0,0) et de rayon SEUIL" ?

On a vu en mathématiques une formule permettant de calculer la distance entre deux points repérés, donc une première traduction pourrait être

"la tortue est à l'intérieur du disque de centre (0,0) et de rayon SEUIL" -> "racine_carré(xT*xT + yT*yT) < SEUIL"

On peut économiser le calcul de la racine carrée en traduisant:

"la tortue est à l'intérieur du disque de centre (0,0) et de rayon SEUIL"

par "xT*xT + yT*yT < SEUIL*SEUIL"

d'où l'algorithme:
 
 
SEUIL <- 100
PAS   <- 5
xT    <- abscisse de la tortue
yT    <- ordonnée de la tortue
Tant que  xT*xT + yT*yT < SEUIL*SEUIL
    i    <- tirer un nombre au hasard entre 0 et 35
    angle <- i*10
    régler la direction de la tortue sur angle
    avancer de PAS pixels
    xT    <- abscisse de la tortue
	yT    <- ordonnée de la tortue         
 
 

que l'on traduit en python par

 
from turtle import *
from random import *

SEUIL = 100
PAS   = 10
xT    = xcor()
yT    = ycor()
while xT*xT + yT*yT < SEUIL*SEUIL:
    i      =  randint(0,35)
    angle  =  i*10
    setheading(angle)
    forward(PAS)
    xT    = xcor()
    yT    = ycor()
            
 
 

Modifier le programme :

  1. Cacher la tortue
  2. Mettre la vitesse au maximum
  3. Tracer le cercle limite en rouge, la trajectoire de la tortue reste noire
  4. Faire varier PAS

Pour PAS = 10

Pour PAS = 2

Notion de fonction

L'algorithme a perdu de sa lisibilité quand on a traduit "la tortue est à l'intérieur du disque de centre (0,0) et de rayon SEUIL" par "xT*xT + yT*yT < SEUIL*SEUIL"

Si quelqu'un lit l'algorithme il ne comprendra pas forcément à quoi sert xT*xT + yT*yT < SEUIL*SEUIL

De quoi a-t-on besoin ?On a juste besoin de savoir si la tortue est à l'intérieur ou à l'extérieur du disque, ce que l'on peut assimiler à un processus (ou fonction ) ayant en entrée les coordonnées de la tortue (xT,yT) et en sortie Vrai ou Faux

D'où le nouvel algorithme où on définit une fonction estDansLeDisque(rayon)

Le sujet de "est" est l'objet principal de notre algorithme, la tortue


fonction estDansLeDisque(x,y,rayon)
'''retourne vrai si le point de coordonnées (x,y) est dans le 
disque de centre (0,0) et de rayon rayon'''
	retourner x*x + y*y < rayon*rayon
	
SEUIL <- 100
PAS   <- 5
xT    <- abscisse de la tortue
yT    <- ordonnée de la tortue
Tant que  estDansLeDisque(xT,yT,SEUIL)
    i    <- tirer un nombre au hasard entre 0 et 35
    angle <- i*10
    régler la direction de la tortue sur angle
    avancer de PAS pixels
    xT    <- abscisse de la tortue
	yT    <- ordonnée de la tortue   

que l'on traduit en python par

 
from turtle import *
from random import *
#----------------------------------------------------------
def estDansLeDisque(x,y,rayon):
	'''retourne vrai si le point de coordonnées (x,y) est dans le 
	disque de centre (0,0) et de rayon rayon'''
	return x*x + y*y < rayon*rayon
#----------------------------------------------------------	
SEUIL = 100
PAS   = 10
xT    = xcor()
yT    = ycor()
while estDansLeDisque(xT,yT,SEUIL):
    i      =  randint(0,35)
    angle  =  i*10
    setheading(angle)
    forward(PAS)
    xT    = xcor()
    yT    = ycor()
            
 
 

On peut continuer et retrouver presque la lisibilité du premier algorithme en introduisant deux autres fonctions tracerCercleLimite(rayon) et reglerAleatoirementDirectionTortue()

 
 from turtle import *
from random import *
#----------------------------------------------------------
def tracerCercleLimite(rayon):
    goto(0,-rayon)
    pendown()
    pencolor("red")
    circle(rayon)
#----------------------------------------------------------
def estDansLeDisque(x,y,rayon):
    '''retourne vrai si le point de coordonnées (x,y) est dans le 
    disque de centre (0,0) et de rayon rayon'''
    return x*x + y*y < rayon*rayon
#----------------------------------------------------------
def reglerAleatoirementDirectionTortue():
    i      =  randint(0,35)
    angle  =  i*10
    setheading(angle)
#----------------------------------------------------------

    
SEUIL = 100
PAS   = 10

hideturtle()
speed(0)
penup()

tracerCercleLimite(SEUIL)

pencolor("black")
penup()

goto(0,0)
pendown()
xT    = xcor()
yT    = ycor()
while estDansLeDisque(xT,yT,SEUIL):
    reglerAleatoirementDirectionTortue()
    forward(PAS)
    xT    = xcor()
    yT    = ycor()
exitonclick()