{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Mini-projet collectif : \"dessiner ma rue\"\n", "\n", "
\n", " \"rue-félix-le-dantec-brest\"\n", "
\n", " Vue de la rue Félix le Dantec à Brest, un éloge à la couleur\n", "
\n", "
\n", "\n", "\n", "## But :\n", "\n", "On souhaite écrire un programme qui permet de générer « aléatoirement » le dessin d’une rue de 4 immeubles dans un notebook jupyter.\n", "\n", "\"dessiner_ma_rue-rue_finale0.png\"\n", "\n", "On utilisera pour cela le module **`ipycanvas`** de [Martin RENOU](https://github.com/martinRenou) :\n", "\n", "\"ipycanvas-logo.svg\"\n", "\n", "\n", "Si vous ne connaissez pas ce module, il vous faut donc préalablement le prendre en main en faisant, par exemple, les activités de [ipycanvas-Le_BN_pour_dessiner.ipynb\n", "](ipycanvas-Le_BN_pour_dessiner.ipynb)...\n", "\n", "## Contraintes :\n", "\n", "Les contraintes urbanistiques sont les suivantes :\n", "\n", "- Les immeubles ont au minimum un rez-de-chaussée et au maximum 4 étages (5 niveaux) ;\n", "- Les immeubles ont une largeur de 140 pixels ;\n", "- Les immeubles ont une couleur unique pour toute la façade ;\n", "- D'une manière générale, tous les tracés de contour des formes sont de couleur noire et font 1 pixel d'épaisseur ;\n", "- Chaque niveau (rez-de-chaussée ou étage) a une façade de hauteur 60 pixels ;\n", "- Les rez-de-chaussée n'ont qu'une seule porte et 2 fenêtres placées aléatoirement ;\n", "- Toutes les fenêtres sont identiques, de taille 30 pixels sur 30 pixels avec une vitre de couleur 'Azure' le jour ;\n", "- Toutes les portes fenêtre ont un balcon et font une taille de 30 pixels en largeur et 50 pixels en hauteurs ;\n", "- Le toit peut avoir 2 formes; plat ou triangulaire :\n", " - Si le toit est plat : il fait une épaisseur de 10 pixels ;\n", "\t- Si le toit est triangulaire, il fait une hauteur de 40 pixels pour une base de 160 pixels.\n", "\n", "\n", "## Exemples :\n", "\n", "\"dessiner_ma_rue-rue_finale2.png\"\n", "\n", "La série d'exemples suivants est basée sur :\n", "-\tune couleur aléatoire pour les façades ;\n", "-\tdeux modèles de toits ;\n", "-\tdeux modèles de portes avec une couleur aléatoire ;\n", "-\tdeux modèles d'ouvertures pour les étages : fenêtre ou porte-fenêtre avec balcon ;\n", "-\ttrois éléments horizontalement pour chaque niveau.\n", "\"dessiner_ma_rue-rue_finale4.png\"\n", "\"dessiner_ma_rue-rue_finale4.png\"\n", "\n", "\n", "\n", "\n", "## Travail à faire :\n", "\n", "Livrer un programme constitué de modules qui réponde au problème posé en utilisant le module **`ipycanvas`** de [Martin RENOU](https://github.com/martinRenou).\n", "\n", "Vous utiliserez le plus de petites fonctions possibles :\n", "\n", "\"dessiner_ma_rue-schema.svg\"\n", "\n", "\n", "Le [Product Backlog](https://blog.myagilepartner.fr/index.php/2018/08/07/backlog/#:~:text=D%C3%A9finition%20du%20product%20backlog&text=Il%20repr%C3%A9sente%20l'ensemble%20des,les%20spike%20voire%20les%20bugs.), c'est à dire les modules à produire et leurs dépendances sont décrits dans le schéma ci-dessus.\n", "\n", "\n", "\n", "Vous travaillerez collectivement en mode agile et en interdépendance à travers des importations de modules par équipes de 6 élèves + 1 professeur qui jouera le role de [Product Owner](https://www.orientation.com/metiers/product-owner).\n", "\n", "Les équipes seront donc misent en concurrences pour ce projet.\n", "\n", "Dans chaque équipe vous désignerez deux volontaires pour être [Scrum Master](https://www.clementine.jobs/fiches-metiers/metiers-techniques-du-web/scrum-master/#:~:text=Le%20Scrum%20Master%20est%20avant,en%20suivant%20la%20m%C3%A9thode%20Scrum.).\n", "\n", "Tout le monde participe activement au développement du code y compris le [Product Owner](https://www.orientation.com/metiers/product-owner) en cas de besoin (mais pas trop parce qu'il n'a pas que ça à faire !;) ).\n", "\n", "Ce projet sera donc aussi l'occasion de découvrir et d'expérimenter les rudiments d'une méthode agile que présente les vidéos suivantes..." ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", " \n", "
\n" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "%%HTML\n", "
\n", " \n", "
" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", " \n", "
\n" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "%%HTML\n", "
\n", " \n", "
" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", " \n", "
\n" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "%%HTML\n", "
\n", " \n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Le développement du projet va donc se décomposer en plusieurs sprints.\n", "\n", "Le premier sprint, en fait le sprint zéro, sera collectif et piloter par le [Product Owner](https://www.orientation.com/metiers/product-owner) afin que chacun comprenne le besoin du client et prenne en main l'environnement de travail (workflow) qu'il faudra appliquer pour la suite du développement. Le livrable attendu pour ce sprint est le module `ma_rue.py`." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Les sprints suivants seront menés au sein de chaque équipe où les Scrums Master veilleront à animer les cérémonies de sprint, \n", "la répartition des tâches pour chaque User Story, qui seront ici les modules à produire en commençant par ceux qui ne dépendent pas des autres.\n", "\n", "Ainsi le Sprint 1 devrait contenir quatre User Stories pour produire respectivement les modules `trait.py`, `rectangle.py`, `couleur_aleatoire.py` et `toit1`. \n", "\n", "\n", "Pour vous aider dans votre tâche, pour chaque module :\n", "\n", "- la spécification des fonctions est imposée et précisée dans leur docstring respective ;\n", "- des tests unitaires sont fournis, ils doivent produire le même dessin que celui de l'image fournie pour le résultat attendu. \n", "\n", "\n", "Il ne vous reste qu’à écrire le code en suivant le Workflow.\n", "\n", "A vous de jouer !\n", "C'est parti pour le Sprint..., rendez-vous au prochain Scrum...\n", "\n", "> Etres agile c'est avant tout une posture, qui au delà des aspects techniques de l'écriture du code, nous conduit à surveiller également la méthode de développement et l'organisation dans l'équipe avec le souci constant de la réussite collective du projet et de la satisfaction des clients, les Key Users." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Workflow de développement à partir d'un notebook :\n", "\n", "Rechercher, écrire et tester les instructions nécessaires pour chaque module dans trois cellules d'un notebook telles qu'avec l'exemple suivant :\n", "\n", "### `toto.py`" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Dépendances\n", " \n", "from machin import bidule, truc" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Définitions\n", " \n", "bar = 'titi'\n", "\n", "def foo() :\n", " '''\n", " Docstring de foo()\n", " '''\n", " pass\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Tests\n", "\n", "foo() # appel à la fonction foo() pour un test\n", "\n", "print(bar) # affichage en sortie d'une variable" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Sans toutefois trop digresser, multiplier les tests pour éprouver le potentiel des fonctinnalités de votre module. Afin de démontrer, qu'en cas d'abandon du projet final pour une raison ou une autre, vous n'avez pas perdu votre temps car au moins le morceau de code de votre User Story pourrait être réemployé à d'autres fins.\n", "\n", "Si les tests sont concluants alors on peut rassembler le code du module dans un fichier `toto.py` tel que :\n", "\n", "```python\n", "# Dépendances\n", " # (coller ici les instructions de la cellule des dépendances)\n", "from machin import bidule, truc\n", "\n", "# Définitions\n", " # (coller ci-dessous les instructions de la cellule de définitions)\n", "\n", "bar = 'titi'\n", "\n", "def foo() :\n", " '''\n", " Docstring de foo()\n", " '''\n", " pass\n", "\n", "# Tests\n", "if __name__ == '__main__': # ce bloc d'instructions sera exécuté si on fait un %run toto.py\n", " #(coller ci-dessous les instructions de la cellule de tests)\n", " # appel à la fonction foo() pour un test\n", " foo()\n", " # affichage en console d'une variable\n", " print(bar)\n", "```\n", "\n", "On peut alors exécuter le code de test du programme `toto.py` depuis une cellule du notebook avec l'instruction :\n", "\n", "```python\n", "%run toto.py\n", "```\n", "\n", "Si cet ultime test est concluant, on peut alors partager le fichier `toto.py`avec les autres membres de l'équipe (par mail, airdrop, ou beaucoup mieux avec GitHub...).\n", "**/!\\ ne partager un module que si votre code à passer tous les tests**\n", "\n", "Les autres membres peuvent alors tout comme vous, importer dans leur notebook les dépendances validées afin de les utiliser dans la suite du développement des autres modules\n", "\n", "```python\n", "from toto import bar,foo\n", "```\n", "Sinon on continue le développement dans le notebook sans faire d'import de dépendances externes tant qu'elles ne sont pas fonctionnelles..." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Prise en main du workflow, Sprint 0 :\n", "\n", "### `ma_rue.py`\n", "\n", "#### Résultat attendu au test :\n", "\n", "- Affichage d'un canvas vierge de 800 x 400 pixels." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Dépendance\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Définition \n", "\n", "# Création d'un canvas nommé rue de 800 pixels de large par 400 pixels de haut\n", "\n", "\n", "# Définition d'une fonction d'affichage\n", "def affiche(canvas) :\n", " '''\n", " Efface et affiche le canvas dans le notebook\n", " '''\n", " \n", " " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Test\n", "\n", "# Affichage du canvas rue pour un test\n", "affiche(rue)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "> Le test d'affichage est concluant => On emballe ce code dans un fichier `ma_rue.py` et on le teste une dernière fois :" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Validation du module :\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%run ma_rue.py" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "> Cet ultime test est aussi concluant => On partage le fichier `ma_rue.py` dans l'équipe pour importer ses fonctionnalités par la suite" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Application du workflow, Sprint 1 :\n", "\n", "### `trait.py`\n", "\n", "#### Résultat attendu aux tests :\n", "\n", "\"dessiner_ma_rue-trait.png\"" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Dépendances\n", "from ma_rue import rue, affiche" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Définitions\n", "\n", "# Fonction trait()\n", "def trait(x1,y1,x2,y2):\n", " '''\n", " dessine un trait entre les 2 points transmis en paramètres\n", " Paramètres\n", " x1, y1 : coordonnées du début du trait\n", " x2, y2 : coordonnées de la fin du trait\n", " \n", " '''\n", " \n", " \n", " \n", " " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Tests\n", "affiche(rue)\n", "trait(50, 25, rue.width/2, rue.height/2)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Autres tests\n", "for x in range (int(rue.width/2), rue.width + 1, 20) :\n", " trait(x, 0, 3*rue.width/2 - x, rue.height)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Validation du module :\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%run trait.py" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### `rectangle.py`\n", "\n", "#### Résultat attendu aux tests :\n", "\n", "\"dessiner_ma_rue-rectangle.png\"" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Dépendances\n", "from ma_rue import rue, affiche " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Définitions\n", "\n", "# Fonction rectangle()\n", "def rectangle(x,y,w,h,c):\n", " '''\n", " Dessine un rectangle avec un contour noir et rempli de la couleur passée en paramètre\n", " Paramètres\n", " x, y : coordonnées du centre de la base de rectangle\n", " w : largeur du rectangle\n", " h : hauteur du rectangle\n", " c : couleur du remplissage\n", " '''\n", " \n", " \n", " \n", " \n", " " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Tests\n", "affiche(rue)\n", "rectangle(0, 50,200,100,'YellowGreen')\n", "rectangle(800, 450,200,100,'plum')\n", "rectangle(400, 250,200,100,'SkyBlue')\n", "rectangle(400, 250,100,50,'salmon')" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Autres tests\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Validation du module :\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%run rectangle.py" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### `couleur_aleatoire.py`\n", "\n", "#### Résultat attendu au test :\n", "\n", "\"dessiner_ma_rue-couleur_aleatoire.png\"\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Dépendances\n", "from ma_rue import rue, affiche \n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Définitions\n", "\n", "def couleur_aleatoire():\n", " '''\n", " Renvoie une couleur HTML valide\n", " au format 'rgb(rouge, vert, bleu)'\n", " où rouge, vert et bleu sont des entiers\n", " compris entre 0 et 255 choisis aléatoirement.\n", " \n", " '''\n", " \n", " \n", " \n", " return " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Tests\n", "affiche(rue)\n", "couleur = couleur_aleatoire()\n", "rue.fill_style = couleur\n", "rue.fill_rect(0, 0, rue.width, rue.height)\n", "rue.font = '48px Lucida Console'\n", "rue.text_align = 'center'\n", "rue.stroke_text(couleur, rue.width/2, rue.height/2)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Autres tests\n", "from time import sleep\n", "affiche(rue)\n", "for i in range(30) :\n", " couleur = couleur_aleatoire()\n", " rue.fill_style = couleur\n", " rue.fill_rect(0, 0, rue.width, rue.height)\n", " rue.font = '48px Lucida Console'\n", " rue.text_align = 'center'\n", " rue.stroke_text(couleur, rue.width/2, rue.height/2)\n", " sleep(1)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Validation du module :\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%run couleur_aleatoire.py" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### `toit1.py`\n", "\n", "#### Résultat attendu aux tests :\n", "\n", "\"dessiner_ma_rue-toit1.png\"" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Dépendances\n", "from ma_rue import rue, affiche " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Définitions\n", "\n", "# Fonction toit1()\n", "def toit1(x, niveau):\n", " '''\n", " Dessine un triangle plein de couleur noir de 40 pixels de haut\n", " et avec une base de 160 pixels \n", " Paramètres :\n", " x : abcisse du centre du toit\n", " niveau : numero du niveau (0 pour les rdc, ...)\n", " '''\n", " y = rue.height - niveau * 60 # ordonnée de la base du toit\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Tests\n", "affiche(rue)\n", "toit1(rue.width/2, 0)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Autres tests\n", "for i in range(5) :\n", " for j in range(1, 6) :\n", " toit1(0 + 200 * i, j)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Validation du module :" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%run toit1.py" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Exemple de scripts donnés pour des démonstrations à faire pour la revue du Sprint 1 :\n", "\n", "#### Résultat attendu au test 1 :\n", "\n", "\"dessiner_ma_rue-sprint1-test1.png\"\n", "\n", "#### Script de validation du test 1 :" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from ma_rue import rue, affiche \n", "from rectangle import rectangle\n", "from couleur_aleatoire import couleur_aleatoire\n", "from trait import trait\n", "from toit1 import toit1\n", "\n", "affiche(rue)\n", "\n", "for i in range(5) :\n", " rectangle(0+200*i, rue.height, 140, 60*(i+1), couleur_aleatoire())\n", " toit1(0+200*i, i+1)\n", " for j in range(i+1) :\n", " trait(0+200*i-70, rue.height-60*j, 0+200*i+70, rue.height-60*j)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Résultat attendu aux tests 2 :\n", "\n", "\"dessiner_ma_rue-sprint1-test2.png\"\n", "\n", "\n", "#### Script de validation du test 2 :" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "scrolled": true }, "outputs": [], "source": [ "from ma_rue import rue, affiche \n", "from rectangle import rectangle\n", "from couleur_aleatoire import couleur_aleatoire\n", "from trait import trait\n", "from toit1 import toit1\n", "\n", "affiche(rue)\n", "\n", "# Les pieds\n", "toit1(rue.width/4, 0)\n", "toit1(3*rue.width/4, 0)\n", "# Le cadre\n", "rectangle(rue.width/2, rue.height-40, rue.width/2, rue.height -80, couleur_aleatoire())\n", "# Un chapeau\n", "toit1(rue.width/2, 6)\n", "\n", "# Un carré de couleur 'snow' au centre du canvas\n", "c = rue.width/3 # longueur du coté\n", "# Coordonnées du milieu de la base du carré\n", "cx = rue.width/2\n", "cy = rue.height/2 + c/2\n", "rectangle(cx, cy , c, c, 'snow')\n", "\n", "# Figure de fils tendus dans le carré\n", "n = 30 #nombre de fils\n", "pas = c/n\n", "for k in range(1, n+1) :\n", " trait(cx-c/2, cy-c + k*pas, cx-c/2 + k*pas, cy)\n", "for k in range(1, n+1) :\n", " trait(cx-c/2 + k*pas, cy-c, cx+c/2, cy-c + k*pas)\n", "for k in range(1, n+1) :\n", " trait(cx+c/2, cy-c + k*pas , cx+c/2 - k*pas, cy)\n", "for k in range(1, n+1) :\n", " trait(cx-c/2, cy-c + k*pas , cx+c/2 - k*pas, cy-c) " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Autres démonstrations de fin de sprint 1 :" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from ma_rue import rue, affiche \n", "from rectangle import rectangle\n", "from couleur_aleatoire import couleur_aleatoire\n", "from trait import trait\n", "from toit1 import toit1\n", "\n", "# A compléter par vous même pour implémenter vos propres idées de démonstration pour la Sprint Review..." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Rétrospective du Sprint 1 :\n", "\n", "Organiser une réunion de rétrospective du Sprint 1, relever la tête du guidon et résumer ci-dessous les points à retenir :\n", "\n", "#### Nos points forts, ce qui à bien fonctionné :\n", "\n", "- \n", "- \n", "\n", "#### Nos points de faiblesses, ce qui à moins bien fonctionné :\n", "\n", "- \n", "- \n", "\n", "#### Nos points de blocages, ce qui n'a pas fonctionné :\n", "\n", "- \n", "- \n", "\n", "#### Nos axes d'améliorations envisagés pour la suite :\n", "\n", "- \n", "- " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Autres modules à développer (User strories restantes en Backlog) :\n", "\n", "A charge pour vous de vous organiser dans chaque équipe afin de finaliser le développement du projet..." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### `sol.py`\n", "\n", "#### Résultat attendu au test :\n", "\n", "\"dessiner_ma_rue-sol.png\"" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Dépendances\n", "from ma_rue import rue, affiche \n", "from trait import trait " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Définitions\n", "\n", "# Fonction sol()\n", "def sol():\n", " '''\n", " Trace une ligne horizontale au niveau du sol de la rue\n", " d'épaisseur 3 pixels et de longueur 760 pixels\n", " centrée dans le canvas\n", " \n", " '''\n", " y_sol = rue.height-1 # ordonnée du sol de la rue\n", " \n", " \n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Tests\n", "affiche(rue)\n", "sol()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Autres tests\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Validation du module :" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%run sol.py" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### `portes.py`\n", "\n", "#### Résultat attendu au test :\n", "\n", "\"dessiner_ma_rue-portes.png\"" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Dépendances\n", "from ma_rue import rue, affiche\n", "from rectangle import rectangle\n", "from couleur_aleatoire import couleur_aleatoire\n", "from math import pi\n", "from random import randint" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Définitions\n", "\n", "# Fonction portes()\n", "def portes(x,y):\n", " '''\n", " Dessine une porte de 50 pixels en largeur et 70 pixels en hauteur\n", " La forme du haut de la porte est aléatoirement rectangulaire ou arrondi\n", " La couleur pleine de remplissage est choisi aléatoirement parmi les couleurs HTML valides\n", " Paramètres :\n", " x est l'abcisse du milieu de la base de la porte\n", " y est l'ordonnée du sol du niveau de la porte \n", " ''' \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Tests\n", "affiche(rue)\n", "for i in range(21) :\n", " portes(0 + i * 40,rue.height)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Autres tests\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Validation du module :" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%run portes.py" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### `facade.py`\n", "\n", "#### Résultat attendu au test :\n", "\n", "\"dessiner_ma_rue-facade.png\"" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Dépendances\n", "from ma_rue import rue, affiche\n", "from rectangle import rectangle" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Définitions\n", "\n", "\n", "# Fonction\n", "def facade(x, couleur, niveau):\n", " '''\n", " Dessine un rectangle de 60 pixels de haut et 140 pixels de large\n", " Paramètres :\n", " x : abcisse du centre de la façade\n", " couleur : couleur de la façade fixée par l'immeuble\n", " niveau : numéro du niveau (0 pour les rdc, ...)\n", " '''\n", " y = rue.height - niveau * 60 # ordonnée de la base de la facade\n", " \n", " \n", " " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Tests\n", "from couleur_aleatoire import couleur_aleatoire\n", "affiche(rue)\n", "couleur = couleur_aleatoire()\n", "for n in range(6) :\n", " facade(rue.width/2, couleur, n)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Autres tests\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Validation du module :" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%run facade.py" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### `fenetre.py`\n", "\n", "#### Résultat attendu au test :\n", "\n", "\"dessiner_ma_rue-fenetre.png\"" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Dépendances\n", "from ma_rue import rue, affiche\n", "from rectangle import rectangle" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Définitions\n", "\n", "# Fonction\n", "def fenetre(x,y):\n", " '''\n", " Dessine une fenêtre de taille 30 pixels sur 30 pixels\n", " avec une vitre de couleur 'Azure' le jour\n", " et un contour noir. \n", " Paramètres :\n", " x est l'abcisse du milieu de la base de la fenêtre\n", " y est l'ordonnée du sol du niveau de la fenetre\n", " '''\n", " \n", " \n", " " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Tests\n", "affiche(rue)\n", "fenetre(rue.width/2,rue.height)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Autres tests\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Validation du module :" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%run fenetre.py" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### `balcon.py`\n", "\n", "#### Résultat attendu au test :\n", "\n", "\"dessiner_ma_rue-balcon.png\"" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Dépendances\n", "from ma_rue import rue, affiche\n", "from rectangle import rectangle\n", "from trait import trait " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Définitions\n", "\n", "# Fonction balcon()\n", "def balcon(x,y):\n", " '''\n", " Dessine une porte fenêtre de largeur 30 pixels et 50 pixels en hauteur\n", " avec une vitre de couleur 'Azure' le jour au contour noir,\n", " devancé d'un balcon constitué de traits noirs d'épaisseur 3 pixels.\n", " Paramètres :\n", " x est l'abcisse du milieu de la base de la porte-fenetre\n", " y est l'ordonnée du sol du niveau de la porte-fenetre\n", " '''\n", " # porte-fenetre\n", " \n", " \n", " \n", " # balcon\n", " \n", " \n", " \n", " " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Tests\n", "affiche(rue)\n", "balcon(rue.width/2,rue.height)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Autres tests\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Validation du module :" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%run balcon.py" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### `rdc.py`\n", "\n", "#### Résultat attendu au test :\n", "\n", "\"dessiner_ma_rue-rdc.png\"" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Dépendances\n", "from ma_rue import rue, affiche\n", "from facade import facade\n", "from portes import portes\n", "from fenetre import fenetre\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Définitions\n", "\n", "# Fonction rdc()\n", "def rdc(x, couleur):\n", " '''\n", " Dessine le rdc sur une facade au niveau do sol de la rue\n", " avec une seule porte et 2 fenêtres placées aléatoirement.\n", " Paramètres\n", " x : abscisse du milieu de la base du RDC\n", " couleur : couleur fixée par l'immeuble \n", " '''\n", " # Dessine la facade\n", " \n", " \n", " # Choix d'une distribution\n", " \n", " \n", " \n", " # dessiner une porte\n", " \n", " \n", " # dessiner une fenetre\n", " \n", " " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Tests\n", "from couleur_aleatoire import couleur_aleatoire\n", "affiche(rue)\n", "for i in range(7) :\n", " rdc(i*160, couleur_aleatoire())" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Autres tests\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Validation du module :" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%run rdc.py" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### `etage.py`\n", "\n", "#### Résultat attendu au test :\n", "\n", "\"dessiner_ma_rue-etage.png\"\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Dépendances\n", "from ma_rue import rue, affiche\n", "from facade import facade\n", "from fenetre import fenetre\n", "from balcon import balcon \n", "\n", "from random import randint" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Définitions\n", "\n", "# Fonction etage()\n", "def etage(x, couleur, niveau):\n", " '''\n", " Dessine sur une facade un étage avec 3 éléments choisis aléatoirement\n", " parmi une fenêtre ou une porte fenêtre avec balcon. \n", " \n", " Paramètres\n", " x : abscisse du milieu de la base de l'étage\n", " couleur : couleur fixée par l'immeuble\n", " niveau : numéro de l'étage en partant de 0 pour le rdc\n", " '''\n", " y = rue.height - niveau * 60 # ordonnée de la base de l'etage\n", " \n", " # Murs\n", " \n", " \n", " \n", " # Eléments\n", " \n", " \n", " \n", " \n", " \n", " " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Tests\n", "from couleur_aleatoire import couleur_aleatoire\n", "affiche(rue)\n", "couleur = couleur_aleatoire()\n", "for n in range(6) :\n", " etage(rue.width/2,couleur,n)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Autres tests\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Validation du module :" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%run etage.py" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### `toit2.py`\n", "\n", "#### Résultat attendu au test :\n", "\n", "\"dessiner_ma_rue-toit2.png\"\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Dépendances\n", "from ma_rue import rue, affiche\n", "from trait import trait" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Définitions\n", "\n", "# Fonction toit2()\n", "\n", "def toit2(x, niveau):\n", " '''\n", " Paramètres :\n", " x : abcisse du centre du toit\n", " y_sol : ordonnée du sol du la rue\n", " niveau : num du niveau (0 pour les rdc, ...)\n", " '''\n", " y = rue.height - niveau * 60 # ordonnée de la base du toit\n", " \n", " # trait horizontal\n", " \n", " \n", " \n", " \n", " \n", " " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Tests\n", "affiche(rue)\n", "for n in range(6) :\n", " toit2(rue.width/2, n)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Autres tests\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Validation du module :" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%run toit2.py" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### `toits.py`\n", "\n", "#### Résultat attendu au test :\n", "\n", "\"dessiner_ma_rue-toit.png\"\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Dépendances\n", "from ma_rue import rue, affiche\n", "from toit1 import toit1\n", "from toit2 import toit2\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Définitions\n", "\n", "# Fonction toits()\n", "\n", "def toits(x, niveau):\n", " '''\n", " Dessine aléatoirement un toit plat ou un toit en pointe\n", " à l'ordonnée du niveau passé en paramètre\n", " Paramètres\n", " x : abscisse du centre de l'étage\n", " y_sol: ordonnée du sol\n", " niveau : numéro de l'étage en partant de 0 pour le rdc\n", " '''\n", " \n", " \n", " \n", " " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Tests\n", "affiche(rue)\n", "for i in range(5) :\n", " for j in range(6) :\n", " toits(0 + 200 * i, j)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Autres tests\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Validation du module :" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%run toits.py" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### `immeuble.py`\n", "\n", "#### Résultat attendu au test :\n", "\n", "\"dessiner_ma_rue-immeuble.png\"\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Dépendances\n", "from ma_rue import rue, affiche\n", "from couleur_aleatoire import couleur_aleatoire\n", "from rdc import rdc\n", "from etage import etage\n", "from toits import toits\n", "\n", "from random import randint" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Définitions\n", "\n", "def immeuble(x):\n", " '''\n", " Dessine un immeuble selon les règles urbanistiques imposées\n", " \n", " Paramètres\n", " x : abscisse du milieu de la base de l'immeuble\n", " \n", " '''\n", " # Nombre d'étage (aléatoire)\n", " \n", " \n", " #Couleur facade (aléatoire)\n", " \n", " \n", " # Dessin du RDC\n", " \n", "\n", " # Dessin des étages\n", " \n", " \n", "\n", " # Dessin du toit\n", " \n", " " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Tests\n", "affiche(rue)\n", "immeuble(rue.width/3)\n", "immeuble(2*rue.width/3)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Autres tests\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Validation du module :" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%run immeuble.py" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### `rue_finale.py`\n", "\n", "#### Résultat attendu au test :\n", "\n", "\"dessiner_ma_rue-rue_finale1.png\"\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Dépendances\n", "\n", "from sol import sol\n", "from immeuble import *" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Définitions\n", "\n", "\n", "def rue_finale(canvas):\n", " \n", " # Affichage de ma rue\n", " affiche(canvas)\n", " \n", " \n", " # Dessin des immeubles\n", " \n", " \n", " \n", " # Dessin du sol de la rue\n", " \n", " " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Tests\n", "rue_finale(rue)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Autres tests\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Validation du module :" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%run rue_finale.py" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Foncionnalités supplémentaires à envisager, la file d'attente en Product BackLog :\n", "\n", "Mettons à l'épreuve notre agilité et voyons comment nous pourrions intégrer ces nouvelles fonctionnalités à notre projet...\n", "\n", "- Une voiture traverse ma rue de gauche à droite.\n", "> => utiliser des calques avec MultiCanvas ?\n", "\n", "- Le code urbanistique évolue et impose une palette de couleurs données à appliquer dans ma ville.\n", " ( En fait, le maire a reçu des remarques des automobilistes circulant dans votre rue, ils veulent bien me permettre un peu de fantaisie de couleurs mais dans des limites acceptables par mes concitoyens...)\n", "> => Chosir un type construit adapté parmi Liste, Distionnaire ou Tuple ?\n", "\n", "\n", "- Peut-on produire un croquis façon dessin à main levé de ma rue ?\n", "> => Avec le module RoughCanvas ?\n", "\n", "\n", "- Dans ma rue, il y a des immeubles qui ont des fenêtres de type oeil de boeuf, dans ce cas, toutes les fenêtres sont de ce type et alors les portes comme les portes fenêtres ont un haut arrondi.\n", "\n", "- Dans ma rue, il y a aussi des immeubles où toutes les fenêtres sont triangulaires, et dans ce cas les portes comme les portes fenêtres ont un haut triangulaire. \n", "\n", "- Mais que se passe-t'il dans ma rue lorsque la nuit tombe ? Les chats y sont-ils tous gris ??" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Ressource :\n", "\n", "Pour ipycanvas :\n", "\n", "- https://blog.jupyter.org/ipycanvas-a-python-canvas-for-jupyter-bbb51e4777f7\n", "- https://github.com/martinRenou/ipycanvas/\n", "- https://ipycanvas.readthedocs.io/en/latest/?badge=latest\n", "\n", "Pour Agile, Scrum, Design Thinking, ...\n", "\n", "- [Agilité et la méthode SCRUM - Aperçu général de la méthode et ses 3 piliers | Elephorm](https://youtu.be/RQy7nHagxK0)\n", "\n", "- [Scrum pour les nuls](https://youtu.be/kZTLlWkxFN4)\n", "\n", "- [La Gestion de Produit Agile en deux mots](https://youtu.be/3qMpB-UH9kA)\n", "\n", "- [Méthode Agile Informatique - La Minute Agile Scrum 94](https://youtu.be/9l8iFcp44y4)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "****\n", "## Références aux programmes :\n", "\n", "#### Langages et programmation\n", "\n", "|Contenus|Capacités attendues|Commentaires|\n", "|--------|-------------------|------------|\n", "|Constructions élémentaires.|Mettre en évidence un corpus de constructions élémentaires.|Séquences, affectation, conditionnelles, boucles bornées, boucles non bornées, appels de fonction.|\n", "|Spécification.|Prototyper une fonction.
Décrire les préconditions sur les arguments.
Décrire des postconditions sur les résultats.|Des assertions peuvent être utilisées pour garantir des préconditions ou des postconditions.|\n", "|Mise au point de programmes.|Utiliser des jeux de tests.|L’importance de la qualité et du nombre des tests est mise en évidence.
Le succès d’un jeu de tests ne garantit pas la correction d’un programme.|\n", "|Utilisation de bibliothèques.|Utiliser la documentation d’une bibliothèque.|Aucune connaissance exhaustive d’une bibliothèque particulière n’est exigible.|" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\"Licence
Ce document est l'adaptation d'une proposition d'Adrien WILLM et du travail de Sébastien CHANTHERY au module `ipycanvas` de [Martin RENOU](https://github.com/martinRenou) ingénieur logiciel scientifique chez [QuantStack](https://quantstack.net/index.html) avec un peu d'agilité et un workflow de développement dans un environnement jupyter. Il est mis à disposition selon les termes de la Licence Creative Commons Attribution - Partage dans les Mêmes Conditions 4.0 International.\n", "\n", "Pour toute question, suggestion ou commentaire : eric.madec@ecmorlaix.fr" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.10.1 (tags/v3.10.1:2cd268a, Dec 6 2021, 19:10:37) [MSC v.1929 64 bit (AMD64)]" }, "toc": { "base_numbering": 1, "nav_menu": {}, "number_sections": true, "sideBar": true, "skip_h1_title": false, "title_cell": "Table of Contents", "title_sidebar": "Contents", "toc_cell": false, "toc_position": {}, "toc_section_display": true, "toc_window_display": false }, "varInspector": { "cols": { "lenName": 16, "lenType": 16, "lenVar": 40 }, "kernels_config": { "python": { "delete_cmd_postfix": "", "delete_cmd_prefix": "del ", "library": "var_list.py", "varRefreshCmd": "print(var_dic_list())" }, "r": { "delete_cmd_postfix": ") ", "delete_cmd_prefix": "rm(", "library": "var_list.r", "varRefreshCmd": "cat(var_dic_list()) " } }, "types_to_exclude": [ "module", "function", "builtin_function_or_method", "instance", "_Feature" ], "window_display": false }, "vscode": { "interpreter": { "hash": "c813da0d88532624e95401f841607d640ef6d724b81c00ab0d0885f617a921c3" } } }, "nbformat": 4, "nbformat_minor": 4 }