diff --git a/recursivite/images/triangle_de_sierpinski.png b/recursivite/images/triangle_de_sierpinski.png
new file mode 100644
index 0000000000000000000000000000000000000000..ec8cd8afeb22b6726348fb34422919b2f7eea3ef
Binary files /dev/null and b/recursivite/images/triangle_de_sierpinski.png differ
diff --git a/recursivite/recursivite2.ipynb b/recursivite/recursivite2.ipynb
new file mode 100644
index 0000000000000000000000000000000000000000..d2ca17a06fac10fbb7b53d738eea65af53f60592
--- /dev/null
+++ b/recursivite/recursivite2.ipynb
@@ -0,0 +1 @@
+{"cells":[{"metadata":{},"cell_type":"markdown","source":"<h1 class=\"alert alert-success\">Complément sur la récursivité en programmation</h2>"},{"metadata":{},"cell_type":"markdown","source":"## <h2 class=\"alert alert-info\"> 1. Introduction à la récursivité</h2>\nUn algorithme récursif est un algorithme qui résout un problème en calculant des solutions d'instances plus petites du même problème. "},{"metadata":{},"cell_type":"markdown","source":"<h2 class=\"alert alert-success\"> Rappel : Algorithme pour implémenter une fonction récursive</h2>\n\n- Etape 1 - Définir le cas de base : Identifier le cas le plus simple pour lequel une solution est connue.\n\n- Etape 2 - Définir la récursion : Définir le problème en termes de plus petits sous-problèmes et appeler la fonction pour les résoudre.\n\n- Etape 3 - Définir la fin : S'assurer que la récursion va bien arriver au cas de base pour éviter d'avoir une boucle infinie."},{"metadata":{},"cell_type":"markdown","source":"<h2 class = \"alert alert-success\"> Structure d'un code récursif en python :</h2>"},{"metadata":{},"cell_type":"raw","source":"def fonction(n, ...):\n    if n==0 :\n        # code pour le cas de base\n    else :\n        # votre code où apparaîtra fonction(n-1,...)"},{"metadata":{},"cell_type":"markdown","source":"### <h2 class=\"alert alert-info\">2. Fractales : courbe de Koch Correction</h2>\n\nLa courbe de Koch est une fractale reposant sur la construction récursive suviante :\n1. Étape 1 : Tracer un segment de longueur a. \n\n![Image de losange](https://githepia.hesge.ch/info_sismondi/3AM.OS/-/raw/main/recursivite/koch_0.png)\n\n2. Étape 2 : Diviser le segment en 3 parties de même longueur. Construire un triangle équilatéral ayant pour base le segment médian de la première étape, et en supprimer la base.\n![Image de losange](https://githepia.hesge.ch/info_sismondi/3AM.OS/-/raw/main/recursivite/koch_1.png)\n\n3. Étape 3 : Reprendre l'étape 2 sur chacun des segments créés.\n![Image de losange](https://githepia.hesge.ch/info_sismondi/3AM.OS/-/raw/main/recursivite/koch_2.png)\n\n4. Et ainsi de suite...\n![Image de losange](https://githepia.hesge.ch/info_sismondi/3AM.OS/-/raw/main/recursivite/koch_3.png)"},{"metadata":{},"cell_type":"markdown","source":"On peut construire récursivement cette courbe. \n\nLa fonction de tracer prend deux paramètres en entrée :\n* la longeur $a$ du segment.\n* l'étape $n$ de \"profondeur\" de récursivité. \n\nPar exemple, à la profondeur $n=0$, on trace un simple segment : ceci constituera le cas de base et la condition d'arrêt des appels récursifs. À la profondeur $n=1$, le tracé donne la figure de l'étape 2."},{"metadata":{},"cell_type":"markdown","source":"<h2 class=\"alert alert-warning\">Courbe de Koch : fonction récursive.</h2>\n\nEn vous inspirant de la logique du code de la fonction précédente (en la \"rendant récursive\"), écrire une fonction koch(a, n) récursive qui :\n\n- prend comme paramètres un nombre entier a représentant la longueur du segment et un entier n égal au nombre de récursions souhaité.\n- construit la courbe de Koch en divisant récursivement chacun des segments\n\n*Rappel* : si n=0, le tracé est un simplement segment de longueur a."},{"metadata":{},"cell_type":"markdown","source":"<div class = \"alert alert-block alert-success\"> \n\n### Solution\n</div>"},{"metadata":{"trusted":true},"cell_type":"code","source":"import turtle as tt # import du module turtle\n\ntt.speed(10)\ntt.penup()\ntt.setposition(-300, 0) \ntt.pendown()\n\ndef koch(a, n):\n    if n == 0:\n        tt.forward(a)\n    else:\n        koch(a/3, n-1)\n        tt.left(60)\n        koch(a/3, n-1)\n        tt.right(120)\n        koch(a/3, n-1)\n        tt.left(60)\n        koch(a/3, n-1)\n\nkoch(360, 3)\n\ntt.done()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"<h2 class=\"alert alert-warning\">Flocon de Koch : fonction récursive</h2>\n\n\nPour obtenir le flocon de Koch:\n\n<figure> \n    <img title='Koch snowflake' \n         src=\"https://isquared.digital/assets/images/koch_snowflake.png\"\n         width='600px' >\n    <figcaption>Etapes 0, 1, 2, 3 et 4</figcaption>\n</figure>\n\nIl suffit d'écrire une fonction `floconkoch(a,n)` qui va itérer  `koch(a,n)` avec la bonne rotation."},{"metadata":{"trusted":true},"cell_type":"code","source":"a = 180\n\ntt.speed(10)\ntt.penup()\ntt.setposition(-a/2, a/3) \ntt.pendown()\n\n\ndef floconkoch(a, n):\n    for i in range(3):\n        koch(a, n)\n        tt.right(120)\n\n# test pour afficher l'étape 3\nflocon(a, 3)\n\ntt.penup()\ntt.home()\n\ntt.done()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### <h2 class=\"alert alert-info\">2. Fractales de Koch et perimètres </h2>\n\n1. Complétez ce code récursif pour donner le perimètre du Flocon de Koch à l'étape n.\n\n*Aidez vous de la figure ci-dessous pour comprendre l'évolution de l'aire entre deux itérations*\n![Image du triangle de sierpinski](http://img.over-blog-kiwi.com/1/93/65/56/20160116/ob_804ca5_flcon-iteration.png)"},{"metadata":{"trusted":true},"cell_type":"code","source":"def perimetreKoch(a,n):\n    if n==0 :\n        # code pour le cas de base \n        \n    else :\n        # votre code où apparaîtra fonction(n-1,...)\n        \n\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# test pour a=50, n=3\nperimetreKoch(50,3)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# test pour a=50, n=100\nperimetreKoch(50,100)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**Question:** Que peut-on déduire du périmètre du Flocon de Koch (lorsque n tend vers l'infini) ?\n\n**Réponse:** "},{"metadata":{},"cell_type":"raw","source":""},{"metadata":{},"cell_type":"markdown","source":"Pour calculer l'aire il est plus facile d'utiliser une boucle avec des variables qui comptes le nombres de triangles qu'on rajoute à chaque étape et la largeur de leur base.\n\n2. Complétez le code de la fonction pour donner l'aire du Flocon de Koch à l'étape n."},{"metadata":{"trusted":true},"cell_type":"code","source":"def aireKoch(a,n):\n    A = ...\n    l = ...\n    c = ... # le nombre de carré\n    for i in range(n):\n        A = ...\n        l = ...\n        c = ...\n        \n    return A","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# test pour a=50, n=3\naireKoch(50,3)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# test pour a=50, n=100\naireKoch(50,100)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**Question:**  Que peut-on déduire de l'aire du Flocon de Koch (lorsque n tend vers l'infini) ?\n\n**Réponse:** "},{"metadata":{"trusted":true},"cell_type":"raw","source":""},{"metadata":{},"cell_type":"markdown","source":"### <h2 class=\"alert alert-info\">3. une autre images fractale: le triangle de Sierpinski</h2>\n\nLa courbe de Koch est une fractale reposant sur la construction récursive suviante :\n\n![Image du triangle de sierpinski](https://githepia.hesge.ch/info_sismondi/3AM.OS/-/raw/main/recursivite/images/triangle_de_sierpinski.png)\n\n1. Écrire une fonction `triangle(a)` qui permet de dessiner un triangle de longeur `a`, puis une fonction `etape2(a)` qui permet de dessiner (pas de récursivité ici) la figure correspondant à l'étape 2 en utilisant la fonction `triangle(a)`.\n"},{"metadata":{"trusted":true},"cell_type":"code","source":"import turtle as tt\n\ndef triangle(a):\n    ...\n\ndef etape2(a) :\n    ...\n\n\netape2(200)\ntt.done()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"2. En vous inspirant de la logique du code de la fonction précédente (en la \"rendant récursive\"), écrire une fonction `triangle_sierpinski(a, n)` récursive qui :\n\n    - remplace les appels à triangle par des appels récursifs pour n>=1\n    - trace un simple triangle lorsque n=0\n"},{"metadata":{"trusted":true},"cell_type":"code","source":"import turtle as tt\n\n\ndef triangle_sierpinski(a, n) :\n    ...\n    \n\ntt.hideturtle()  # on cache la tortue\ntt.speed(0) # tortue rapide\n\ntriangle_sierpinski( 200 , 7)\ntt.done()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### <h2 class=\"alert alert-info\">4. Décomposition d'un entier positif en somme d'au plus quatre carrés</h2>\n\nLe théorème des quatre carrés de Lagrange affirme que tout nombre entier positif `n` peut s'écrire comme la somme d'au plus quatre carrés.\n\nPar exemple, $1871 = 1 + 25 + 81 + 1764 = 1^2 + 5^2 + 9^2 + 42^2$.\n\nPour afficher une possibilité on peut donner l'algorithme suivant qui permet de décomposer un entier positif `n` en une somme d'au plus quatre carrés.\n"},{"metadata":{},"cell_type":"markdown","source":"<div style='background-color: #f7bd83;\n    border-radius: 0.5em;\n    padding: 1em;\n    margin: 0em 2em 0em 2em'>\n\n<p><b>Algorithme de décomposition de l'entier positif <code>n</code> en une somme d'au plus quatre carrés</b></p>\n<p><b>Début</b></p>\n<p STYLE=\"padding:0 0 0 40px;\">Si <code>n</code> est le carré d'un entier alors</p>\n<p STYLE=\"padding:0 0 0 80px;\">Retourner un tableau contenant uniquement l'élément <code>n</code></p>\n    <p STYLE=\"padding:0 0 0 40px;\">Sinon</p>\n    <p STYLE=\"padding:0 0 0 80px;\"><code>liste_carres</code> ← tableau contenant la liste décroissante des nombres compris entre 1 et <code>n</code> qui sont des carrés d'entiers</p>\n<p STYLE=\"padding:0 0 0 80px;\">Pour chaque élément <code>carre</code> de <code>liste_carres</code> faire</p>\n<p STYLE=\"padding:0 0 0 120px;\"><code>decompo</code> ← liste renvoyé par <code>decomposition_carres(n - carre)</code> auquel on ajoute l'élément <code>carre</code> à la fin</p>\n<p STYLE=\"padding:0 0 0 120px;\">Si longueur(<code>decompo</code>) $\\leq$ 4 alors</p>\n<p STYLE=\"padding:0 0 0 160px;\">Retourner <code>decompo</code></p>\n    <p><b>Fin</b></p>\n        \n</div>"},{"metadata":{},"cell_type":"markdown","source":"**(1)** 💻 Définir une fonction `est_carre` qui prend en paramètre d'entrée un entier positif `n` et qui renvoie `True` si `n` est le carré d'un entier et `False` sinon."},{"metadata":{"trusted":true},"cell_type":"code","source":"def est_carre(n):\n    if ...:\n        return ...\n    else:\n        return ...","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Test\nnb = 9\nprint(nb, \"est-il un carre ? \", est_carre(nb))\nnb = 10\nprint(nb, \"est-il un carre ? \", est_carre(nb))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**(2)** 💻 Définir une fonction `liste_carres_entiers` qui prend en paramètre d'entrée un entier positif `n` et qui renvoie la liste décroissante des entiers compris entre 1 et `n` et qui sont des carrés d'entiers."},{"metadata":{"trusted":true},"cell_type":"code","source":"def liste_carres_entiers(n):\n    L = ...\n    for k in reversed(...):\n        if ...:\n            ...\n    return L","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Test\nlistes_carres = liste_carres_entiers(100)\nprint(listes_carres) # doit afficher [100, 81, 64, 49, 36, 25, 16, 9, 4, 1]","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**(3)** 💻 Implémenter la fonction `decomposition_carres` qui prend en paramètre d'entrée un entier positif `n` et qui renvoie, sous forme de tableau de longueur inférieure ou égale à 4, une décomposition de `n` en somme de carrés d'entiers."},{"metadata":{"trusted":true},"cell_type":"code","source":"def decomposition_carres(n):\n    ...","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Test\nnb = 1871\nprint(\"La décomposition de \",nb, \"est : \", decomposition_carres(nb))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**(4)** ✏️ Donner une décomposition en somme d'au plus quatre carrés pour les entiers $300$, $1789$, $2021$ et $12345$."},{"metadata":{"trusted":true},"cell_type":"code","source":"","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**(5)** ✏️ Proposer une fonction non récursive `decomposition_carres2(n)` qui permet de calculer la décomposition et tester la fonction"},{"metadata":{"trusted":true},"cell_type":"code","source":"def decomposition_carres2(n):\n    listes_carres = ...\n    for ...:\n        for ...:\n            for ...:\n                for ...:\n                    if ... :\n                        return ...","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Test\nnb = 1871\nprint(\"La décomposition de \",nb, \"est : \", decomposition_carres2(nb))","execution_count":null,"outputs":[]}],"metadata":{"kernelspec":{"display_name":"Python 3.8.1 64-bit ('python38': conda)","language":"python","name":"python38164bitpython38conda56991d5ad1414e06a4dcd344400cf456"}},"nbformat":4,"nbformat_minor":2}
\ No newline at end of file
diff --git a/recursivite/recursivite2_corrige.ipynb b/recursivite/recursivite2_corrige.ipynb
new file mode 100644
index 0000000000000000000000000000000000000000..1f9067c3e35a174cae3158d6a5881288d7fff026
--- /dev/null
+++ b/recursivite/recursivite2_corrige.ipynb
@@ -0,0 +1 @@
+{"cells":[{"metadata":{},"cell_type":"markdown","source":"<h1 class=\"alert alert-success\">Complément sur la récursivité en programmation</h2>"},{"metadata":{},"cell_type":"markdown","source":"## <h2 class=\"alert alert-info\"> 1. Introduction à la récursivité</h2>\nUn algorithme récursif est un algorithme qui résout un problème en calculant des solutions d'instances plus petites du même problème. "},{"metadata":{},"cell_type":"markdown","source":"<h2 class=\"alert alert-success\"> Rappel : Algorithme pour implémenter une fonction récursive</h2>\n\n- Etape 1 - Définir le cas de base : Identifier le cas le plus simple pour lequel une solution est connue.\n\n- Etape 2 - Définir la récursion : Définir le problème en termes de plus petits sous-problèmes et appeler la fonction pour les résoudre.\n\n- Etape 3 - Définir la fin : S'assurer que la récursion va bien arriver au cas de base pour éviter d'avoir une boucle infinie."},{"metadata":{},"cell_type":"markdown","source":"<h2 class = \"alert alert-success\"> Structure d'un code récursif en python :</h2>"},{"metadata":{},"cell_type":"raw","source":"def fonction(n, ...):\n    if n==0 :\n        # code pour le cas de base\n    else :\n        # votre code où apparaîtra fonction(n-1,...)"},{"metadata":{},"cell_type":"markdown","source":"### <h2 class=\"alert alert-info\">2. Fractales : courbe de Koch Correction</h2>\n\nLa courbe de Koch est une fractale reposant sur la construction récursive suviante :\n1. Étape 1 : Tracer un segment de longueur a. \n\n![Image de losange](https://githepia.hesge.ch/info_sismondi/3AM.OS/-/raw/main/recursivite/koch_0.png)\n\n2. Étape 2 : Diviser le segment en 3 parties de même longueur. Construire un triangle équilatéral ayant pour base le segment médian de la première étape, et en supprimer la base.\n![Image de losange](https://githepia.hesge.ch/info_sismondi/3AM.OS/-/raw/main/recursivite/koch_1.png)\n\n3. Étape 3 : Reprendre l'étape 2 sur chacun des segments créés.\n![Image de losange](https://githepia.hesge.ch/info_sismondi/3AM.OS/-/raw/main/recursivite/koch_2.png)\n\n4. Et ainsi de suite...\n![Image de losange](https://githepia.hesge.ch/info_sismondi/3AM.OS/-/raw/main/recursivite/koch_3.png)"},{"metadata":{},"cell_type":"markdown","source":"On peut construire récursivement cette courbe. \n\nLa fonction de tracer prend deux paramètres en entrée :\n* la longeur $a$ du segment.\n* l'étape $n$ de \"profondeur\" de récursivité. \n\nPar exemple, à la profondeur $n=0$, on trace un simple segment : ceci constituera le cas de base et la condition d'arrêt des appels récursifs. À la profondeur $n=1$, le tracé donne la figure de l'étape 2."},{"metadata":{},"cell_type":"markdown","source":"<h2 class=\"alert alert-warning\">Courbe de Koch : fonction récursive.</h2>\n\nEn vous inspirant de la logique du code de la fonction précédente (en la \"rendant récursive\"), écrire une fonction koch(a, n) récursive qui :\n\n- prend comme paramètres un nombre entier a représentant la longueur du segment et un entier n égal au nombre de récursions souhaité.\n- construit la courbe de Koch en divisant récursivement chacun des segments\n\n*Rappel* : si n=0, le tracé est un simplement segment de longueur a."},{"metadata":{},"cell_type":"markdown","source":"<div class = \"alert alert-block alert-success\"> \n\n### Solution\n</div>"},{"metadata":{"trusted":true},"cell_type":"code","source":"import turtle as tt # import du module turtle\n\ntt.speed(10)\ntt.penup()\ntt.setposition(-300, 0) \ntt.pendown()\n\ndef koch(a, n):\n    if n == 0:\n        tt.forward(a)\n    else:\n        koch(a/3, n-1)\n        tt.left(60)\n        koch(a/3, n-1)\n        tt.right(120)\n        koch(a/3, n-1)\n        tt.left(60)\n        koch(a/3, n-1)\n\nkoch(360, 3)\n\ntt.done()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"<h2 class=\"alert alert-warning\">Flocon de Koch : fonction récursive</h2>\n\n\nPour obtenir le flocon de Koch:\n\n<figure> \n    <img title='Koch snowflake' \n         src=\"https://isquared.digital/assets/images/koch_snowflake.png\"\n         width='600px' >\n    <figcaption>Etapes 0, 1, 2, 3 et 4</figcaption>\n</figure>\n\nIl suffit d'écrire une fonction `floconkoch(a,n)` qui va itérer  `koch(a,n)` avec la bonne rotation."},{"metadata":{"trusted":true},"cell_type":"code","source":"a = 180\n\ntt.speed(10)\ntt.penup()\ntt.setposition(-a/2, a/3) \ntt.pendown()\n\n\ndef floconkoch(a, n):\n    for i in range(3):\n        koch(a, n)\n        tt.right(120)\n\n# test pour afficher l'étape 3\nflocon(a, 3)\n\ntt.penup()\ntt.home()\n\ntt.done()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### <h2 class=\"alert alert-info\">2. Fractales de Koch et perimètres </h2>\n\n1. Complétez ce code récursif pour donner le perimètre du Flocon de Koch à l'étape n.\n\n*Aidez vous de la figure ci-dessous pour comprendre l'évolution de l'aire entre deux itérations*\n![Image du triangle de sierpinski](http://img.over-blog-kiwi.com/1/93/65/56/20160116/ob_804ca5_flcon-iteration.png)"},{"metadata":{"trusted":true},"cell_type":"code","source":"def perimetreKoch(a,n):\n    if n==0 :\n        # code pour le cas de base \n        return 3*a\n    else :\n        # votre code où apparaîtra fonction(n-1,...)\n        return (4/3)*perimetreKoch(a,n-1)\n\n","execution_count":51,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# test pour a=50, n=3\nperimetreKoch(50,3)","execution_count":52,"outputs":[{"output_type":"execute_result","execution_count":52,"data":{"text/plain":"355.5555555555555"},"metadata":{}}]},{"metadata":{"trusted":true},"cell_type":"code","source":"# test pour a=50, n=100\nperimetreKoch(50,100)","execution_count":53,"outputs":[{"output_type":"execute_result","execution_count":53,"data":{"text/plain":"467697361531188.8"},"metadata":{}}]},{"metadata":{},"cell_type":"markdown","source":"**Question:** Que peut-on déduire du périmètre du Flocon de Koch (lorsque n tend vers l'infini) ?\n\n**Réponse:** "},{"metadata":{},"cell_type":"raw","source":""},{"metadata":{},"cell_type":"markdown","source":"Pour calculer l'aire il est plus facile d'utiliser une boucle avec des variables qui comptes le nombres de triangles qu'on rajoute à chaque étape et la largeur de leur base.\n\n2. Complétez le code de la fonction pour donner l'aire du Flocon de Koch à l'étape n."},{"metadata":{"trusted":true},"cell_type":"code","source":"def aireKoch(a,n):\n    A = (3**0.5 / 4 * a**2)\n    l = a / 3\n    c = 3 # le nombre de carré\n    for i in range(n):\n        A = A + c * (3**0.5 / 4 * l**2)\n        l = l / 3\n        c = c * 3\n        \n    return A","execution_count":55,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# test pour a=50, n=3\naireKoch(50,3)","execution_count":56,"outputs":[{"output_type":"execute_result","execution_count":56,"data":{"text/plain":"1603.7507477489605"},"metadata":{}}]},{"metadata":{"trusted":true},"cell_type":"code","source":"# test pour a=50, n=100\naireKoch(50,100)","execution_count":57,"outputs":[{"output_type":"execute_result","execution_count":57,"data":{"text/plain":"1623.7976320958232"},"metadata":{}}]},{"metadata":{},"cell_type":"markdown","source":"**Question:**  Que peut-on déduire de l'aire du Flocon de Koch (lorsque n tend vers l'infini) ?\n\n**Réponse:** "},{"metadata":{"trusted":true},"cell_type":"raw","source":""},{"metadata":{},"cell_type":"markdown","source":"### <h2 class=\"alert alert-info\">3. une autre images fractale: le triangle de Sierpinski</h2>\n\nLa courbe de Koch est une fractale reposant sur la construction récursive suviante :\n\n![Image du triangle de sierpinski](https://githepia.hesge.ch/info_sismondi/3AM.OS/-/raw/main/recursivite/images/triangle_de_sierpinski.png)\n\n1. Écrire une fonction `triangle(a)` qui permet de dessiner un triangle de longeur `a`, puis une fonction `etape2(a)` qui permet de dessiner (pas de récursivité ici) la figure correspondant à l'étape 2 en utilisant la fonction `triangle(a)`.\n"},{"metadata":{"trusted":true},"cell_type":"code","source":"import turtle as tt\n\ndef triangle(a):\n    for _ in range(3) :\n        tt.forward(a)\n        tt.left(120)\n\ndef etape2(a) :\n    for _ in range(3) :\n        triangle(a/2)\n        tt.forward(a)\n        tt.left(120)\n\n\netape2(200)\ntt.done()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"2. En vous inspirant de la logique du code de la fonction précédente (en la \"rendant récursive\"), écrire une fonction `triangle_sierpinski(a, n)` récursive qui :\n\n    - remplace les appels à triangle par des appels récursifs pour n>=1\n    - trace un simple triangle lorsque n=0\n"},{"metadata":{"trusted":true},"cell_type":"code","source":"import turtle as tt\n\n\ndef triangle_sierpinski(a, n) :\n    if n > 0 :\n        for _ in range(3) :\n            triangle_sierpinski(a/2, n-1)\n            tt.forward(a)\n            tt.left(120)\n\ntt.hideturtle()  # on cache la tortue\ntt.speed(0) # tortue rapide\n\ntriangle_sierpinski( 200 , 7)\ntt.done()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### <h2 class=\"alert alert-info\">4. Décomposition d'un entier positif en somme d'au plus quatre carrés</h2>\n\nLe théorème des quatre carrés de Lagrange affirme que tout nombre entier positif `n` peut s'écrire comme la somme d'au plus quatre carrés.\n\nPar exemple, $1871 = 1 + 25 + 81 + 1764 = 1^2 + 5^2 + 9^2 + 42^2$.\n\nPour afficher une possibilité on peut donner l'algorithme suivant qui permet de décomposer un entier positif `n` en une somme d'au plus quatre carrés.\n"},{"metadata":{},"cell_type":"markdown","source":"<div style='background-color: #f7bd83;\n    border-radius: 0.5em;\n    padding: 1em;\n    margin: 0em 2em 0em 2em'>\n\n<p><b>Algorithme de décomposition de l'entier positif <code>n</code> en une somme d'au plus quatre carrés</b></p>\n<p><b>Début</b></p>\n<p STYLE=\"padding:0 0 0 40px;\">Si <code>n</code> est le carré d'un entier alors</p>\n<p STYLE=\"padding:0 0 0 80px;\">Retourner un tableau contenant uniquement l'élément <code>n</code></p>\n    <p STYLE=\"padding:0 0 0 40px;\">Sinon</p>\n    <p STYLE=\"padding:0 0 0 80px;\"><code>liste_carres</code> ← tableau contenant la liste décroissante des nombres compris entre 1 et <code>n</code> qui sont des carrés d'entiers</p>\n<p STYLE=\"padding:0 0 0 80px;\">Pour chaque élément <code>carre</code> de <code>liste_carres</code> faire</p>\n<p STYLE=\"padding:0 0 0 120px;\"><code>decompo</code> ← liste renvoyé par <code>decomposition_carres(n - carre)</code> auquel on ajoute l'élément <code>carre</code> à la fin</p>\n<p STYLE=\"padding:0 0 0 120px;\">Si longueur(<code>decompo</code>) $\\leq$ 4 alors</p>\n<p STYLE=\"padding:0 0 0 160px;\">Retourner <code>decompo</code></p>\n    <p><b>Fin</b></p>\n        \n</div>"},{"metadata":{},"cell_type":"markdown","source":"**(1)** 💻 Définir une fonction `est_carre` qui prend en paramètre d'entrée un entier positif `n` et qui renvoie `True` si `n` est le carré d'un entier et `False` sinon."},{"metadata":{"trusted":true},"cell_type":"code","source":"def est_carre(n):\n    if round(n**0.5)**2 == n:\n        return True\n    else:\n        return False","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Test\nnb = 9\nprint(nb, \"est-il un carre ? \", est_carre(nb))\nnb = 10\nprint(nb, \"est-il un carre ? \", est_carre(nb))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**(2)** 💻 Définir une fonction `liste_carres_entiers` qui prend en paramètre d'entrée un entier positif `n` et qui renvoie la liste décroissante des entiers compris entre 1 et `n` et qui sont des carrés d'entiers."},{"metadata":{"trusted":true},"cell_type":"code","source":"def liste_carres_entiers(n):\n    L = []\n    for k in reversed(range(1, n+1)):\n        if est_carre(k):\n            L.append(k)\n    return L","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Test\nlistes_carres = liste_carres_entiers(100)\nprint(listes_carres) # doit afficher [100, 81, 64, 49, 36, 25, 16, 9, 4, 1]","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**(3)** 💻 Implémenter la fonction `decomposition_carres` qui prend en paramètre d'entrée un entier positif `n` et qui renvoie, sous forme de tableau de longueur inférieure ou égale à 4, une décomposition de `n` en somme de carrés d'entiers."},{"metadata":{"trusted":true},"cell_type":"code","source":"def decomposition_carres(n):\n    if est_carre(n):\n        return [n]\n    else:\n        listes_carres = liste_carres_entiers(n)\n        for carre in listes_carres:\n            decompo = decomposition_carres(n - carre) + [carre]\n            if len(decompo) <= 4:\n                return decompo","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Test\nnb = 1871\nprint(\"La décomposition de \",nb, \"est : \", decomposition_carres(nb))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**(4)** ✏️ Donner une décomposition en somme d'au plus quatre carrés pour les entiers $300$, $1789$, $2021$ et $12345$."},{"metadata":{"trusted":true},"cell_type":"code","source":"def print_decompoision(n, decompo):\n    s = str(n)+ \" = \"\n    for n in decompo:\n        s = s + str(int(n**0.5))+\"² + \"\n    s = s[:-3]\n    print(s)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"nb = 1871\nprint_decompoision(nb, decomposition_carres(nb))\nnb = 300\nprint_decompoision(nb, decomposition_carres(nb))\nnb = 1789\nprint_decompoision(nb, decomposition_carres(nb))\nnb = 2021\nprint_decompoision(nb, decomposition_carres(nb))\nnb = 12345\nprint_decompoision(nb, decomposition_carres(nb))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**(5)** ✏️ Proposer une fonction non récursive `decomposition_carres2(n)` qui permet de calculer la décomposition et tester la fonction"},{"metadata":{"trusted":true},"cell_type":"code","source":"def decomposition_carres2(n):\n    listes_carres = liste_carres_entiers(n)\n    listes_carres = listes_carres + [0]\n    for carre1 in listes_carres:\n        for carre2 in listes_carres:\n            for carre3 in listes_carres:\n                for carre4 in listes_carres:\n                    if carre1 + carre2 +carre3 +carre4 ==n :\n                        return [carre1, carre2, carre3, carre4]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"nb = 1871\nprint_decompoision(nb, decomposition_carres2(nb))\nnb = 300\nprint_decompoision(nb, decomposition_carres2(nb))\nnb = 1789\nprint_decompoision(nb, decomposition_carres2(nb))\nnb = 2021\nprint_decompoision(nb, decomposition_carres2(nb))\nnb = 12345\nprint_decompoision(nb, decomposition_carres2(nb))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"","execution_count":null,"outputs":[]}],"metadata":{"kernelspec":{"display_name":"Python 3.8.1 64-bit ('python38': conda)","language":"python","name":"python38164bitpython38conda56991d5ad1414e06a4dcd344400cf456"}},"nbformat":4,"nbformat_minor":2}
\ No newline at end of file
diff --git a/recursivite/recursivite_corrige.ipynb b/recursivite/recursivite_corrige.ipynb
index 26b02f29f18896a99074ff2a6b39615faf4a1235..e11d07fc1abb1414f31dc45200575dbca66a1c8d 100644
--- a/recursivite/recursivite_corrige.ipynb
+++ b/recursivite/recursivite_corrige.ipynb
@@ -1 +1 @@
-{"cells":[{"metadata":{},"cell_type":"markdown","source":"<h1 class=\"alert alert-success\">Récursivité </h2>"},{"metadata":{},"cell_type":"markdown","source":"<h2 class=\"alert alert-info\"> 1. Introduction </h2>\n\nLa **récursivité** est un concept qui est très proche de la notion mathématiques de la récurrence. On dit qu’une fonction est récursive si elle s’appelle elle-même.\nPour résoudre un problème ou effectuer un calcul, on se ramène à la résolution d’un problème similaire mais de complexité moindre. On recommence ainsi jusqu’à obtenir un problème élémentaire que l’on sait résoudre. \n\n!!! note Définition\nOn qualifie de **récursive** toute fonction qui s'appelle elle-même.\n!!!\n\nLa plus-part des langages de programmation actuels permettent de mettre en œuvre directement cette réduction du problème, en autorisant une fonction à s’appeler elle-même : on parle alors de fonction récursive. On trouvera souvent deux versions possibles d'un même programme : itérative et récursive.\n\nCependant deux éléments sont indispensables à la terminaison d’une fonction récursive :\n\n- il est nécessaire qu’il y ait une condition d’arrêt ;\n- il ne doit pas y avoir de suite infinie d’appels récursifs.\n\n### Exemple\nOn souhaite calculer la somme $S=\\sum_{i=1}^n i =1 +2+3+\\cdots+(n-1) + n$. Ci-dessous une fonction recursive qui calcule la somme des $n$ premiers termes dont on peut visualiser les appels"},{"metadata":{"trusted":true,"scrolled":false},"cell_type":"code","source":"from rcviz import viz # pour visualiser les appels \n@viz\ndef somme(n):\n    if n < 1:\n        return 0\n    else:\n        return n + somme(n - 1)\n\nsomme(4) # calcule 1 + 2 + 3 + 4","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Un sous-programme est dit récursif s’il fait appel à lui-même, comme ici.\nDétaillons la procédure compte :\n\n- Pour calculer la somme des `n` termes, on dépcompose le problème comme calculer la somme des `n-1` termes plus `n`;\n- le test `n < 0` est une condition d’arrêt, obligatoire sinon le sous-programme peut boucler indéfiniment;\n- les appels récursifs continuent jusqu’à ce que le paramètre passé à la procédure prenne la valeur 0;\n- la dernière valeur retournée est donc 0.\n\nOn peut visualiser les appels avec :"},{"metadata":{"trusted":true,"scrolled":false},"cell_type":"code","source":"somme.callgraph() # pour visualiser les appels récusifs","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"!!! danger Attention\nOn remarque qu'il est possible d'exécuter cette fonction avec un paramètre qui n'est pas un entier positif. Pour interdire ce cas de figure on peut utiliser l'instruction `assert` :\n!!!\n"},{"metadata":{"trusted":true,"scrolled":false},"cell_type":"code","source":"def somme(n):\n    assert n >= 0 and isinstance(n, int), \"n doit être un entier naturel\"\n    if n < 1:\n        return 0\n    else:\n        return n + somme(n - 1)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"scrolled":false},"cell_type":"code","source":"somme(-2)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"scrolled":false},"cell_type":"code","source":"somme(2.8)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"scrolled":false},"cell_type":"code","source":"somme(8)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"<h3 style=\"color:teal;background-color:azure;\" > <i class=\"fa fa-pencil\" aria-hidden=\"true\"> </i> &nbsp; Exercice 1 : Somme des éléments d'une liste </h3>\n\nEcrire une fonction récursive ```somme_liste``` qui :\n\n- prend en paramètre une liste d'entiers `L`\n- retourne la somme des éléments de la liste `L`\n\n\n**Coup de pouce :** \n\n*Condition d'arrêt* : si la liste est vide, la somme de ses élément vaut 0 : donc la fonction renvoie 0.\n\n*Récursion* : renvoyer la valeur du 1er élément additionnée de la somme du reste de la liste."},{"metadata":{"trusted":true,"scrolled":false},"cell_type":"code","source":"def somme_liste(L):\n    if len(L) <= 0:\n        return 0\n    else:\n        return L[0] + somme_liste(L[1:])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"scrolled":false},"cell_type":"code","source":"# test \ntab = [5, 4, 7, 2]\nsomme_liste(tab)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"<h3 style=\"color:teal;background-color:azure;\" > <i class=\"fa fa-pencil\" aria-hidden=\"true\"> </i> &nbsp; Exercice 2 : Miroir d’une chaîne de caractère </h3>\n\nÉcrire une fonction ```miroir``` récursive qui :\n\n- prend comme paramètre une chaîne de caractères `s`\n- renvoie le « miroir » de la chaîne; par exemple, le miroir de \"abcde\" est \"edcba\".\n\n\n**Coup de pouce :** \n\n*Condition d'arrêt* : si la chaine contient un seul caractère ou aucun, son miroir est elle-même.\n\n*Récursion* : Le principe consiste à permutter le 1er et le dernier carcatère, et à recopier le miroir  de la sous-chaine interne (entre le 2ème caractère et l'avant-dernier) au milieu de ces 2 caractères. Il faut donc renvoyer une chaine qui est la concaténation du dernier caratère, du miroir de la sous-chaine interne, et du 1er caractère.\n\n**Aide** : on pourra utiliser la syntaxe `s[1:-1]` qui permet d'extraire une sous-chaine de caractères entre le second élément de l'avant dernier, et `s[0]`, respectivement `s[-1]`,  pour accéder au premier, respectivement dernier, élément"},{"metadata":{"trusted":true,"scrolled":false},"cell_type":"code","source":"def miroir(s):\n    if len(s) <= 1:\n        return s\n    else:\n        return s[-1] + miroir(s[1:-1]) + s[1]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"scrolled":false},"cell_type":"code","source":"# test\nchaine = 'quelle belle chaine'\nmiroir(chaine)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"<h2 class=\"alert alert-info\">2. Rappels sur Turtle</h2>\n\nTurtle est un module Python permettant de dessiner sur un canevas. Le crayon est dirigé par une tortue !\n\nJupyter propose une implémentation de ce module (très légèrement modifié). Les commandes principales consistent à positionner la tortue, lever ou baisser le crayon (pour écrire ou non lorsque la tortue se déplace) et à commander les mouvements de la tortue (avancer/reculer, tourner à gauche/droite d'un certain angle).\n\nPour mieux comprendre et découvrir les commandes accessibles, étudier l'exemple de démonstration ci-dessous :"},{"metadata":{"trusted":true,"scrolled":false},"cell_type":"code","source":"import turtle as tt # import du module turtle\n\ntt.speed(3)         # vitesse moyenne (maxi = 10)\n\ntt.penup()          # lève le crayon (pour ne pas écrire pendant le déplacement)\ntt.setposition(-100, 100) \n# origine (0, 0) au centre du cadre de dessin (dimensions 600x600)\ntt.pendown()        # abaisse le crayon (pour voir la trace de la tortue)\n\ntt.forward(20)      # avance de 20\ntt.left(60)         # virage de 60° vers la gauche\ntt.forward(100)    \ntt.right(120)       # virage de 120° vers la droite\ntt.pencolor(\"red\")  # couleurs autorisées  \"blue\", \"yellow\", \"brown\", \"black\", \"purple\", \"green\"\ntt.forward(100)  \ntt.left(60)       \ntt.forward(100)     # recule de 100\ntt.backward(70)  \ntt.right(90)   \ntt.pencolor(\"green\")  \ntt.forward(300)  \n\ntt.penup()\ntt.home()           # retour à l'origine\n\ntt.done()           # indispensable pour activer la tortue dans Basthon","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"scrolled":false},"cell_type":"code","source":"# 2ème exemple :\n\nimport turtle as tt # import du module turtle\n\n\ncouleurs = [\"red\", \"blue\", \"yellow\", \"brown\", \"black\", \"purple\", \"green\"]\n\ntt.speed(10)\n\nfor i in range(7):\n    tt.penup()\n    tt.setposition(-200+50*i, 0)\n    tt.pendown()\n    tt.pencolor(couleurs[i])\n    for j in range(4):\n        tt.forward(30)\n        tt.left(90)\n        \ntt.done()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**Pour résumer:**\n\n| Fonction |Exemple|Commentaire|\n|:-------- |:------|:----------|\n|forward(x)|forward(150)|Trace un trait de 150 points|\n|backward(x)|backward(150)|Trace un trait “à reculons” de 150 points|\n|left(n)|left(60)|Tourne sur place la tortue de 60° à gauche|\n|right(n)|right(60)|Tourne sur place la tortue de 60° à droite|\n|setposition(x, y) |setposition(-100, 100)|va à la position (-100,100) sachant que l'origine (0;0) est au centre du cadre de dessin (dimensions 600x600)|\n|width(x)|width(5)|Change l’épaisseur à 5 points|\n|color(\"c\")|color(\"yellow\")|Change la couleur du trait (mais aucun trait n’est tracé à ce moment). Notez les guillemets !|\n|penup()|penup()|Lève la tortue (permet de se déplacer sans dessiner)|\n|pendown()|pendown()|Baisse le stylo|\n|home()|home()|retour à l'origine|"},{"metadata":{},"cell_type":"markdown","source":"<h2 class=\"alert alert-info\">3. Fractales : courbe de Koch</h2>\n\nLa courbe de Koch est une fractale reposant sur la construction récursive suviante :\n1. Étape 1 : Tracer un segment de longueur a. \n\n![Image de losange](https://githepia.hesge.ch/info_sismondi/3AM.OS/-/raw/main/recursivite/koch_0.png)\n\n2. Étape 2 : Diviser le segment en 3 parties de même longueur. Construire un triangle équilatéral ayant pour base le segment médian de la première étape, et en supprimer la base.\n![Image de losange](https://githepia.hesge.ch/info_sismondi/3AM.OS/-/raw/main/recursivite/koch_1.png)\n\n3. Étape 3 : Reprendre l'étape 2 sur chacun des segments créés.\n![Image de losange](https://githepia.hesge.ch/info_sismondi/3AM.OS/-/raw/main/recursivite/koch_2.png)\n\n4. Et ainsi de suite...\n![Image de losange](https://githepia.hesge.ch/info_sismondi/3AM.OS/-/raw/main/recursivite/koch_3.png)\n"},{"metadata":{},"cell_type":"markdown","source":"On peut construire récursivement cette courbe. \n\nLa fonction de tracer prend deux paramètres en entrée :\n* la longeur $a$ du segment.\n* l'étape $n$ de \"profondeur\" de récursivité. \n\nPar exemple, à la profondeur $n=0$, on trace un simple segment : ceci constituera la condition d'arrêt des appels récursifs. À la profondeur $n=1$, le tracé donne la figure de l'étape 2."},{"metadata":{},"cell_type":"markdown","source":"<h3 style=\"color:teal;background-color:azure;\" > <i class=\"fa fa-pencil\" aria-hidden=\"true\"> </i> &nbsp; Exercice 3 : Faire l'étape 2 </h3>\n\n\n1. Écrire une fonction `etape2(a)` qui permet de dessiner avec la tortue (pas de récursivité ici) la figure correspondant à l'étape 2 (décrite ci-avant).\n"},{"metadata":{"trusted":true,"scrolled":false},"cell_type":"code","source":"import turtle as tt # import du module turtle\ntt.speed(10) # pour dessiner plus rapidement\n\ndef etape2(a):\n    tt.forward(a)\n    tt.left(60)\n    tt.forward(a)\n    tt.right(120)\n    tt.forward(a)\n    tt.left(60)\n    tt.forward(a)\n    \n# test:\na = 50\netape2(a)\n\ntt.done()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"2. En vous inspirant de la logique du code de la fonction précédente (en la \"rendant récursive\"), écrire une fonction koch(a, n) récursive qui :\n\n    - prend comme paramètres un nombre entier a représentant la longueur du segment et un entier n égal au nombre de récursions souhaité.\n    - construit la courbe de Koch en divisant récursivement chacun des segments\n\n    *Rappel* : si n=0, le tracé est un simplement segment de longueur a."},{"metadata":{"trusted":true,"scrolled":false},"cell_type":"code","source":"import turtle as tt # import du module turtle\n\ntt.speed(10)\ntt.penup()\ntt.setposition(-300, 0) \ntt.pendown()\n\ndef koch(a, n):\n    if n == 0 :\n        tt.forward(a)\n    else:\n        koch(a/3, n-1)\n        tt.left(60)\n        koch(a/3, n-1)\n        tt.right(120)\n        koch(a/3, n-1)\n        tt.left(60)\n        koch(a/3, n-1)\n\nkoch(360, 4)\n\ntt.done()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"<h2 class=\"alert alert-info\">Et pour s'amuser encore un peu...</h2>\nExécuter le code ci-dessous :"},{"metadata":{"trusted":true,"scrolled":false},"cell_type":"code","source":"a = 180\n\ntt.speed(10)\ntt.penup()\ntt.setposition(-a/2, a/3) \ntt.pendown()\n\ndef flocon(a, n):\n    for i in range(3):\n        koch(a, n)\n        tt.right(120)\n        \nflocon(a, 3)\n\ntt.penup()\ntt.home()\n\ntt.done()","execution_count":null,"outputs":[]},{"metadata":{"trusted":false},"cell_type":"markdown","source":"---\n\n#### Remarque générale\n\nUne partie de ce notebook reprend le cours sur la récursivité du lycée Faustin Flerettiré http://nsinfo.yo.fr/nsi_term_programmation_recursivite.html. Le notebook est sous license Creative Commons [BY-NC-SA](https://creativecommons.org/licenses/?lang=fr)\n![Licence Creative Commons](https://i.creativecommons.org/l/by-nc-sa/4.0/88x31.png)"}],"metadata":{"kernelspec":{"display_name":"Python 3.8.1 64-bit ('python38': conda)","language":"python","name":"python38164bitpython38conda56991d5ad1414e06a4dcd344400cf456"}},"nbformat":4,"nbformat_minor":2}
\ No newline at end of file
+{"cells":[{"metadata":{},"cell_type":"markdown","source":"<div class = \"alert  alert-danger\"> \n    \n# Cours avec solution\n    \nCliquez sur **Exécuter tout** Dans le menu **Cellule**\n</div>"},{"metadata":{},"cell_type":"markdown","source":"<h1 class=\"alert alert-success\">Récursivité </h2>"},{"metadata":{},"cell_type":"markdown","source":"<h2 class=\"alert alert-info\"> 1. Introduction </h2>\n\nLa **récursivité** est un concept qui est très proche de la notion mathématiques de la récurrence. On dit qu’une fonction est récursive si elle s’appelle elle-même.\nPour résoudre un problème ou effectuer un calcul, on se ramène à la résolution d’un problème similaire mais de complexité moindre. On recommence ainsi jusqu’à obtenir un problème élémentaire que l’on sait résoudre. \n\n!!! note Définition\nOn qualifie de **récursive** toute fonction qui s'appelle elle-même.\n!!!\n\nLa plus-part des langages de programmation actuels permettent de mettre en œuvre directement cette réduction du problème, en autorisant une fonction à s’appeler elle-même : on parle alors de fonction récursive. On trouvera souvent deux versions possibles d'un même programme : itérative et récursive.\n\nCependant deux éléments sont indispensables à la terminaison d’une fonction récursive :\n\n- il est nécessaire qu’il y ait une condition d’arrêt ;\n- il ne doit pas y avoir de suite infinie d’appels récursifs.\n\n### Exemple\nOn souhaite calculer la somme $S=\\sum_{i=1}^n i =1 +2+3+\\cdots+(n-1) + n$. Ci-dessous une fonction recursive qui calcule la somme des $n$ premiers termes dont on peut visualiser les appels"},{"metadata":{"trusted":true,"scrolled":true},"cell_type":"code","source":"from rcviz import viz # pour visualiser les appels \n@viz\ndef somme(n):\n    if n < 1:\n        return 0\n    else:\n        return n + somme(n - 1)\n\nsomme(4) # calcule 1 + 2 + 3 + 4","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Un sous-programme est dit récursif s’il fait appel à lui-même, comme ici.\nDétaillons la procédure compte :\n\n- Pour calculer la somme des `n` termes, on dépcompose le problème comme calculer la somme des `n-1` termes plus `n`;\n- le test `n < 0` est une condition d’arrêt, obligatoire sinon le sous-programme peut boucler indéfiniment;\n- les appels récursifs continuent jusqu’à ce que le paramètre passé à la procédure prenne la valeur 0;\n- la dernière valeur retournée est donc 0.\n\nOn peut visualiser les appels avec :"},{"metadata":{"trusted":true,"scrolled":false},"cell_type":"code","source":"somme.callgraph() # pour visualiser les appels récusifs","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"!!! danger Attention\nOn remarque qu'il est possible d'exécuter cette fonction avec un paramètre qui n'est pas un entier positif. Pour interdire ce cas de figure on peut utiliser l'instruction `assert` :\n!!!\n"},{"metadata":{"trusted":true,"scrolled":true},"cell_type":"code","source":"def somme(n):\n    assert n >= 0 and isinstance(n, int), \"n doit être un entier naturel\"\n    if n < 1:\n        return 0\n    else:\n        return n + somme(n - 1)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"scrolled":true},"cell_type":"code","source":"somme(-2)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"scrolled":false},"cell_type":"code","source":"somme(2.8)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"scrolled":true},"cell_type":"code","source":"somme(8)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"<h3 style=\"color:teal;background-color:azure;\" > <i class=\"fa fa-pencil\" aria-hidden=\"true\"> </i> &nbsp; Exercice 1 : Somme des éléments d'une liste </h3>\n\nEcrire une fonction récursive ```somme_liste``` qui :\n\n- prend en paramètre une liste d'entiers `L`\n- retourne la somme des éléments de la liste `L`\n\n\n**Coup de pouce :** \n\n*Condition d'arrêt* : si la liste contient un seul élément, la somme de ses élément vaut la valeur de cet élément : donc la fonction renvoie ce nombre.\n\n*Récursion* : renvoyer la valeur du 1er élément additionnée de la somme du reste de la liste."},{"metadata":{},"cell_type":"markdown","source":"<div class = \"alert alert-block alert-warning\"> \n\n### Solution\n</div>"},{"metadata":{"trusted":true,"scrolled":true},"cell_type":"code","source":"# V1\ndef somme_liste(L):\n    if len(L)==1:\n        return L[0]\n    else:\n        S = L[0] + somme_liste(L[1:])\n        return S","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"scrolled":true},"cell_type":"code","source":"# test \ntab = [5, 4, 7, 2]\nsomme_liste(tab) # la fonction doit renvoyer : 18","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"scrolled":true},"cell_type":"code","source":"# V2\ndef somme_liste(L):\n    if len(L)==0:\n        return 0\n    else:\n        S = L[0] + somme_liste(L[1:])\n        return S","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"scrolled":true},"cell_type":"code","source":"# test \ntab = [5, 4, 7, 2]\nsomme_liste(tab) # la fonction doit renvoyer : 18","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"<h3 style=\"color:teal;background-color:azure;\" > <i class=\"fa fa-pencil\" aria-hidden=\"true\"> </i> &nbsp; Exercice 2 : Miroir d’une chaîne de caractère </h3>\n\nÉcrire une fonction ```miroir``` récursive qui :\n\n- prend comme paramètre une chaîne de caractères `s`\n- renvoie le « miroir » de la chaîne; par exemple, le miroir de \"abcde\" est \"edcba\".\n\n\n**Coup de pouce :** \n\n*Condition d'arrêt* : si la chaine contient un seul caractère ou aucun, son miroir est elle-même.\n\n*Récursion* : Le principe consiste à permutter le 1er et le dernier carcatère, et à recopier le miroir  de la sous-chaine interne (entre le 2ème caractère et l'avant-dernier) au milieu de ces 2 caractères. Il faut donc renvoyer une chaine qui est la concaténation du dernier caratère, du miroir de la sous-chaine interne, et du 1er caractère.\n\n**Aide** : on pourra utiliser la syntaxe `s[1:-1]` qui permet d'extraire une sous-chaine de caractères entre le second élément de l'avant dernier, et `s[0]`, respectivement `s[-1]`,  pour accéder au premier, respectivement dernier, élément"},{"metadata":{},"cell_type":"markdown","source":"<div class = \"alert alert-block alert-warning\"> \n\n### Solution\n</div>"},{"metadata":{"trusted":true,"scrolled":true},"cell_type":"code","source":"# V1\ndef miroir(s):\n    if len(s)<= 1:\n        return s\n    else:\n        return s[-1] + miroir(s[1:-1]) + s[0]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"scrolled":true},"cell_type":"code","source":"# test\nchaine = 'quelle belle chaine'\nmiroir(chaine) # la fonction doit renvoyer : 'eniahc ellleb elleu'\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"scrolled":true},"cell_type":"code","source":"# V2\ndef miroir(s):\n    if len(s)<= 1:\n        return s\n    else:\n        return s[-1] + miroir(s[:-1])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"scrolled":true},"cell_type":"code","source":"# test\nchaine = 'quelle belle chaine'\nmiroir(chaine) # la fonction doit renvoyer : 'eniahc ellleb elleu'\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"scrolled":true},"cell_type":"code","source":"# V3\ndef miroir(s):\n    if len(s)<= 1:\n        return s\n    else:\n        return  miroir(s[1:]) + s[0]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"scrolled":true},"cell_type":"code","source":"# test\nchaine = 'quelle belle chaine'\nmiroir(chaine) # la fonction doit renvoyer : 'eniahc ellleb elleu'\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"<h2 class=\"alert alert-info\">2. Rappels sur Turtle</h2>\n\nTurtle est un module Python permettant de dessiner sur un canevas. Le crayon est dirigé par une tortue !\n\nJupyter propose une implémentation de ce module (très légèrement modifié). Les commandes principales consistent à positionner la tortue, lever ou baisser le crayon (pour écrire ou non lorsque la tortue se déplace) et à commander les mouvements de la tortue (avancer/reculer, tourner à gauche/droite d'un certain angle).\n\nPour mieux comprendre et découvrir les commandes accessibles, étudier l'exemple de démonstration ci-dessous :"},{"metadata":{"trusted":true,"scrolled":true},"cell_type":"code","source":"import turtle as tt # import du module turtle\n\ntt.speed(3)         # vitesse moyenne (maxi = 10)\n\ntt.penup()          # lève le crayon (pour ne pas écrire pendant le déplacement)\ntt.setposition(-100, 100) \n# origine (0, 0) au centre du cadre de dessin (dimensions 600x600)\ntt.pendown()        # abaisse le crayon (pour voir la trace de la tortue)\n\ntt.forward(20)      # avance de 20\ntt.left(60)         # virage de 60° vers la gauche\ntt.forward(100)    \ntt.right(120)       # virage de 120° vers la droite\ntt.pencolor(\"red\")  # couleurs autorisées  \"blue\", \"yellow\", \"brown\", \"black\", \"purple\", \"green\"\ntt.forward(100)  \ntt.left(60)       \ntt.forward(100)     # recule de 100\ntt.backward(70)  \ntt.right(90)   \ntt.pencolor(\"green\")  \ntt.forward(300)  \n\ntt.penup()\ntt.home()           # retour à l'origine\n\ntt.done()           # indispensable pour activer la tortue dans Basthon","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"scrolled":true},"cell_type":"code","source":"# 2ème exemple :\n\nimport turtle as tt # import du module turtle\n\n\ncouleurs = [\"red\", \"blue\", \"yellow\", \"brown\", \"black\", \"purple\", \"green\"]\n\ntt.speed(10)\n\nfor i in range(7):\n    tt.penup()\n    tt.setposition(-200+50*i, 0)\n    tt.pendown()\n    tt.pencolor(couleurs[i])\n    for j in range(4):\n        tt.forward(30)\n        tt.left(90)\n        \ntt.done()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**Pour résumer:**\n\n| Fonction |Exemple|Commentaire|\n|:-------- |:------|:----------|\n|forward(x)|forward(150)|Trace un trait de 150 points|\n|backward(x)|backward(150)|Trace un trait “à reculons” de 150 points|\n|left(n)|left(60)|Tourne sur place la tortue de 60° à gauche|\n|right(n)|right(60)|Tourne sur place la tortue de 60° à droite|\n|setposition(x, y) |setposition(-100, 100)|va à la position (-100,100) sachant que l'origine (0;0) est au centre du cadre de dessin (dimensions 600x600)|\n|width(x)|width(5)|Change l’épaisseur à 5 points|\n|color(\"c\")|color(\"yellow\")|Change la couleur du trait (mais aucun trait n’est tracé à ce moment). Notez les guillemets !|\n|penup()|penup()|Lève la tortue (permet de se déplacer sans dessiner)|\n|pendown()|pendown()|Baisse le stylo|\n|home()|home()|retour à l'origine|"},{"metadata":{},"cell_type":"markdown","source":"<h2 class=\"alert alert-info\">3. Fractales : courbe de Koch</h2>\n\nLa courbe de Koch est une fractale reposant sur la construction récursive suviante :\n1. Étape 1 : Tracer un segment de longueur a. \n\n![Image de losange](https://githepia.hesge.ch/info_sismondi/3AM.OS/-/raw/main/recursivite/koch_0.png)\n\n2. Étape 2 : Diviser le segment en 3 parties de même longueur. Construire un triangle équilatéral ayant pour base le segment médian de la première étape, et en supprimer la base.\n![Image de losange](https://githepia.hesge.ch/info_sismondi/3AM.OS/-/raw/main/recursivite/koch_1.png)\n\n3. Étape 3 : Reprendre l'étape 2 sur chacun des segments créés.\n![Image de losange](https://githepia.hesge.ch/info_sismondi/3AM.OS/-/raw/main/recursivite/koch_2.png)\n\n4. Et ainsi de suite...\n![Image de losange](https://githepia.hesge.ch/info_sismondi/3AM.OS/-/raw/main/recursivite/koch_3.png)\n"},{"metadata":{},"cell_type":"markdown","source":"On peut construire récursivement cette courbe. \n\nLa fonction de tracer prend deux paramètres en entrée :\n* la longeur $a$ du segment.\n* l'étape $n$ de \"profondeur\" de récursivité. \n\nPar exemple, à la profondeur $n=0$, on trace un simple segment : ceci constituera la condition d'arrêt des appels récursifs. À la profondeur $n=1$, le tracé donne la figure de l'étape 2."},{"metadata":{},"cell_type":"markdown","source":"<h3 style=\"color:teal;background-color:azure;\" > <i class=\"fa fa-pencil\" aria-hidden=\"true\"> </i> &nbsp; Exercice 3 : Faire l'étape 2 </h3>\n\n\n1. Écrire une fonction `etape2(a)` qui permet de dessiner avec la tortue (pas de récursivité ici) la figure correspondant à l'étape 2 (décrite ci-avant).\n"},{"metadata":{},"cell_type":"markdown","source":"<div class = \"alert alert-block alert-warning\"> \n\n### Solution\n</div>"},{"metadata":{"trusted":true,"scrolled":true},"cell_type":"code","source":"import turtle as tt # import du module turtle\ntt.speed(10) # pour dessiner plus rapidement\n\ndef etape2(a):\n    tt.forward(a/3)\n    tt.left(60)\n    tt.forward(a/3)\n    tt.right(120)\n    tt.forward(a/3)\n    tt.left(60)\n    tt.forward(a/3)\n    \n# test:\na = 50\netape2(a)\n\ntt.done()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"2. En vous inspirant de la logique du code de la fonction précédente (en la \"rendant récursive\"), écrire une fonction koch(a, n) récursive qui :\n\n    - prend comme paramètres un nombre entier a représentant la longueur du segment et un entier n égal au nombre de récursions souhaité.\n    - construit la courbe de Koch en divisant récursivement chacun des segments\n\n    *Rappel* : si n=0, le tracé est un simplement segment de longueur a."},{"metadata":{"trusted":true,"scrolled":true},"cell_type":"code","source":"import turtle as tt # import du module turtle\n\ntt.speed(10)\ntt.penup()\ntt.setposition(-300, 0) \ntt.pendown()\n\ndef koch(a, n):\n    if n == 0:\n        tt.forward(a)\n    else:\n        koch(a/3, n-1)\n        tt.left(60)\n        koch(a/3, n-1)\n        tt.right(120)\n        koch(a/3, n-1)\n        tt.left(60)\n        koch(a/3, n-1)\n\nkoch(360, 3)\n\ntt.done()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"<h2 class=\"alert alert-info\">Et pour s'amuser encore un peu...</h2>\nExécuter le code ci-dessous :"},{"metadata":{"trusted":true,"scrolled":true},"cell_type":"code","source":"a = 180\n\ntt.speed(10)\ntt.penup()\ntt.setposition(-a/2, a/3) \ntt.pendown()\n\ndef flocon(a, n):\n    for i in range(3):\n        koch(a, n)\n        tt.right(120)\n        \nflocon(a, 3)\n\ntt.penup()\ntt.home()\n\ntt.done()","execution_count":null,"outputs":[]},{"metadata":{"trusted":false},"cell_type":"markdown","source":"---\n\n#### Remarque générale\n\nUne partie de ce notebook reprend le cours sur la récursivité du lycée Faustin Flerettiré http://nsinfo.yo.fr/nsi_term_programmation_recursivite.html. Le notebook est sous license Creative Commons [BY-NC-SA](https://creativecommons.org/licenses/?lang=fr)\n![Licence Creative Commons](https://i.creativecommons.org/l/by-nc-sa/4.0/88x31.png)"}],"metadata":{"kernelspec":{"display_name":"Python 3.8.1 64-bit ('python38': conda)","language":"python","name":"python38164bitpython38conda56991d5ad1414e06a4dcd344400cf456"}},"nbformat":4,"nbformat_minor":2}
\ No newline at end of file