La note ne valide pas seulement le résultat de votre programme, mais également son style :
y = x * 2 # y est le double de x
n'apporte rien),
Vérifiez ces points avant de demander à votre intervenant de valider votre code.
Vous aurez également besoin du fichier boulet.py.
Le but de ce TP est de revoir certains concepts vu au premier semestre en insistant sur la qualité du code écrit. Le code fourni suit des règles simples pour rendre le code le plus lisible possible :
#
de Python),
Après quelques exercices préliminaires, nous allons modéliser (et dessiner) la trajectoire d'un boulet de canon en fonction de l'angle de tir, de la vitesse initiale du boulet et de sa masse. Nous chercherons ensuite à ajuster automatiquement l'angle de tir pour essayer d'atteindre une cible précise.
Le principe de la recherche dichotomique (Wikipedia) est de chercher une solution d'un problème en coupant l'ensemble des solutions possible en deux parties égales à chaque étape. Au bout d'un moment, soit la solution est trouvée, soit l'ensemble devient vide et il n'y a pas de solution.
Par exemple, pour trouver un nombre entre 0 et 100 par questions oui/non successives, les stratégies suivantes ne sont pas très efficaces :
La strategie optimale est de séparer l'ensemble des nombre en 2 parties égales (ou presque) à chaque question. On peut poser par exemple :
Si on représente les questions sur un dessin, on a :
Avec cette stratégie, il ne faudra jamais plus de 7 questions pour arriver à trouver le nombre !
Le principe est le suivant : pour chercher un nombre entre a et b, on demande s'il est entre a et m, où m est la moyenne de a et b. Si la réponse est oui, on recommence à chercher entre a et m, et si la réponse est non, on recommence à chercher entre m+1 et b.
Dans tous les cas, on ne connait pas à l'avance le nombre de question à poser. La boucle "while
" est donc plus appropriée.
La procédure suivante implante la stratégie naïve qui teste tous les nombres jusqu'à tomber sur le nombre choisi par l'utilisateur :
def strategie_naive(): """implémentation de la stratégie naïve qui cherche un nombre entre et 100 choisi par l'utilisateur. """ print("Pense à un nombre entre 0 et 100 puis appuie sur 'Enter'...") input() trouve = False # variable qui passe à vrai quand on a trouvé le nombre nb_questions = 0 nb = 0 # nombre deviné : on va tester tous les entiers de 0 à 100 while not trouve: # on demande si le nombre est égal à nb : question = "Est-ce que ton nombre est égal à " + str(nb) + " ? [o/n] " reponse = "" while reponse not in ["o", "n"]: reponse = input(question) if reponse == "o": print("oui !") trouve = True # pour arrêter la boucle elif reponse == "n": print("non...") nb = nb + 1 # pour passer au nombre suivant nb_questions = nb_questions+1 print("Ton nombre est égal à", nb, "et il m'a fallu", nb_questions, "questions pour le trouver.")
strategie_naive()
,
Combien de questions sont nécessaires pour trouver un nombre entre 1 et 100 ? Entre 1 et 1000 ? Entre 1 et 10000 ?
La trajectoire d'un objet inerte est régie par les lois de la mécanique. Nous allons utiliser une approximation de ces lois pour modéliser de manière discrète la trajectoire d'un boulet de canon.
À un instant t donné, le boulet a
x
et y
,
vx
et vy
et il est soumis à la force d'attraction terrestre. Au temps t + dt
, la position et la vitesse du boulet sont modifiées en utilisant les valeurs précédentes :
x = x + vx * dt
,
y = y + vy * dt
,
vx = vx - A*vx*v*dt
où v
est la norme du vecteur vitesse (voir plus bas) et A
est le coefficient de frottement (voir plus bas),
vy = vy - (G + A*vy*v)*dt
, où G
est la constante gravitationnelle de la terre (9.81
), v
est la norme du vecteur vitesse (voir plus bas) et A
est le coefficient de frottement (voir plus bas).
v
est la norme du vecteur vitesse : v = sqrt(vx*vx + vy*vy)
. La fonction sqrt
est la fonction racine carrée de Python, qu'il faut avoir chargée avec une ligne
from math import sqrt
A
est le coefficient de frottement. Pour un boulet sphérique de 10cm de diamètre, dans de l'air à 15°, il vaut environ 0.003256 / masse
.
Attention : dans ces formules, la différence de temps dt
est exprimé en secondes.
Pour que la modélisation ressemble à la réalité physique, il faut que dt
soit assez petit.
Écrivez une fonction "trajectoire_boulet
" qui prend en argument les valeurs suivantes :
angle
: l'angle du canon, en degrés, par rapport à l'horizontal
masse
: la masse, en kilogramme, du boulet de canon (5kg est une valeur pertinente)
vitesse
: la vitesse, en mètre/s, du boulet à la sortie du canon (125 m/s est une valeur pertinente).
dt
: l'intervalle de temps pour les calculs successifs, en centièmes de secondes. Si cette valeur n'est pas fournie, votre fonction utilisera la valeur 1
par défaut.
freq
: la fréquence des affichages. En effet, si l'on dessine le boulet trop souvent, on ne pourra pas voir les positions successives du boulet. Une valeur de ce paramètre de 50 n'affichera donc qu'une position sur 50. Si cette valeur n'est pas donnée, votre fonction utilisera la valeur 10
par défaut.
La valeur de retour de la fonction est la distance parcourue par le boulet avant qu'il touche le sol. (Il s'agit donc de la dernière valeur de x
.)
Votre fonction devra afficher (en utilisant la procédure dessine_boulet(x,y)
) le boulet aux positions intermédiaires appropriées (argument freq
).
Vous devez écrire votre fonction dans le fichier à trous suivant : boulet.py.
from math import sin,cos,pi
"Run" -> "Run Module F5"
) et d'utiliser la petite interface.
Nous cherchons maintenant à atteindre une cible, avec une précision de 1 mètre. Pour ceci, il faudra tirer des boulets (avec la fonction trajectoire_boulet
) et modifier l'angle en fonction de la distance parcourue par le boulet : on commence par tirer un boulet à 45°, puis,
Écrivez la fonction dichotomie
, qui prend en argument :
cible
: la distance entre le canon et la cible, en mètres,
masse
, vitesse
, dt
et freq
avec la même interprétation que dans la question précédente.
Votre fonction appellera la fonction précédente trajectoire
pour calculer et afficher les trajectoires du boulet.
boulet.py
. Ça ne change rien, mais les tests sont plus interessants... (Le coefficient de frottement ne correspondra par contre plus vraiment à la réalité...)
(Bonus)
L'angle de 45° permet d'envoyer un boulet le plus loin possible seulement lorsque la résistance de l'air n'est pas prise en compte. Comme on utilise des formules qui modélisent la résistance de l'air, l'angle permettant d'obtenir une distance maximale est en fait plus petit que 45°, et il dépend des paramètres comme le poids ou la vitesse du boulet.
Écrivez une fonction
def distance_max(masse, vitesse, dt, freq): """Cette fonction doit calculer l'angle approprié pour envoyer un boulet le plus loin possible. - masse : masse du boulet de canon, - vitesse : vitesse initiale du boulet canon, en mètre / seconde - dt : intervalle de temps utilisé pour les calculs (en centièmes de secondes), - freq : fréquence des positions à afficher lors des appels à la fonction trajectoire_boulet. La fonction renvoie la valeur de l'angle trouvé... """
La méthode optimale pour une telle recherche est similaire à la recherche dichotomique, mais pour chercher le maximum entre a et b, on calcule
Il y a maintenant 3 cas :
On parle parfois de recherche ternaire.
(Note : le dernier cas peut en fait être ignoré : il suffit de remplacer "strictement plus petite" par "plus petite ou égale" dans le deuxième cas. Cela ne change pas vraiment le nombre d'opérations pour trouver le maximum.)