This repository has been archived on 2019-08-09. You can view files and clone it, but cannot push or open issues or pull requests.
s1-tp/S1/TP 8/lsystem.py
2014-11-21 00:01:48 +01:00

408 lines
11 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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 lexemple 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 dun 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
# Nhé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=35n et α=60 le résultat de la séquence
# dordres 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 nappartient 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 dordres 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=27n et α=90 le résultat de la séquence
# dordres 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 dune 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 dordres 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)