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)
|