1425 lines
40 KiB
Plaintext
1425 lines
40 KiB
Plaintext
{
|
|
"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
|
|
} |