{ "cells": [ { "cell_type": "markdown", "id": "9cedca3e", "metadata": {}, "source": [ "# PERRIAND-7 : protocole de réveil\n", "\n", "> **Journal de bord, jour 68.**\n", "> Il y a soixante-huit jours, l'équipage de la station orbitale **PERRIAND-7** est entré\n", "> en cryosommeil pour traverser la ceinture de radiations de Van Allen étendue.\n", "> Vous venez d'ouvrir les yeux.\n", ">\n", "> La station, elle, s'est moins bien réveillée que vous. Les radiations ont provoqué des\n", "> corruptions mémoire dans l'ordinateur de bord : plusieurs programmes affichent des\n", "> valeurs absurdes, d'autres refusent tout simplement de s'exécuter.\n", ">\n", "> Vous êtes l'**ingénieur système** de bord. Cinq modules à réveiller, puis la sortie\n", "> d'orbite. Dans l'ordre.\n", "\n", "---\n", "\n", "## Comment travailler\n", "\n", "Chaque module contient quatre types d'exercices :\n", "\n", "| Type | Ce qu'on attend de vous |\n", "|---|---|\n", "| **DIAGNOSTIC** | Lire le code et **prédire** ce qu'il affiche **avant** de l'exécuter. Écrivez votre prédiction dans le commentaire prévu, puis exécutez pour vérifier. |\n", "| **RÉPARATION** | Le code est cassé. Trouvez l'erreur et corrigez-la. |\n", "| **PRODUCTION** | Écrivez le code demandé. |\n", "| **BONUS** | Facultatif. À faire si vous avez terminé le module. |\n", "\n", "**La difficulté monte.** Dans chaque module, les derniers exercices sont volontairement\n", "plus exigeants, et le module 6 l'est encore davantage. C'est le principe d'un sujet de\n", "bac : les dernières questions servent à voir jusqu'où vont les meilleurs. Ne pas les\n", "terminer n'est pas un échec ; les faire, c'est du bonus.\n", "\n", "**Auto-correction.** Chaque exercice de production est suivi d'une cellule de tests.\n", "Exécutez-la : si `OK` s'affiche, c'est gagné. Si vous obtenez une `AssertionError`,\n", "c'est que le code ne fait pas encore ce qui est demandé.\n", "\n", "**Bloqué ?** Chaque module commence par une cellule **SECOURS** qui remet en place\n", "toutes les données dont il a besoin. Les modules sont **indépendants** : vous pouvez\n", "passer au suivant sans avoir fini le précédent.\n", "\n", "---\n", "\n", "*Objectif de la séance : redémarrer le moteur après deux mois d'arrêt. Rien de ce qui suit\n", "n'est nouveau : tout a été vu en Première. Mais chaque notion révisée ici sert directement\n", "un chapitre de Terminale.*\n" ] }, { "cell_type": "markdown", "id": "ac079dd1", "metadata": {}, "source": [ "---\n", "\n", "# Module 1 : LE RÉACTEUR\n", "\n", "### *Variables, affectation, mutabilité*\n", "\n", "> Le réacteur tourne. C'est déjà ça. Mais les jauges du poste de pilotage affichent\n", "> n'importe quoi : 4 % d'oxygène ici, 340 % là. Avant de réparer un seul programme,\n", "> il faut comprendre **comment l'ordinateur de bord range ses valeurs en mémoire**.\n", "\n", "*Ce module prépare : POO (les attributs d'un objet sont des variables), et les listes\n", "chaînées (où deux variables peuvent pointer vers le même maillon).*\n" ] }, { "cell_type": "markdown", "id": "d26e115e", "metadata": {}, "source": [ "### SECOURS : exécutez cette cellule pour démarrer le module 1" ] }, { "cell_type": "code", "id": "7e59265c", "metadata": {}, "source": [ "# Relevés des capteurs au réveil\n", "TAUX_O2_NOMINAL = 21 # en pourcentage\n", "PRESSION_NOMINALE = 101 # en kilopascals\n" ], "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "id": "12e8a187", "metadata": {}, "source": [ "## Diagnostic 1.1 : l'ordre des affectations\n", "\n", "L'ordinateur a exécuté ces quatre lignes. **Avant d'exécuter la cellule**, écrivez ce que\n", "vous pensez qu'elle va afficher.\n", "\n", "*Rappel : une affectation `a = b` calcule d'abord la valeur de droite, puis la range dans\n", "la variable de gauche. Ce qui est calculé est calculé, ça ne se recalcule pas tout seul.*\n" ] }, { "cell_type": "code", "id": "046ffdf2", "metadata": {}, "source": [ "oxygene = 21\n", "oxygene = oxygene - 4\n", "pression = oxygene * 2\n", "oxygene = 21\n", "\n", "print(oxygene, pression)\n", "\n", "# Ma prédiction :\n" ], "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "id": "a7e98bb1", "metadata": {}, "source": [ "## Diagnostic 1.2 : deux noms, une seule liste\n", "\n", "Celui-ci piège tout le monde. Prédisez, puis exécutez.\n" ] }, { "cell_type": "code", "id": "e82b0b0e", "metadata": {}, "source": [ "reserve_principale = [120, 80, 50]\n", "reserve_secours = reserve_principale\n", "reserve_secours.append(0)\n", "\n", "print(\"principale :\", reserve_principale)\n", "print(\"secours :\", reserve_secours)\n", "\n", "# Ma prédiction :\n" ], "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "id": "2cdd1c50", "metadata": {}, "source": [ "> **À retenir.** Une liste est **mutable** : on peut la modifier sur place.\n", "> Un entier ou une chaîne ne le sont pas. C'est pour ça que le piège ci-dessus\n", "> n'existe pas avec des entiers.\n" ] }, { "cell_type": "markdown", "id": "7ca950ac", "metadata": {}, "source": [ "## Réparation 1.3 : l'échange raté\n", "\n", "Le programme de bord doit **échanger** les valeurs de deux capteurs mal branchés.\n", "Le technicien précédent a écrit ceci. Ça ne marche pas.\n", "\n", "**Corrigez** la cellule pour que l'échange fonctionne réellement.\n" ] }, { "cell_type": "code", "id": "45ce169a", "metadata": {}, "source": [ "temp_interne = 18\n", "temp_externe = -270\n", "\n", "# --- échange (cassé) ---\n", "temp_interne = temp_externe\n", "temp_externe = temp_interne\n", "# -----------------------\n", "\n", "print(temp_interne, temp_externe)\n" ], "execution_count": null, "outputs": [] }, { "cell_type": "code", "id": "738e0cdf", "metadata": {}, "source": [ "assert temp_interne == -270 and temp_externe == 18\n", "print(\"OK. Échange réussi\")\n" ], "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "id": "a0c630bd", "metadata": {}, "source": [ "## Production 1.4 : calcul de l'autonomie\n", "\n", "Il reste `litres_oxygene` litres d'oxygène dans les réserves. Chaque membre d'équipage\n", "consomme `consommation_par_heure` litres par heure.\n", "\n", "Calculez dans une variable **`autonomie_h`** le nombre **entier** d'heures complètes\n", "que l'équipage peut encore tenir.\n", "\n", "*Indice : `//` est la division entière, celle qui ne garde que le nombre de tours complets.*\n" ] }, { "cell_type": "code", "id": "2e94b40a", "metadata": {}, "source": [ "litres_oxygene = 480\n", "consommation_par_heure = 3\n", "nb_membres = 4\n", "\n", "autonomie_h = ... # à compléter\n", "\n", "print(\"Autonomie :\", autonomie_h, \"heures\")\n" ], "execution_count": null, "outputs": [] }, { "cell_type": "code", "id": "1aed1664", "metadata": {}, "source": [ "assert autonomie_h == 40, \"Attendu 40, obtenu \" + str(autonomie_h)\n", "print(\"OK. Autonomie correcte : 40 h\")\n" ], "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "id": "4350e6ad", "metadata": {}, "source": [ "## Bonus 1.5 : copie indépendante\n", "\n", "Créez `sauvegarde` : une copie de `releves` qui **ne bouge pas** quand on modifie `releves`.\n" ] }, { "cell_type": "code", "id": "40103661", "metadata": {}, "source": [ "releves = [21, 101, 18]\n", "\n", "sauvegarde = ... # à compléter\n", "\n", "releves.append(999)\n", "print(\"releves :\", releves)\n", "print(\"sauvegarde:\", sauvegarde)\n" ], "execution_count": null, "outputs": [] }, { "cell_type": "code", "id": "5f75eb8a", "metadata": {}, "source": [ "assert sauvegarde == [21, 101, 18]\n", "assert releves == [21, 101, 18, 999]\n", "print(\"OK. La sauvegarde est bien indépendante\")\n" ], "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "id": "303bbff3", "metadata": {}, "source": [ "---\n", "\n", "# Module 2 : LES PROTOCOLES\n", "\n", "### *Fonctions : paramètres, `return`, portée*\n", "\n", "> Les protocoles de sécurité de la station sont des **fonctions**. On les appelle, elles\n", "> répondent. Sauf que depuis les radiations, plusieurs d'entre elles ne répondent plus\n", "> rien du tout : elles se contentent de parler dans le vide.\n", "\n", "*Ce module prépare : la **récursivité** (une fonction qui s'appelle elle-même n'a de\n", "sens que si elle **renvoie** quelque chose) et la Modularité.*\n" ] }, { "cell_type": "markdown", "id": "63724e09", "metadata": {}, "source": [ "### SECOURS : exécutez cette cellule pour démarrer le module 2" ] }, { "cell_type": "code", "id": "511a487d", "metadata": {}, "source": [ "SEUIL_CRITIQUE = 80\n", "SEUIL_ALERTE = 95\n" ], "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "id": "72959168", "metadata": {}, "source": [ "## Diagnostic 2.1 : `print` n'est pas `return`\n", "\n", "Prédisez les **deux** lignes affichées.\n" ] }, { "cell_type": "code", "id": "9aec1b79", "metadata": {}, "source": [ "def niveau_pression(pression):\n", " if pression < 80:\n", " print(\"CRITIQUE\")\n", " else:\n", " print(\"NOMINAL\")\n", "\n", "resultat = niveau_pression(45)\n", "print(\"resultat vaut :\", resultat)\n", "\n", "# Ma prédiction :\n" ], "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "id": "b93de0e2", "metadata": {}, "source": [ "> **À retenir.** `print` **montre** à l'humain. `return` **rend** une valeur au\n", "> programme. Une fonction qui ne fait que `print` est un cul-de-sac : on ne peut pas\n", "> construire quoi que ce soit par-dessus.\n" ] }, { "cell_type": "markdown", "id": "8ba6160b", "metadata": {}, "source": [ "## Réparation 2.2 : rendre le protocole utilisable\n", "\n", "Réécrivez `niveau_pression` pour qu'elle **renvoie** la chaîne au lieu de l'afficher.\n", "\n", "- pression strictement inférieure à 80 : renvoie `\"CRITIQUE\"`\n", "- pression entre 80 (inclus) et 95 (exclu) : renvoie `\"ALERTE\"`\n", "- pression supérieure ou égale à 95 : renvoie `\"NOMINAL\"`\n" ] }, { "cell_type": "code", "id": "2c7c648f", "metadata": {}, "source": [ "def niveau_pression(pression):\n", " ... # à compléter\n" ], "execution_count": null, "outputs": [] }, { "cell_type": "code", "id": "235aaf17", "metadata": {}, "source": [ "assert niveau_pression(45) == \"CRITIQUE\"\n", "assert niveau_pression(79) == \"CRITIQUE\"\n", "assert niveau_pression(80) == \"ALERTE\"\n", "assert niveau_pression(94) == \"ALERTE\"\n", "assert niveau_pression(95) == \"NOMINAL\"\n", "assert niveau_pression(120) == \"NOMINAL\"\n", "print(\"OK. Protocole de pression opérationnel\")\n" ], "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "id": "df5b2857", "metadata": {}, "source": [ "## Diagnostic 2.3 : la variable qui n'existe pas\n", "\n", "Ce code **plante**. Avant de l'exécuter, essayez de dire **pourquoi**.\n" ] }, { "cell_type": "code", "id": "8f53752a", "metadata": {}, "source": [ "compteur_alertes = 0\n", "\n", "def signaler_alerte():\n", " compteur_alertes = compteur_alertes + 1\n", " return compteur_alertes\n", "\n", "print(signaler_alerte())\n", "\n", "# Ma prédiction (quelle erreur, et pourquoi ?) :\n" ], "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "id": "2db401da", "metadata": {}, "source": [ "**Corrigez** en transformant `signaler_alerte` en une fonction qui prend le compteur\n", "actuel en paramètre et renvoie le compteur augmenté de 1.\n" ] }, { "cell_type": "code", "id": "e8a6fc67", "metadata": {}, "source": [ "def signaler_alerte(compteur):\n", " ... # à compléter\n", "\n", "compteur_alertes = 0\n", "compteur_alertes = signaler_alerte(compteur_alertes)\n", "compteur_alertes = signaler_alerte(compteur_alertes)\n", "print(compteur_alertes)\n" ], "execution_count": null, "outputs": [] }, { "cell_type": "code", "id": "9220f6e4", "metadata": {}, "source": [ "assert signaler_alerte(0) == 1\n", "assert signaler_alerte(41) == 42\n", "assert compteur_alertes == 2\n", "print(\"OK. Compteur d'alertes réparé\")\n" ], "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "id": "74da1f8f", "metadata": {}, "source": [ "## Production 2.4 : une fonction qui en appelle une autre\n", "\n", "Écrivez `diagnostic(pression, temperature)` qui renvoie une chaîne de la forme :\n", "\n", "```\n", "\"Pression NOMINAL / Temperature 18\"\n", "```\n", "\n", "Votre fonction **doit appeler** `niveau_pression` : ne recopiez pas les tests de seuil.\n", "\n", "*Indice : pour coller des morceaux de texte, `+` fonctionne, mais il faut convertir les\n", "nombres avec `str(...)`.*\n" ] }, { "cell_type": "code", "id": "f675b126", "metadata": {}, "source": [ "def diagnostic(pression, temperature):\n", " ... # à compléter\n" ], "execution_count": null, "outputs": [] }, { "cell_type": "code", "id": "c808569d", "metadata": {}, "source": [ "assert diagnostic(101, 18) == \"Pression NOMINAL / Temperature 18\"\n", "assert diagnostic(45, -3) == \"Pression CRITIQUE / Temperature -3\"\n", "assert diagnostic(88, 0) == \"Pression ALERTE / Temperature 0\"\n", "print(\"OK. Diagnostic complet opérationnel\")\n" ], "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "id": "f38f5656", "metadata": {}, "source": [ "## Bonus 2.5 : paramètre par défaut\n", "\n", "Écrivez `verrouiller(module, code_acces=\"0000\")` qui renvoie :\n", "- `\"MODULE VERROUILLE\"` si le code fourni est `\"0000\"`\n", "- `\"CODE REFUSE\"` sinon\n" ] }, { "cell_type": "code", "id": "9bbac347", "metadata": {}, "source": [ "def verrouiller(module, code_acces=\"0000\"):\n", " ... # à compléter\n" ], "execution_count": null, "outputs": [] }, { "cell_type": "code", "id": "3be9ed12", "metadata": {}, "source": [ "assert verrouiller(\"Sas\") == \"MODULE VERROUILLE\"\n", "assert verrouiller(\"Sas\", \"0000\") == \"MODULE VERROUILLE\"\n", "assert verrouiller(\"Sas\", \"1234\") == \"CODE REFUSE\"\n", "print(\"OK. Verrouillage opérationnel\")\n" ], "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "id": "c9a85d18", "metadata": {}, "source": [ "---\n", "\n", "# Module 3 : LE BALAYAGE\n", "\n", "### *Boucles : `for`, `while`, accumulateur*\n", "\n", "> Il faut maintenant **balayer** les 5 000 relevés de capteurs accumulés pendant\n", "> l'hibernation, pour repérer les anomalies. Personne ne fera ça à la main.\n", "\n", "*Ce module prépare : le parcours des arbres et des graphes, où l'on visite un à un\n", "tous les éléments d'une structure sans savoir à l'avance combien il y en a.*\n" ] }, { "cell_type": "markdown", "id": "7558e6b5", "metadata": {}, "source": [ "### SECOURS : exécutez cette cellule pour démarrer le module 3" ] }, { "cell_type": "code", "id": "c10a8eb5", "metadata": {}, "source": [ "mesures = [12, 45, 7, 88, 23, 91, 4]\n" ], "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "id": "d77cebe9", "metadata": {}, "source": [ "## Diagnostic 3.1 : combien de tours ?\n", "\n", "Prédisez ce qui s'affiche, **et combien de lignes**.\n" ] }, { "cell_type": "code", "id": "aa6ae61c", "metadata": {}, "source": [ "i = 0\n", "while i < 5:\n", " print(i)\n", " i = i + 2\n", "\n", "print(\"fin, i vaut\", i)\n", "\n", "# Ma prédiction :\n" ], "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "id": "5c8282f2", "metadata": {}, "source": [ "## Diagnostic 3.2 : NE PAS EXÉCUTER\n", "\n", "Cette cellule est en mode texte : **ne l'exécutez pas**, elle ne s'arrêterait jamais.\n", "\n", "```python\n", "carburant = 100\n", "while carburant > 0:\n", " print(\"Purge en cours...\")\n", " carburant = 100\n", "```\n", "\n", "**Question (répondez dans la cellule ci-dessous) :** pourquoi cette boucle ne se\n", "termine-t-elle jamais, et quelle est la plus petite modification qui la ferait terminer ?\n" ] }, { "cell_type": "code", "id": "65da8f42", "metadata": {}, "source": [ "# Ma réponse :\n" ], "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "id": "571a3166", "metadata": {}, "source": [ "## Réparation 3.3 : le capteur oublié\n", "\n", "Ce code doit afficher **toutes** les mesures. Il en rate une. Trouvez laquelle, et corrigez.\n" ] }, { "cell_type": "code", "id": "1793514f", "metadata": {}, "source": [ "for i in range(1, len(mesures)):\n", " print(\"capteur\", i, \":\", mesures[i])\n" ], "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "id": "5ff70b05", "metadata": {}, "source": [ "## Production 3.4 : le maximum, à la main\n", "\n", "Écrivez `maximum(valeurs)` qui renvoie la plus grande valeur d'une liste **non vide**,\n", "**sans utiliser `max()`**.\n", "\n", "*Méthode de l'accumulateur : on retient un « meilleur pour l'instant », et on le met à\n", "jour à chaque tour.*\n" ] }, { "cell_type": "code", "id": "38ce42e7", "metadata": {}, "source": [ "def maximum(valeurs):\n", " ... # à compléter\n" ], "execution_count": null, "outputs": [] }, { "cell_type": "code", "id": "508af429", "metadata": {}, "source": [ "assert maximum([12, 45, 7, 88, 23, 91, 4]) == 91\n", "assert maximum([5]) == 5\n", "assert maximum([3, 3, 3]) == 3\n", "assert maximum([-10, -3, -50]) == -3, \"attention aux valeurs négatives : ne partez pas de 0\"\n", "print(\"OK. Détection du maximum opérationnelle\")\n" ], "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "id": "bb2ed90c", "metadata": {}, "source": [ "## Production 3.5 : le premier capteur défaillant\n", "\n", "Écrivez `premier_defaillant(valeurs, seuil)` qui renvoie **l'indice** de la première\n", "mesure strictement inférieure à `seuil`, et `-1` si aucune ne l'est.\n", "\n", "*Indice : ici on a besoin de l'indice, donc de `range(len(valeurs))`. Et on peut sortir\n", "de la fonction dès qu'on a trouvé.*\n" ] }, { "cell_type": "code", "id": "c8e95e62", "metadata": {}, "source": [ "def premier_defaillant(valeurs, seuil):\n", " ... # à compléter\n" ], "execution_count": null, "outputs": [] }, { "cell_type": "code", "id": "b1ef7f88", "metadata": {}, "source": [ "assert premier_defaillant([12, 45, 7, 88], 20) == 0\n", "assert premier_defaillant([45, 88, 7, 4], 10) == 2\n", "assert premier_defaillant([45, 88, 91], 10) == -1\n", "assert premier_defaillant([], 10) == -1\n", "print(\"OK. Détection de défaillance opérationnelle\")\n" ], "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "id": "2fbc699e", "metadata": {}, "source": [ "## Bonus 3.6 : la sentinelle\n", "\n", "Le capteur d'altitude envoie ses relevés en continu et termine sa transmission par la\n", "valeur `-1`. Écrivez `somme_jusqu_a_sentinelle(flux)` qui additionne les valeurs\n", "**jusqu'au premier `-1` exclu**. Les valeurs après le `-1` sont du bruit : on les ignore.\n", "\n", "*Indice : un `while` avec deux conditions est plus naturel qu'un `for` ici.*\n" ] }, { "cell_type": "code", "id": "db64a7cd", "metadata": {}, "source": [ "def somme_jusqu_a_sentinelle(flux):\n", " ... # à compléter\n" ], "execution_count": null, "outputs": [] }, { "cell_type": "code", "id": "c2dee877", "metadata": {}, "source": [ "assert somme_jusqu_a_sentinelle([10, 20, 30, -1, 999, 999]) == 60\n", "assert somme_jusqu_a_sentinelle([-1, 5, 5]) == 0\n", "assert somme_jusqu_a_sentinelle([1, 2, 3]) == 6\n", "assert somme_jusqu_a_sentinelle([]) == 0\n", "print(\"OK. Lecture du flux opérationnelle\")\n" ], "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "id": "019e79d6", "metadata": {}, "source": [ "---\n", "\n", "# Module 4 : LA SOUTE\n", "\n", "### *Listes : indices, tranches, listes de listes*\n", "\n", "> La soute est organisée en rayonnages. L'inventaire numérique a survécu, mais les\n", "> programmes qui l'exploitent, non.\n", "\n", "*Ce module prépare : les structures linéaires (pile, file, listes chaînées) et le\n", "tri fusion du chapitre « diviser pour régner ».*\n" ] }, { "cell_type": "markdown", "id": "f55cbffb", "metadata": {}, "source": [ "### SECOURS : exécutez cette cellule pour démarrer le module 4" ] }, { "cell_type": "code", "id": "77c49e75", "metadata": {}, "source": [ "soute = [\"eau\", \"vivres\", \"outils\", \"piles\", \"filtres\"]\n", "\n", "# Chaque sous-liste est un rayonnage : [rayon_0, rayon_1, rayon_2]\n", "# Chaque ligne = un étage de la soute.\n", "stock = [[12, 5, 0],\n", " [3, 8, 7],\n", " [0, 0, 4],\n", " [9, 1, 2]]\n" ], "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "id": "c557dcd6", "metadata": {}, "source": [ "## Diagnostic 4.1 : indices et tranches\n", "\n", "Prédisez les quatre affichages.\n" ] }, { "cell_type": "code", "id": "afd7698a", "metadata": {}, "source": [ "print(soute[0])\n", "print(soute[-1])\n", "print(soute[1:3])\n", "print(len(soute[1:3]))\n", "\n", "# Ma prédiction :\n" ], "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "id": "722fe0e0", "metadata": {}, "source": [ "## Réparation 4.2 : le bug du technicien\n", "\n", "Ce code doit retirer de `soute` tout ce qui commence par la lettre `\"p\"`.\n", "Il en oublie. **Exécutez-le d'abord** pour constater le problème, puis corrigez-le.\n", "\n", "*Indice : modifier une liste pendant qu'on la parcourt décale les indices sous les pieds\n", "de la boucle. La solution habituelle est de **construire une nouvelle liste** plutôt que\n", "de retirer dans l'ancienne.*\n" ] }, { "cell_type": "code", "id": "eb031359", "metadata": {}, "source": [ "soute_test = [\"piles\", \"pinces\", \"eau\", \"outils\"]\n", "\n", "for objet in soute_test:\n", " if objet[0] == \"p\":\n", " soute_test.remove(objet)\n", "\n", "print(soute_test) # devrait afficher ['eau', 'outils']\n" ], "execution_count": null, "outputs": [] }, { "cell_type": "code", "id": "9eb6ad74", "metadata": {}, "source": [ "assert soute_test == [\"eau\", \"outils\"]\n", "print(\"OK. Purge de la soute correcte\")\n" ], "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "id": "3e7af438", "metadata": {}, "source": [ "## Production 4.3 : total d'un rayonnage\n", "\n", "`stock` est une **liste de listes** : `stock[i][j]` est la quantité stockée à l'étage `i`,\n", "rayon `j`.\n", "\n", "Écrivez `total_rayon(grille, r)` qui renvoie la somme des quantités du rayon `r`,\n", "**tous étages confondus**.\n", "\n", "*Attention : le rayon `r` est une **colonne**, pas une ligne. Il faut parcourir les étages.*\n" ] }, { "cell_type": "code", "id": "032922c5", "metadata": {}, "source": [ "def total_rayon(grille, r):\n", " ... # à compléter\n" ], "execution_count": null, "outputs": [] }, { "cell_type": "code", "id": "3fbf18ee", "metadata": {}, "source": [ "assert total_rayon(stock, 0) == 24\n", "assert total_rayon(stock, 1) == 14\n", "assert total_rayon(stock, 2) == 13\n", "print(\"OK. Inventaire par rayon opérationnel\")\n" ], "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "id": "ebf325de", "metadata": {}, "source": [ "## Production 4.4 : filtrer en une ligne\n", "\n", "Écrivez `au_dessus(valeurs, seuil)` qui renvoie la liste des valeurs strictement\n", "supérieures à `seuil`, **en utilisant une compréhension de liste**.\n", "\n", "*Rappel de la forme : `[expression for element in liste if condition]`*\n" ] }, { "cell_type": "code", "id": "edde708e", "metadata": {}, "source": [ "def au_dessus(valeurs, seuil):\n", " ... # à compléter (une seule ligne, avec une compréhension)\n" ], "execution_count": null, "outputs": [] }, { "cell_type": "code", "id": "4f84985e", "metadata": {}, "source": [ "assert au_dessus([12, 45, 7, 88, 23], 20) == [45, 88, 23]\n", "assert au_dessus([1, 2, 3], 10) == []\n", "assert au_dessus([], 0) == []\n", "print(\"OK. Filtrage opérationnel\")\n" ], "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "id": "1cb952eb", "metadata": {}, "source": [ "## Bonus 4.5 : fusionner deux listes triées\n", "\n", "Deux capteurs ont enregistré des relevés, chacun **déjà trié dans l'ordre croissant**.\n", "Écrivez `fusion(a, b)` qui renvoie une seule liste triée contenant tous les éléments,\n", "**sans utiliser `sorted()` ni `.sort()`**.\n", "\n", "*Méthode : deux indices qui avancent, on prend à chaque tour le plus petit des deux\n", "éléments courants.*\n", "\n", "> Cet exercice est **exactement** la seconde moitié du tri fusion, que vous verrez\n", "> dans le chapitre « diviser pour régner ».\n" ] }, { "cell_type": "code", "id": "f90d480c", "metadata": {}, "source": [ "def fusion(a, b):\n", " ... # à compléter\n" ], "execution_count": null, "outputs": [] }, { "cell_type": "code", "id": "5c804e8a", "metadata": {}, "source": [ "assert fusion([1, 4, 9], [2, 3, 10]) == [1, 2, 3, 4, 9, 10]\n", "assert fusion([], [2, 3]) == [2, 3]\n", "assert fusion([5], []) == [5]\n", "assert fusion([1, 1], [1]) == [1, 1, 1]\n", "print(\"OK. Fusion opérationnelle, vous venez d'écrire la moitié d'un tri fusion\")\n" ], "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "id": "b8c12ccc", "metadata": {}, "source": [ "---\n", "\n", "# Module 5 : L'ÉQUIPAGE\n", "\n", "### *Dictionnaires : clés, valeurs, parcours*\n", "\n", "> Reste le plus important : les **dossiers de l'équipage** et le **plan de la station**.\n", "> Une liste ne suffit plus : on ne cherche pas « le 3ᵉ membre », on cherche « Kowalski ».\n", "\n", "*Ce module prépare : les graphes (un graphe se représente par un dictionnaire de\n", "listes) et la mémoïsation en programmation dynamique (un dictionnaire de résultats\n", "déjà calculés).*\n" ] }, { "cell_type": "markdown", "id": "4bf29dc6", "metadata": {}, "source": [ "### SECOURS : exécutez cette cellule pour démarrer le module 5" ] }, { "cell_type": "code", "id": "3d3ad4e9", "metadata": {}, "source": [ "equipage = {\n", " \"Kowalski\": \"pilote\",\n", " \"Ndiaye\": \"medecin\",\n", " \"Reyes\": \"ingenieur\",\n", " \"Sokolova\": \"pilote\",\n", " \"Tanaka\": \"ingenieur\",\n", "}\n", "\n", "# Plan de la station : à chaque module, la liste des modules directement accessibles\n", "plan = {\n", " \"Sas\": [\"Couloir\"],\n", " \"Couloir\": [\"Sas\", \"Cockpit\", \"Soute\", \"Labo\"],\n", " \"Cockpit\": [\"Couloir\"],\n", " \"Soute\": [\"Couloir\", \"Reacteur\"],\n", " \"Labo\": [\"Couloir\"],\n", " \"Reacteur\": [\"Soute\"],\n", "}\n" ], "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "id": "15df7fc9", "metadata": {}, "source": [ "## Diagnostic 5.1 : accès et absence\n", "\n", "Prédisez le résultat des trois premières lignes. La quatrième est volontairement\n", "commentée : dites ce qui se passerait si on la décommentait.\n" ] }, { "cell_type": "code", "id": "2b5fd78b", "metadata": {}, "source": [ "print(equipage[\"Reyes\"])\n", "print(len(equipage))\n", "print(\"Bowman\" in equipage)\n", "# print(equipage[\"Bowman\"])\n", "\n", "# Ma prédiction :\n" ], "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "id": "2b5ffaac", "metadata": {}, "source": [ "## Réparation 5.2 : le poste qui n'existe pas\n", "\n", "Cette fonction plante dès qu'on lui donne un nom inconnu. Corrigez-la pour qu'elle\n", "renvoie `\"inconnu\"` dans ce cas.\n" ] }, { "cell_type": "code", "id": "a84b9a81", "metadata": {}, "source": [ "def poste_de(registre, nom):\n", " return registre[nom]\n", "\n", "print(poste_de(equipage, \"Tanaka\"))\n", "print(poste_de(equipage, \"Bowman\")) # plante\n" ], "execution_count": null, "outputs": [] }, { "cell_type": "code", "id": "fdbbebf4", "metadata": {}, "source": [ "assert poste_de(equipage, \"Tanaka\") == \"ingenieur\"\n", "assert poste_de(equipage, \"Bowman\") == \"inconnu\"\n", "print(\"OK. Registre sécurisé\")\n" ], "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "id": "c7226646", "metadata": {}, "source": [ "## Production 5.3 : compter les postes\n", "\n", "Écrivez `compter_postes(registre)` qui renvoie un **dictionnaire** associant à chaque\n", "poste le nombre de membres qui l'occupent.\n", "\n", "Sur `equipage`, on doit obtenir : `{'pilote': 2, 'medecin': 1, 'ingenieur': 2}`\n", "\n", "*Méthode classique : on part d'un dictionnaire vide, et pour chaque valeur rencontrée,\n", "soit la clé existe déjà et on l'incrémente, soit elle n'existe pas et on la crée à 1.*\n" ] }, { "cell_type": "code", "id": "bfd2eb9b", "metadata": {}, "source": [ "def compter_postes(registre):\n", " ... # à compléter\n" ], "execution_count": null, "outputs": [] }, { "cell_type": "code", "id": "066e51a5", "metadata": {}, "source": [ "resultat = compter_postes(equipage)\n", "assert resultat == {\"pilote\": 2, \"medecin\": 1, \"ingenieur\": 2}\n", "assert compter_postes({}) == {}\n", "assert compter_postes({\"A\": \"pilote\"}) == {\"pilote\": 1}\n", "print(\"OK. Recensement de l'équipage opérationnel\")\n" ], "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "id": "156a9f11", "metadata": {}, "source": [ "## Production 5.4 : lire le plan de la station\n", "\n", "`plan` est un dictionnaire dont **les valeurs sont des listes**.\n", "\n", "1. Écrivez `voisins(plan, module)` : la liste des modules directement accessibles depuis\n", " `module`, ou `[]` si le module n'existe pas.\n", "2. Écrivez `nb_liaisons(plan)` : le nombre **total** de liaisons listées dans le plan\n", " (on compte simplement la longueur de toutes les listes).\n", "\n", "> Cette structure a un nom : c'est une **liste d'adjacence**. C'est celle que vous\n", "> utiliserez pour représenter un graphe.\n" ] }, { "cell_type": "code", "id": "471df698", "metadata": {}, "source": [ "def voisins(plan, module):\n", " ... # à compléter\n", "\n", "\n", "def nb_liaisons(plan):\n", " ... # à compléter\n" ], "execution_count": null, "outputs": [] }, { "cell_type": "code", "id": "97c73d89", "metadata": {}, "source": [ "assert voisins(plan, \"Cockpit\") == [\"Couloir\"]\n", "assert voisins(plan, \"Couloir\") == [\"Sas\", \"Cockpit\", \"Soute\", \"Labo\"]\n", "assert voisins(plan, \"Hangar\") == []\n", "assert nb_liaisons(plan) == 10\n", "print(\"OK. Lecture du plan opérationnelle\")\n" ], "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "id": "cb36253a", "metadata": {}, "source": [ "## Bonus 5.5 : regrouper par poste\n", "\n", "Écrivez `par_poste(registre)` qui renvoie un dictionnaire associant à chaque poste la\n", "**liste des noms** qui l'occupent :\n", "\n", "```python\n", "{'pilote': ['Kowalski', 'Sokolova'], 'medecin': ['Ndiaye'], 'ingenieur': ['Reyes', 'Tanaka']}\n", "```\n" ] }, { "cell_type": "code", "id": "3562ccb9", "metadata": {}, "source": [ "def par_poste(registre):\n", " ... # à compléter\n" ], "execution_count": null, "outputs": [] }, { "cell_type": "code", "id": "3b7e95fe", "metadata": {}, "source": [ "attendu = {\"pilote\": [\"Kowalski\", \"Sokolova\"],\n", " \"medecin\": [\"Ndiaye\"],\n", " \"ingenieur\": [\"Reyes\", \"Tanaka\"]}\n", "assert par_poste(equipage) == attendu\n", "assert par_poste({}) == {}\n", "print(\"OK. Regroupement opérationnel\")\n" ], "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "id": "5fb7dd42", "metadata": {}, "source": [ "---\n", "\n", "# Module 6 : SORTIE D'ORBITE\n", "\n", "### *Synthèse, et retour à la récursivité*\n", "\n", "> Tous les systèmes répondent. Reste à vérifier qu'aucun module n'est resté isolé après\n", "> les avaries : si un compartiment n'est plus relié au reste de la station, l'équipage\n", "> qui s'y trouve est piégé.\n" ] }, { "cell_type": "markdown", "id": "ce52365e", "metadata": {}, "source": [ "### SECOURS : exécutez cette cellule pour démarrer le module 6" ] }, { "cell_type": "code", "id": "03c291e7", "metadata": {}, "source": [ "plan = {\n", " \"Sas\": [\"Couloir\"],\n", " \"Couloir\": [\"Sas\", \"Cockpit\", \"Soute\", \"Labo\"],\n", " \"Cockpit\": [\"Couloir\"],\n", " \"Soute\": [\"Couloir\", \"Reacteur\"],\n", " \"Labo\": [\"Couloir\"],\n", " \"Reacteur\": [\"Soute\"],\n", " \"Serre\": [\"Cellule\"], # compartiment isolé du reste !\n", " \"Cellule\": [\"Serre\"],\n", "}\n" ], "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "id": "b0fc880b", "metadata": {}, "source": [ "## Synthèse 6.1 : quels modules sont atteignables ?\n", "\n", "Écrivez `atteignables(plan, depart)` : la liste des modules que l'on peut rejoindre\n", "depuis `depart`, en comptant `depart` lui-même.\n", "\n", "L'algorithme vous est donné, il ne reste qu'à le traduire :\n", "\n", "```\n", "a_visiter ← liste contenant seulement depart\n", "visites ← liste vide\n", "tant que a_visiter n'est pas vide :\n", " module ← on retire le DERNIER élément de a_visiter\n", " si module n'est pas déjà dans visites :\n", " ajouter module à visites\n", " pour chaque v dans les voisins de module :\n", " ajouter v à a_visiter\n", "renvoyer visites\n", "```\n", "\n", "*Indice : « retirer le dernier élément » se dit `liste.pop()` en Python.*\n", "\n", "> Ce que vous venez d'écrire est un **parcours en profondeur**. `a_visiter` est une\n", "> **pile**. Vous retrouverez les deux, sous ces noms, dans les chapitres Pile/File et\n", "> Graphes.\n" ] }, { "cell_type": "code", "id": "10f0f01a", "metadata": {}, "source": [ "def atteignables(plan, depart):\n", " ... # à compléter\n" ], "execution_count": null, "outputs": [] }, { "cell_type": "code", "id": "cbb4d921", "metadata": {}, "source": [ "r = atteignables(plan, \"Sas\")\n", "assert sorted(r) == [\"Cockpit\", \"Couloir\", \"Labo\", \"Reacteur\", \"Sas\", \"Soute\"]\n", "assert \"Serre\" not in r, \"La serre ne doit PAS être atteignable depuis le sas\"\n", "assert sorted(atteignables(plan, \"Serre\")) == [\"Cellule\", \"Serre\"]\n", "assert atteignables(plan, \"Hangar\") == [\"Hangar\"]\n", "print(\"OK. Cartographie terminée, 2 compartiments isolés détectés : Serre et Cellule\")\n" ], "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "id": "8d802304", "metadata": {}, "source": [ "## Diagnostic 6.2 : le compte à rebours\n", "\n", "Dernière étape avant le décollage. **Ne l'exécutez pas tout de suite** : écrivez d'abord,\n", "sur votre feuille, l'ordre exact des affichages pour `compte_a_rebours(3)`.\n" ] }, { "cell_type": "code", "id": "a7f1d995", "metadata": {}, "source": [ "def compte_a_rebours(n):\n", " if n == 0:\n", " print(\"DECOLLAGE\")\n", " else:\n", " print(n)\n", " compte_a_rebours(n - 1)\n", " print(\"verif\", n)\n", "\n", "compte_a_rebours(3)\n", "\n", "# Ma prédiction :\n" ], "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "id": "7f208932", "metadata": {}, "source": [ "---\n", "\n", "## Fin du protocole\n", "\n", "**PERRIAND-7 est de nouveau opérationnelle.**\n", "\n", "Ce que vous venez de réutiliser, et où ça resservira :\n", "\n", "| Module | Notion | Chapitre de Terminale concerné |\n", "|---|---|---|\n", "| 1 · Réacteur | variables, mutabilité, aliasing | POO, listes chaînées |\n", "| 2 · Protocoles | `return`, paramètres, portée | **Récursivité**, Modularité |\n", "| 3 · Balayage | boucles, accumulateur | parcours d'arbres et de graphes |\n", "| 4 · Soute | listes, listes de listes, compréhensions | structures linéaires, tri fusion |\n", "| 5 · Équipage | dictionnaires, dict de listes | **graphes**, mémoïsation |\n", "| 6 · Sortie d'orbite | pile, parcours, pile d'appels | Pile/File, **Récursivité** |\n", "\n", "---\n", "*Lycée Charlotte Perriand, NSI Terminale, Licence CC BY-SA 4.0*\n" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "name": "python", "version": "3.11" } }, "nbformat": 4, "nbformat_minor": 5 }