408 lines
11 KiB
Python
408 lines
11 KiB
Python
|
# PREUD'HOMME BONTOUX Geoffrey - PeiP 12 - 2014/2015
|
|||
|
# TP n°8 donné le 14/11/2014 - Dessiner avec la tortue ep02
|
|||
|
# http://www.fil.univ-lille1.fr/~allegraud/info_l1s1/tp_chaines_et_listes.html
|
|||
|
|
|||
|
from turtle import *
|
|||
|
import doctest
|
|||
|
|
|||
|
# Réalisez une procédure nommée dessine
|
|||
|
|
|||
|
|
|||
|
def dessine(ordres, l, α):
|
|||
|
"""
|
|||
|
Trace sur turtle la séquence d'ordre donnée, avec la longueur l et l'angle α
|
|||
|
donné.
|
|||
|
|
|||
|
CU : ordres str, l numérique, α numérique → ∅
|
|||
|
"""
|
|||
|
assert(type(ordres) is str), "ordres doit être du type str"
|
|||
|
assert(type(l) is float or type(l) is int), "l doit être numérique"
|
|||
|
assert(type(α) is float or type(α) is int), "α doit être numérique"
|
|||
|
|
|||
|
for i in ordres:
|
|||
|
if i == 'F' or i == 'G':
|
|||
|
forward(l)
|
|||
|
elif i == '+':
|
|||
|
left(α)
|
|||
|
elif i == '-':
|
|||
|
right(α)
|
|||
|
else:
|
|||
|
assert (False), "ordres doit être composé des caractères 'F', 'G', '+' \
|
|||
|
ou '-'"
|
|||
|
|
|||
|
# Testez votre procédure sur l’exemple précédent.
|
|||
|
|
|||
|
# dessine('F--F--F', 100, 60)
|
|||
|
|
|||
|
# Tracez chacune des figures ci-dessous :
|
|||
|
|
|||
|
# un carré
|
|||
|
|
|||
|
# dessine('F-F-F-F', 100, 90)
|
|||
|
|
|||
|
# un hexagone régulier
|
|||
|
|
|||
|
# dessine('F-F-F-F-F-F', 100, 360/6)
|
|||
|
|
|||
|
# (facultatif) une maison
|
|||
|
|
|||
|
# Version compressée
|
|||
|
|
|||
|
# reset()
|
|||
|
# dessine('FFF+++FF+++F+++FF+++FFF+++FFFFF+FFFFF++++FFFFF++++FFFFF++++++FFFFF+++FFFFF', 10, 30)
|
|||
|
|
|||
|
# Version expliquée
|
|||
|
|
|||
|
# L = 10 # On choisi une longueur sufisament petite pour les détails
|
|||
|
# ANGLE_DEG = 30 # On a besoin d'angles de 90° (pour les murs) et de 60° (pour
|
|||
|
# # le triangle équilatéral qui sert de toit), on prend donc le PGCD des deux
|
|||
|
# MUR = 5
|
|||
|
# ANGLE_DROIT = 90 // ANGLE_DEG
|
|||
|
# ANGLE_TRIANGLE_DEG = 180 // 3
|
|||
|
# ROTATION_TRIANGLE_DEG = 180 - ANGLE_TRIANGLE_DEG
|
|||
|
# ROTATION_TRIANGLE = ROTATION_TRIANGLE_DEG // ANGLE_DEG
|
|||
|
# DEMITOUR = 180 // ANGLE_DEG
|
|||
|
# DECALAGE_PORTE_GAUCHE = MUR // 2
|
|||
|
# HAUTEUR_PORTE = 2
|
|||
|
# LARGEUR_PORTE = 1
|
|||
|
# DECALAGE_PORTE_DROITE = MUR - DECALAGE_PORTE_GAUCHE
|
|||
|
|
|||
|
# reset()
|
|||
|
# dessine(# Mur du bas et porte
|
|||
|
# 'F' * (DECALAGE_PORTE_GAUCHE + LARGEUR_PORTE)
|
|||
|
# + '+' * ANGLE_DROIT
|
|||
|
# + 'F' * HAUTEUR_PORTE
|
|||
|
# + '+' * ANGLE_DROIT
|
|||
|
# + 'F' * LARGEUR_PORTE
|
|||
|
# + '+' * ANGLE_DROIT
|
|||
|
# + 'F' * HAUTEUR_PORTE
|
|||
|
# + '+' * ANGLE_DROIT
|
|||
|
# + 'F' * DECALAGE_PORTE_DROITE
|
|||
|
# # Mur de droite
|
|||
|
# + '+' * ANGLE_DROIT
|
|||
|
# + 'F' * MUR
|
|||
|
# # Toit
|
|||
|
# + '-' * ANGLE_DROIT
|
|||
|
# + '+' * ROTATION_TRIANGLE
|
|||
|
# + 'F' * MUR
|
|||
|
# + '+' * ROTATION_TRIANGLE
|
|||
|
# + 'F' * MUR
|
|||
|
# + '+' * ROTATION_TRIANGLE
|
|||
|
# + 'F' * MUR
|
|||
|
# + '+' * DEMITOUR
|
|||
|
# + 'F' * MUR
|
|||
|
# + '+' * ANGLE_DROIT
|
|||
|
# + 'F' * MUR, L, ANGLE_DEG)
|
|||
|
|
|||
|
# (facultatif) un mouton
|
|||
|
|
|||
|
# Version compressée
|
|||
|
|
|||
|
# reset()
|
|||
|
# dessine('FFFFFFF+++FFF+++FFFFFFF+++FFF+++FFFFFFF+FFF++FFF++++FFF++++++FFF+++++FFFFFFF+FFF', 20, 30)
|
|||
|
|
|||
|
# Version expliquée
|
|||
|
|
|||
|
# L = 20
|
|||
|
# ANGLE_DEG = 30
|
|||
|
# LARGEUR = 7
|
|||
|
# LONGUEUR = 3
|
|||
|
# PROFONDEUR = 3
|
|||
|
# ANGLE_DROIT = 90 // ANGLE_DEG
|
|||
|
# ANGLE_PERSPECTIVE = 1
|
|||
|
# DEMITOUR = 180 // ANGLE_DEG
|
|||
|
#
|
|||
|
# print(# Face avant
|
|||
|
# 'F' * LARGEUR
|
|||
|
# + '+' * ANGLE_DROIT
|
|||
|
# + 'F' * LONGUEUR
|
|||
|
# + '+' * ANGLE_DROIT
|
|||
|
# + 'F' * LARGEUR
|
|||
|
# + '+' * ANGLE_DROIT
|
|||
|
# + 'F' * LONGUEUR
|
|||
|
# + '+' * ANGLE_DROIT
|
|||
|
# # Arète oblique en bas
|
|||
|
# + 'F' * LARGEUR
|
|||
|
# + '+' * ANGLE_PERSPECTIVE
|
|||
|
# + 'F' * PROFONDEUR
|
|||
|
# # Arète verticale à droite
|
|||
|
# + '+' * (ANGLE_DROIT - ANGLE_PERSPECTIVE)
|
|||
|
# + 'F' * LONGUEUR
|
|||
|
# # Arète oblique au milieu
|
|||
|
# + '+' * (ANGLE_DROIT + ANGLE_PERSPECTIVE)
|
|||
|
# + 'F' * PROFONDEUR
|
|||
|
# + '+' * DEMITOUR
|
|||
|
# + 'F' * PROFONDEUR
|
|||
|
# # Arète horizontale en haut
|
|||
|
# + '+' * (DEMITOUR - ANGLE_PERSPECTIVE)
|
|||
|
# + 'F' * LARGEUR
|
|||
|
# # Arète oblique à gauche
|
|||
|
# + '+' * ANGLE_PERSPECTIVE
|
|||
|
# + 'F' * PROFONDEUR
|
|||
|
# , L, ANGLE_DEG)
|
|||
|
|
|||
|
|
|||
|
# « Ça c'est la caisse. Le mouton que tu veux est dedans. »
|
|||
|
# - Antoine de Saint Exupery
|
|||
|
|
|||
|
# Dériver un ordre par rapport à une variable
|
|||
|
|
|||
|
# Soit une chaîne so et une autre chaîne r. On appelle la dérivation de so
|
|||
|
# par r par rapport à 'F' la chaîne obtenue en remplaçant chacune des
|
|||
|
# occurrences du caractère 'F' de so par tous les caractères de r.
|
|||
|
|
|||
|
# Par exemple, la dérivation de 'F+F' par 'F-F' est 'F-F+F-F'.
|
|||
|
|
|||
|
# Réalisez une fonction derive qui revoie la dérivation de la première chaîne passée en paramètre par la seconde par rapport à 'F'.
|
|||
|
# On définit la dérivée n-ième de so par r par rapport à 'F' comme le
|
|||
|
# terme un de la suite (un)n∈N définie par récurrence :
|
|||
|
|
|||
|
def derive(so, r):
|
|||
|
"""
|
|||
|
Revoie la dérivation de la première chaîne passée en paramètre par la
|
|||
|
seconde par rapport à 'F'.
|
|||
|
Remplace dans une chaîne donnée toutes les occurences d’un caracère donné
|
|||
|
par une autre chaîne de caractères.
|
|||
|
|
|||
|
CU : so str et r str → str
|
|||
|
|
|||
|
>>> derive('', '++')
|
|||
|
''
|
|||
|
>>> derive('F+F', 'F-F')
|
|||
|
'F-F+F-F'
|
|||
|
"""
|
|||
|
assert(type(so) is str), "so doit être du type str"
|
|||
|
assert(type(r) is str), "r doit être du type str"
|
|||
|
|
|||
|
retour = ''
|
|||
|
for i in so:
|
|||
|
if i == 'F':
|
|||
|
retour += r
|
|||
|
else:
|
|||
|
retour += i
|
|||
|
return retour
|
|||
|
|
|||
|
# Programmez une fonction derive_n
|
|||
|
|
|||
|
|
|||
|
def derive_n(so, r, n):
|
|||
|
"""
|
|||
|
Renvoie la dérivation n-ième de la première chaîne par la seconde par
|
|||
|
rapport à 'F'
|
|||
|
|
|||
|
CU : CU : so str et r str et n int → str
|
|||
|
|
|||
|
>>> derive_n('F+F', 'F-F', 3)
|
|||
|
'F-F-F-F-F-F-F-F+F-F-F-F-F-F-F-F'
|
|||
|
>>> derive_n('FFF', 'F+F+F', 0)
|
|||
|
'FFF'
|
|||
|
"""
|
|||
|
assert(type(n) is int), "n doit être du type int"
|
|||
|
# derive() s'occupe des autres assertions, inutile de vérifier so deux fois
|
|||
|
|
|||
|
retour = so
|
|||
|
for i in range(0, n):
|
|||
|
retour = derive(retour, r)
|
|||
|
return retour
|
|||
|
|
|||
|
|
|||
|
# Fractales
|
|||
|
|
|||
|
# N’hésitez pas à accélerer la tortue en utilisant la fonction speed du
|
|||
|
# module turtle.
|
|||
|
|
|||
|
speed(0)
|
|||
|
|
|||
|
# Merci.
|
|||
|
|
|||
|
# Tracez pour n compris entre 0 et 5, l=35−n et α=60 le résultat de la séquence
|
|||
|
# d’ordres obtenu en dérivant n fois 'F--F--F' par 'F+F--F+F'
|
|||
|
|
|||
|
# n = 3
|
|||
|
# l = 3 ** (5 - n)
|
|||
|
# α = 60
|
|||
|
# ordres = derive_n('F--F--F', 'F+F--F+F', n)
|
|||
|
# dessine(ordres, l, α)
|
|||
|
|
|||
|
|
|||
|
# Essayez maintenant de dériver plusieurs fois 'F' par 'F+F-F-F+F' avec un angle
|
|||
|
# de 90°.
|
|||
|
|
|||
|
# dessine(derive_n('F', 'F+F-F-F+F', 3), 5, 90)
|
|||
|
|
|||
|
|
|||
|
# Dérivation à plusieurs variables
|
|||
|
|
|||
|
# Écrivez une fonction cherche_regle
|
|||
|
|
|||
|
def cherche_regle(ordre, liste_vars, liste_regles):
|
|||
|
"""
|
|||
|
Renvoie ordre si ordre n’appartient pas à liste_vars ou liste_regles[i] si
|
|||
|
il existe un indice i vérifiant ordre == liste_vars[i].
|
|||
|
|
|||
|
CU : ordre str de taille 1, liste_vars une liste contenant exclusivement des
|
|||
|
types str, liste_regles une liste contenant exclusivement des types str de
|
|||
|
même taille que liste_vars → str
|
|||
|
|
|||
|
>>> cherche_regle('F', ['F', 'G'], ['F-F', 'G+G'])
|
|||
|
'F-F'
|
|||
|
>>> cherche_regle('A', ['F', 'G'], ['F-F', 'G+G'])
|
|||
|
'A'
|
|||
|
"""
|
|||
|
assert(type(ordre) is str and len(ordre) == 1), "ordre doit être du type \
|
|||
|
str et être de taille 1"
|
|||
|
assert(type(liste_vars) is list), "liste_vars doit être du type list"
|
|||
|
for i in liste_vars:
|
|||
|
assert(type(i) is str), "liste_vars doit contenir exclusivement des \
|
|||
|
types str"
|
|||
|
assert(type(liste_regles) is list), "liste_regles doit être du type list"
|
|||
|
for i in liste_regles:
|
|||
|
assert(type(i) is str), "liste_regles doit contenir exclusivement des \
|
|||
|
types str"
|
|||
|
assert(len(liste_vars) == len(liste_regles)), "liste_regles doit être de \
|
|||
|
même taille que liste_vars"
|
|||
|
|
|||
|
if (ordre in liste_vars):
|
|||
|
return liste_regles[liste_vars.index(ordre)]
|
|||
|
else:
|
|||
|
return ordre
|
|||
|
|
|||
|
# Écrivez une fonction derive_mult
|
|||
|
|
|||
|
|
|||
|
def derive_mult(so, liste_regles, liste_vars):
|
|||
|
"""
|
|||
|
Renvoie la dérivation de so par liste_regles par rapport à liste_vars.
|
|||
|
|
|||
|
CU : so str, liste_vars une liste contenant exclusivement des types str,
|
|||
|
liste_regles une liste contenant exclusivement des types str de même taille
|
|||
|
que liste_vars → str
|
|||
|
|
|||
|
>>> derive_mult('FGF', ['F', 'G'], ['GG', 'FFF'])
|
|||
|
'GGFFFGG'
|
|||
|
"""
|
|||
|
assert(type(so) is str), "so doit être de type str"
|
|||
|
# cherche_regle s'occupe des autres assertions
|
|||
|
|
|||
|
retour = ''
|
|||
|
for i in so:
|
|||
|
retour += cherche_regle(i, liste_regles, liste_vars)
|
|||
|
return retour
|
|||
|
|
|||
|
# Écrivez une fonction derive_mult_n
|
|||
|
|
|||
|
|
|||
|
def derive_mult_n(so, liste_regles, liste_vars, n):
|
|||
|
"""
|
|||
|
Renvoie la dérivée de la séquence d’ordres par la liste de règles par
|
|||
|
rapport à la liste des variables.
|
|||
|
|
|||
|
CU : so str, liste_vars une liste contenant exclusivement des types str,
|
|||
|
liste_regles une liste contenant exclusivement des types str de même taille
|
|||
|
que liste_vars, n int → str
|
|||
|
|
|||
|
>>> derive_mult_n('FGF', ['F', 'G'], ['GG', 'FFF'], 3)
|
|||
|
'GGGGGGGGGGGGFFFFFFFFFFFFFFFFFFGGGGGGGGGGGG'
|
|||
|
"""
|
|||
|
assert(type(n) is int), "n doit être du type int"
|
|||
|
# deriv_mult() s'occupe des autres assertions
|
|||
|
|
|||
|
retour = so
|
|||
|
for i in range(0, n):
|
|||
|
retour = derive_mult(retour, liste_regles, liste_vars)
|
|||
|
return retour
|
|||
|
|
|||
|
# Tracez pour n compris entre 0 et 6, l=27−n et α=90 le résultat de la séquence
|
|||
|
# d’ordres obtenu en dérivant 2n fois 'FX' par ['X+YF+', '-FX-Y'] par rapport
|
|||
|
# à ['X','Y'].
|
|||
|
|
|||
|
# n = 4
|
|||
|
# l = 2 ** (7 - n)
|
|||
|
# α = 90
|
|||
|
# ordres = derive_mult_n('FX', ['X', 'Y'], ['X+YF+', '-FX-Y'], 2 * n)
|
|||
|
# ordres = derive_mult(ordres, ['X', 'Y'], ['', '']) # Pour éviter les erreurs
|
|||
|
# # d'assertion
|
|||
|
# dessine(ordres, l, α)
|
|||
|
|
|||
|
|
|||
|
# Sauvegarde d’une position
|
|||
|
|
|||
|
# Écrivez une commande sauvegardant l’état de la tortue
|
|||
|
# dans une liste de 3 éléments.
|
|||
|
|
|||
|
etat = [0, 0, 0]
|
|||
|
|
|||
|
|
|||
|
def sauvegarder_etat():
|
|||
|
"""
|
|||
|
Sauvegarde l’état de la tortue dans la variable globale etat
|
|||
|
|
|||
|
CU : ∅ → ∅
|
|||
|
"""
|
|||
|
|
|||
|
global etat
|
|||
|
etat[0] = xcor()
|
|||
|
etat[1] = ycor()
|
|||
|
etat[2] = heading()
|
|||
|
|
|||
|
# Écrivez une commande permettant de restaurer un état contenu
|
|||
|
# dans une liste à 3 éléments.
|
|||
|
|
|||
|
|
|||
|
def restaurer_etat():
|
|||
|
"""
|
|||
|
Restaure l’état de la tortue depuis la variable globale etat
|
|||
|
|
|||
|
CU : ∅ → ∅
|
|||
|
"""
|
|||
|
|
|||
|
global etat
|
|||
|
penup()
|
|||
|
goto(etat[0], etat[1])
|
|||
|
setheading(etat[2])
|
|||
|
pendown()
|
|||
|
|
|||
|
# Modifiez votre procédure dessine pour prendre en compte les deux
|
|||
|
# nouveaux ordres.
|
|||
|
|
|||
|
|
|||
|
def dessine2(ordres, l, α):
|
|||
|
"""
|
|||
|
Trace sur turtle la séquence d'ordre donnée, avec la longueur l et l'angle α
|
|||
|
donné.
|
|||
|
|
|||
|
CU : ordres str, l numérique, α numérique → ∅
|
|||
|
"""
|
|||
|
assert(type(ordres) is str), "ordres doit être du type str"
|
|||
|
assert(type(l) is float or type(l) is int), "l doit être numérique"
|
|||
|
assert(type(α) is float or type(α) is int), "α doit être numérique"
|
|||
|
|
|||
|
for i in ordres:
|
|||
|
if i == 'F' or i == 'G':
|
|||
|
forward(l)
|
|||
|
elif i == '+':
|
|||
|
left(α)
|
|||
|
elif i == '-':
|
|||
|
right(α)
|
|||
|
elif i == '(':
|
|||
|
sauvegarder_etat()
|
|||
|
elif i == ')':
|
|||
|
restaurer_etat()
|
|||
|
else:
|
|||
|
assert (False), "ordres doit être composé des caractères 'F', 'G', '+' \
|
|||
|
'-', '(' ou ')'"
|
|||
|
|
|||
|
# Tracez pour n compris entre 0 et 6, l=4 et α=60 le résultat de la
|
|||
|
# séquence d’ordres obtenu en dérivant n fois 'G' par ['FF', 'F+(G)--G']
|
|||
|
# par rapport à ['F','G'].
|
|||
|
|
|||
|
# n = 6
|
|||
|
# l = 4
|
|||
|
# α = 60
|
|||
|
# ordres = derive_mult_n('G', ['F', 'G'], ['FF', 'F+(G)--G'], n)
|
|||
|
# dessine2(ordres, l, α)
|
|||
|
|
|||
|
|
|||
|
def tester():
|
|||
|
doctest.testmod(verbose=True)
|