diff --git a/README.txt b/README.txt new file mode 100644 index 0000000..9e485a6 --- /dev/null +++ b/README.txt @@ -0,0 +1,35 @@ +Veillez à proposer votre rue dans cette ordre : + +Le nombre d'immeubles voulu +couleur de la façade en anglais - le nombre d'étages - la position de la porte - le type de toit - le type de fenêtre + +Exemple : + +3 immeubles +yellow - 4 - gauche - lisse - carreaux +... + +couleur de façade disponible : yellow, magenta, green, cyan +nombre d'étages disponible : minimum à 1 et maximum à 5 +position de porte disponible : gauche, milieu et droite +type de toit disponible : lisse et pointu +type de fenêtre disponible : carreaux, balcon, simple et aléatoire + +Entrer un paramètre invalide sera remplacé par de l'aléatoire. + +Exemple : +3 immeubles +yellow - aléatoire - gauche - aléatoire - carreaux +... + +ou encore : +3 immeubles + - - - - + - - - - + - - - - + + +Veulliez noter qu'il faut bien avoir le nombre d'immeuble en 1er caractère de la 1ere ligne et les immeubles sur les +lignes qui suivent. + +Pour afficher la rue, veuillez executer le programme interpreteur.py \ No newline at end of file diff --git a/dessiner.py b/dessiner.py new file mode 100644 index 0000000..e14db4b --- /dev/null +++ b/dessiner.py @@ -0,0 +1,171 @@ +"""Ce fichier permet de dessiner des formes à l'aide des fonctions suivantes + ++ triangle_equilateral(cote, info_feutre, coordonnees) ++ arc_de_cercle(rayon, angle, info_feutre, coordonnees) + + +Exemples d'utilisation : +>>> informations_feutre = {'écriture':'blue', 'fond':'#FF88FF', 'épaisseur':5} +>>> triangle_equilateral(50, informations_feutre, (50,100)) +>>> arc_de_cercle(75, 360, informations_feutre, (200,-200)) +""" + + +# Importation + +import turtle as trt +import random as rd + +# Déclaration des fonctions privées + +def nouveau_stylo(ecriture, fond, largeur): + """Renvoie la référence d'un stylo configuré + + :: param ecriture(str) :: la couleur d'écriture ('red', '#FF0000') + :: param fond(str) :: la couleur de fond pour ce stylo + :: param largeur(int) :: la largeur du trait + :: return (Turtle) :: renvoie un objet de la classe Turtle + + """ + feutre = trt.Turtle() + feutre.color(ecriture) + feutre.fillcolor(fond) + feutre.pensize(largeur) + feutre.speed(0) + return feutre + +def deplacer(feutre, x, y): + """Lève le feutre, déplace le feutre et abaisse le feutre + + :: param feutre(Turtle) :: la référence de l'objet Turtle + :: param x(int) :: coordonnée horizontale (abscisse) + :: param y(int) :: coordonnée verticale (ordonnée) + :: return (None) :: c'est une fonction sans retour + .. effet de bord :: modifie l'état de feutre + + """ + feutre.penup() # On lève la pointe + feutre.goto(x, y) # On déplace le crayon + feutre.pendown() # On abaisse la pointe + +def trace_rectangle(feutre,cote1,cote2) : + """Trace un rectangle à l'aide du crayon feutre + + :: param feutre(Turtle) :: la référence de l'objet Turtle + :: param cote1(int) :: la valeur en pixel d'un côté + :: param cote2(int) :: la valeur en pixel de l'autre côté + :: return (None) :: fonction sans retour + .. effet de bord :: modifie l'état de feutre + + """ + feutre.begin_fill() + for c in range(2) : + feutre.forward(cote1) + feutre.left(90) + feutre.forward(cote2) + feutre.left(90) + feutre.end_fill() + feutre.hideturtle() + +def trace_triangle_equilateral(feutre, cote): + """Trace un triangle (equilatéral) à l'aide du crayon feutre + + :: param feutre(Turtle) :: la référence de l'objet Turtle + :: param cote(int) :: la valeur en pixel des côtés + :: return (None) :: fonction sans retour + .. effet de bord :: modifie l'état de feutre + + """ + feutre.begin_fill() + for x in range(3): + feutre.forward(cote) + feutre.left(120) + feutre.end_fill() + feutre.hideturtle() + +def trace_arc(feutre, rayon, angle): + """Trace un arc de cercle à l'aide du crayon feutre + + :: param feutre(Turtle) :: la référence de l'objet Turtle + :: param rayon(int) :: la valeur en pixel du rayon + :: param angle(int) :: l'angle à tracer (360 pour un cercle) + :: return (None) :: fonction sans retour + .. effet de bord :: modifie l'état de feutre + + """ + feutre.begin_fill() + feutre.circle(rayon, angle) + feutre.end_fill() + feutre.hideturtle() + + +# Déclarations des fonctions publiques + +def rectangle(cote, info_feutre, coordonnees): + """Trace un rectangle à partir des info_feutre et aux bonnees coordonnées + + :: param cote(tuple[int]) :: la valeur en pixel des côtés + :: param info_feutre(dict) :: un dictionnaire {"écriture":str, "fond":str, "épaisseur":int} + :: param coordonnees(tuple (int,int) ) :: un tuple (x,y) + + """ + ecriture = info_feutre['écriture'] + fond = info_feutre['fond'] + epaisseur = info_feutre['épaisseur'] + x = coordonnees[0] # ou x,y = coordonnees (par désempaquetage) + y = coordonnees[1] + feutre = nouveau_stylo(ecriture, fond, epaisseur) + deplacer(feutre, x, y) + trace_rectangle(feutre, cote[0], cote[1]) + +def triangle_equilateral(cote, info_feutre, coordonnees): + """Trace un triangle (equilatéral) à partir des info_feutre et aux bonnees coordonnées + + :: param cote(int) :: la valeur en pixel des côtés + :: param info_feutre(dict) :: un dictionnaire {"écriture":str, "fond":str, "épaisseur":int} + :: param coordonnees(tuple (int,int) ) :: un tuple (x,y) + + """ + ecriture = info_feutre['écriture'] + fond = info_feutre['fond'] + epaisseur = info_feutre['épaisseur'] + x = coordonnees[0] # ou x,y = coordonnees (par désempaquetage) + y = coordonnees[1] + + feutre = nouveau_stylo(ecriture, fond, epaisseur) + deplacer(feutre, x, y) + trace_triangle_equilateral(feutre, cote) + + return feutre + +def arc_de_cercle(rayon, angle, info_feutre, coordonnees): + """Trace un arc de cercle à partir des info_feutre et aux bonnees coordonnées + + :: param rayon(int) :: la valeur en pixel du rayon + :: param angle(int) :: la valeur en ° de l'angle + :: param info_feutre(dict) :: un dictionnaire {"écriture":str, "fond":str, "épaisseur":int} + :: param coordonnees(tuple (int,int) ) :: un tuple (x,y) + + """ + ecriture = info_feutre['écriture'] + fond = info_feutre['fond'] + epaisseur = info_feutre['épaisseur'] + x = coordonnees[0] # ou x,y = coordonnees (par désempaquetage) + y = coordonnees[1] + + feutre = nouveau_stylo(ecriture, fond, epaisseur) + deplacer(feutre, x, y) + trace_arc(feutre, rayon, angle) + + return feutre + + +# Instructions du programme principal + +if __name__ == '__main__': + informations_feutre = {'écriture':"blue", 'fond':'#FF88FF', 'épaisseur':5} + rectangle((140,80),informations_feutre,(-400,0)) + rectangle((140,80),informations_feutre,(-200,0)) + rectangle((140,80),informations_feutre,(0,0)) + rectangle((140,80),informations_feutre,(200,0)) + diff --git a/interpreteur.py b/interpreteur.py new file mode 100644 index 0000000..d2906e6 --- /dev/null +++ b/interpreteur.py @@ -0,0 +1,144 @@ +""" +Ce programme permet de lire le fichier "ma_rue.txt" et de le convertir de façon à pouvoir afficher une rue correspondant +aux informations écrites (si les règles du "README.txt" sont respectées) +""" + + +# Importation + +from rue import couleur_aleatoire,couleur_aleatoire_fonce,dessiner_rue_decrite +import random as rd +obj_rue = open('ma_rue.txt', 'r', encoding="utf-8") + + +# Constantes + +LIGNE = [] +for a in obj_rue: + LIGNE.append(a) +NB = int(LIGNE[0][0]) +COULEURS = ('yellow', 'magenta', 'green', 'cyan') +obj_rue.close() + +# Fonction privées + +def lire_ligne_liste(l) -> list : + """ + Transforme une ligne de description d'un immeuble en une liste formatée pour générer ses attributs. + + Cette fonction prend en entrée une chaîne représentant les caractéristiques d'un immeuble, séparées par ' - ', et + retourne une liste contenant ces attributs. Les valeurs incorrectes ou non spécifiées sont remplacées par "aléatoire". + + Paramètres: + l (str): La ligne de description de l'immeuble sous forme de chaîne. + + Retourne: + list: Une liste contenant les attributs de l'immeuble dans l'ordre suivant : + - Couleur de la façade + - Nombre d'étages + - Position de la porte (0 = gauche, 1 = milieu, 2 = droite) + - Type de toit (False = rectangle, True = triangle) + - Type de fenêtre (0 = simple, 1 = balcon, 2 = carreaux) + Les valeurs non spécifiées ou incorrectes sont remplacées par "aléatoire". + """ + l = l.split(' - ') + if l[0] not in COULEURS : + l[0] = 'aléatoire' + + if type(int(l[1])) != int : + l[1] = 'aléatoire' + else : + l[1] = int(l[1]) + + if l[2] == "gauche" : + l[2] = 0 + elif l[2] == "mileu" : + l[2] = 1 + elif l[2] == 'droite' : + l[2] = 2 + else : + l[2] = 'aléatoire' + + if l[3] == 'lisse' : + l[3] = False + elif l[3] == 'pointu' : + l[3] = True + else : + l[3] = 'aléatoire' + + if l[4] == 'careaux\n' or l[4] == 'careaux' : + l[4] = 2 + elif l[4] == 'balcon\n' or l[4] == 'balcon' : + l[4] = 1 + elif l[4] == 'simple\n' or l[4] == 'simple' : + l[4] = 0 + else : + l[4] = 'aléatoire' + + return l + +#Fonctions Publiques +def lire_rue() -> list : + """ + Génère la description complète d'une rue en créant une liste de dictionnaires, chaque dictionnaire représentant un immeuble. + + Cette fonction utilise les données de la liste LIGNE pour lire les attributs de chaque immeuble. Lorsqu'une valeur + n'est pas définie, elle est remplacée par une valeur par défaut ou générée aléatoirement. + + Retourne: + list: Une liste de dictionnaires, chaque dictionnaire contient les informations de l'immeuble suivant : + - 'couleur_facade' (str) : couleur de la façade + - 'numero' (int) : numéro de l'immeuble dans la rue + - 'nb_etage' (int) : nombre d'étages (entre 1 et 5 par défaut) + - 'pos_porte' (int) : position de la porte (0 = gauche, 1 = milieu, 2 = droite) + - 'couleur_porte' (str) : couleur de la porte + - 'type_fenetre' (list) : type de chaque fenêtre (0 = normal, 1 = balcon, 2 = carreaux) + - 'type_toit' (bool) : forme du toit (False = rectangle, True = triangle) + """ + rue = [] + for i in range(NB) : + informations = {} + liste = lire_ligne_liste(LIGNE[i+1]) + #info immeuble + if liste[0] != 'aléatoire' : + informations['couleur_facade'] = liste[0] + else : + informations['couleur_facade'] = couleur_aleatoire() + informations['numero'] = i + if liste[1] != 'aléatoire' : + informations['nb_etage'] = liste[1] + else : + informations['nb_etage'] = rd.randint(1,5) + + #info porte + if liste[2] != 'aléatoire' : + informations['pos_porte'] = liste[2] + else : + informations['pos_porte'] = rd.randint(0,2) + informations['couleur_porte'] = couleur_aleatoire_fonce() + + #info fenetre + informations['type_fenetre'] = [] + if liste[4] == 2 : + for _ in range(int(informations['nb_etage'])*3) : + informations['type_fenetre'].append(2) # 0 -> normal, 1 -> balcon, 2 -> carreaux + elif liste[4] == 1 : + for _ in range(int(informations['nb_etage'])*3) : + informations['type_fenetre'].append(1) # 0 -> normal, 1 -> balcon, 2 -> carreaux + elif liste[4] == 0 : + for _ in range(int(informations['nb_etage'])*3) : + informations['type_fenetre'].append(0) # 0 -> normal, 1 -> balcon, 2 -> carreaux + else : + for _ in range(int(informations['nb_etage'])*3) : + informations['type_fenetre'].append(rd.randint(0,2)) # 0 -> normal, 1 -> balcon, 2 -> carreaux + + #info toit + if liste[3] != 'aléatoire' : + informations['type_toit'] = liste[3] # False -> rectangle, True -> triangle + else : + informations['type_toit'] = bool(rd.randint(0,1)) + rue.append(informations) + return rue + + +dessiner_rue_decrite(lire_rue()) \ No newline at end of file diff --git a/ma_rue.txt b/ma_rue.txt new file mode 100644 index 0000000..dd191e5 --- /dev/null +++ b/ma_rue.txt @@ -0,0 +1,5 @@ +4 immeubles +yellow - 4 - gauche - lisse - carreaux +cyan - 3 - milieu - pointu - balcon +green - 2 - droite - lisse - simple +magenta - 1 - peu importe - lise - caezpokifgjhpzuorg \ No newline at end of file diff --git a/rue.py b/rue.py new file mode 100644 index 0000000..6fa74ea --- /dev/null +++ b/rue.py @@ -0,0 +1,226 @@ +"""Ce fichier permet de dessiner une rue à l'aide des fonctions suivantes : ++ dessiner_rue_aleatoire() ++ dessiner_rue_decrite(rue:dict) +""" + + +# Importation + +from dessiner import triangle_equilateral,rectangle +import random as rd + +# Constantes + +IMMEUBLE = 140 +ETAGE = 80 +COTE_FENETRE = 30 +COTE_CARREAUX = COTE_FENETRE//2 +HAUTEUR_PORTE = 50 + +# Fonction privées + +def immeuble_aleatoire(numero:int) -> dict: + """Génère des informations aléatoires pour un immeuble + + :: param numero (int) :: le numéro identifiant l'immeuble + + Renvoi un dictionnaire contenant les informations de l'immeuble avec les clés suivantes : + - 'couleur_facade': Couleur de la façade de l'immeuble. + - 'numero': Numéro de l'immeuble. + - 'nb_etage': Nombre d'étages de l'immeuble (entre 1 et 5). + - 'pos_porte': Position de la porte (0, 1 ou 2). + - 'couleur_porte': Couleur de la porte (une couleur foncée aléatoire). + - 'type_fenetre': Liste des types de fenêtres pour chaque étage (0, 1 ou 2). + - 'type_toit': Type de toit (booléen, où False indique un toit rectangulaire et True un toit triangulaire). + + Fait par Iyad + """ + informations = {} + #info immeuble + informations['couleur_facade'] = couleur_aleatoire() + informations['numero'] = numero + informations['nb_etage'] = rd.randint(1,5) + #info porte + informations['pos_porte'] = rd.randint(0,2) + informations['couleur_porte'] = couleur_aleatoire_fonce() + #info fenetre + informations['type_fenetre'] = [] + for _ in range(informations['nb_etage']*3) : + informations['type_fenetre'].append(rd.randint(0,2)) # 0 -> normal, 1 -> balcon, 2 -> carreaux + #info toit + informations['type_toit'] = bool(rd.randint(0,1)) # False -> rectangle, True -> triangle + return informations + +def couleur_aleatoire() -> str: + """Permet de fournir une couleur aléatoire non foncée + + Renvoi un str qui contient une couleur non foncée parmis : + "yellow","magenta","green","cyan" + + Fait par Iyad + """ + couleur = ("yellow","magenta","green","cyan") + return couleur[rd.randint(0,3)] + +def couleur_aleatoire_fonce() -> str : + """Permet de fournir une couleur aléatoire foncée + + Renvoi un str qui contient une couleur foncée parmis : + "purple","red","blue","black" + + Fait par Louay + """ + couleur = ("purple","red","blue","black") + return couleur[rd.randint(0,3)] + +def coordonnees_facade(immeuble:dict) -> tuple: + """Calcule les coordonnées de la façade d'un immeuble + + :: param immeuble (dict) :: un dictionnaire contenant les informations de l'immeuble tel que : + - numero : le numéro de l'immeuble + + Renvoi un tuple contenant les coordonnées (x_gauche, y_bas) de la façade de l'immeuble + + Fait par Louay + """ + x_gauche = -400 + 200 * immeuble['numero'] + y_bas = 0 + return (x_gauche, y_bas) + +def dessiner_facade(immeuble:dict) -> None: + """Permet de dessiner la façade de l'immeuble + + :: param immeuble (dict) :: un dictionnaire contenant les informations de l'immeuble tel que : + - couleur_facade : la couleur de la façade de l'immeuble + - nb_etage : le n'ombre d'étages de l'immeuble + + Fait par Iyad + """ + crayon = {} + crayon['écriture'] = "gray" + crayon['fond'] = immeuble['couleur_facade'] + crayon['épaisseur'] = 5 + x, y = coordonnees_facade(immeuble) + rectangle((IMMEUBLE,(immeuble['nb_etage']*ETAGE)),crayon,(x,y+(immeuble['nb_etage']+ETAGE))) + +def dessiner_porte(immeuble:dict) -> None: + """Permet de dessiner la porte d'un immeuble + + :: param immeuble (dict) :: un dictionnaire contenant les informations de l'immeuble tel que : + - couleur_porte : la couleur de la porte + - pos_porte : la position de la porte définie aléatoirement + - nb_etages : le nombre d'étages de l'immeuble + + Fait par Louay + """ + crayon = {} + crayon['écriture'] = "gray" + crayon['fond'] = immeuble['couleur_porte'] + crayon['épaisseur'] = 3 + x,y = coordonnees_facade(immeuble) + y += ETAGE + 4 + x += 20 + (immeuble['pos_porte']) * 40 + rectangle((COTE_FENETRE,HAUTEUR_PORTE),crayon, (x,y)) + + + +def dessiner_fenetre(immeuble: dict) -> None: + """Permet de tracer 3 types de fenêtres. Tel que une fenêtre simple mais aussi à carreaux ou avec un balcon. + + :: param immeuble (dict) :: un dictionnaire contenant les informations de l'immeuble tel que : + - nb_etages : le nombre d'étages de l'immeuble + - pos_porte : la position de la porte définie aléatoirement + - type_fenetre : une liste des types de fenêtres + + Fait par Louay et Iyad + """ + + crayon = {} + crayon['écriture'] = "gray" + crayon['fond'] = "cyan" + crayon['épaisseur'] = 3 + nb_etages = immeuble['nb_etage'] + x_base, y_base = coordonnees_facade(immeuble) + y_base += ETAGE + 20 + + + for etage in range(nb_etages): + y = y_base + etage * ETAGE + + for colonne in range(3): + x = x_base + 20 + colonne * 40 + type_fenetre = immeuble['type_fenetre'] + if etage == 0 and colonne == immeuble['pos_porte']: + continue + + if immeuble['type_fenetre'][etage * 3 + colonne] == 0: + rectangle((COTE_FENETRE, COTE_FENETRE), crayon, (x, y)) + + elif immeuble['type_fenetre'][etage * 3 + colonne] == 1: + rectangle((COTE_FENETRE, COTE_FENETRE), crayon, (x, y)) + rectangle((0, COTE_FENETRE), crayon, (x + COTE_CARREAUX, y)) + rectangle((COTE_FENETRE, 0), crayon, (x, y + COTE_CARREAUX)) + + elif immeuble['type_fenetre'][etage * 3 + colonne] == 2: + rectangle((COTE_FENETRE, HAUTEUR_PORTE), crayon, (x, y - 20)) + for i in range(5): + rectangle((0, COTE_FENETRE + 3), crayon, (x + i * 7, y - COTE_CARREAUX - 3)) + rectangle((COTE_FENETRE, 0), crayon, (x, y + COTE_CARREAUX)) + +def dessiner_toit(immeuble:dict) -> None: + """Permet de dessiner 2 types de toits tel que pointu ou plat + + :: param immeuble (dict) :: un dictionnaire contenant les informations de l'immeuble tel que : + - type_toit : indique le type de toit définie par un booléen + - nb_etage : nombre d'étages de l'immeuble + + Fait par Iyad + """ + crayon = {} + crayon['écriture'] = "black" + crayon['fond'] = "black" + crayon['épaisseur'] = 5 + x, y = coordonnees_facade(immeuble) + x -= 10 + y += (immeuble['nb_etage']+1) * ETAGE + if immeuble['type_toit'] == False : + dim = (20 + IMMEUBLE), 20 + rectangle(dim, crayon, (x,y)) + else : + dim = (20 + IMMEUBLE) + triangle_equilateral(dim, crayon, (x,y)) + +def dessiner_immeuble(immeuble:dict) -> None: + """Permet de dessiner un immeuble complet + + :: param immeuble (dict) :: un dictionnaire contenant toutes les informations de l'immeuble + + Fait par Iyad + """ + dessiner_facade(immeuble) + dessiner_fenetre(immeuble) + dessiner_porte(immeuble) + dessiner_toit(immeuble) + +# Fonction publiques + +def dessiner_rue_aleatoire() -> None: + """Permet de dessiner une rue contenant 4 immeubles aux caractéristiques définies aléatoirement + """ + for n in range(rd.randint(1,4)): + informations_immeuble = immeuble_aleatoire(n) + dessiner_immeuble(informations_immeuble) + +def dessiner_rue_decrite(rue:list) -> None: + """Permet de dessiner une rue contenant 4 immeubles aux caractéristiques définies dans ma_rue.txt + """ + for dictionnaire in rue : + dessiner_immeuble(dictionnaire) + + + +# Programme principal + +if __name__ == '__main__': + dessiner_rue_aleatoire() +