46 KiB
46 KiB
In [ ]:
# Relevés des capteurs au réveil
TAUX_O2_NOMINAL = 21 # en pourcentage
PRESSION_NOMINALE = 101 # en kilopascals
In [ ]:
oxygene = 21
oxygene = oxygene - 4
pression = oxygene * 2
oxygene = 21
print(oxygene, pression)
# Ma prédiction : 21 34
# La ligne 3 a utilisé la valeur d'oxygene à cet instant (17), pas sa valeur finale.
# pression vaut donc 34 et ne « suit » pas les changements ultérieurs d'oxygene.
In [ ]:
reserve_principale = [120, 80, 50]
reserve_secours = reserve_principale
reserve_secours.append(0)
print("principale :", reserve_principale)
print("secours :", reserve_secours)
# Ma prédiction : les deux affichent [120, 80, 50, 0]
# `reserve_secours = reserve_principale` ne copie PAS la liste : elle donne un
# deuxième nom à la même liste en mémoire. Modifier l'une modifie l'autre.
# Pour obtenir une vraie copie : reserve_secours = list(reserve_principale)
In [ ]:
temp_interne = 18
temp_externe = -270
# --- échange (corrigé) ---
temp_interne, temp_externe = temp_externe, temp_interne
# Variante sans affectation multiple, avec une variable tampon :
# tampon = temp_interne
# temp_interne = temp_externe
# temp_externe = tampon
# -------------------------
print(temp_interne, temp_externe)
In [ ]:
assert temp_interne == -270 and temp_externe == 18
print("OK. Échange réussi")
In [ ]:
litres_oxygene = 480
consommation_par_heure = 3
nb_membres = 4
autonomie_h = litres_oxygene // (consommation_par_heure * nb_membres)
print("Autonomie :", autonomie_h, "heures")
In [ ]:
assert autonomie_h == 40, "Attendu 40, obtenu " + str(autonomie_h)
print("OK. Autonomie correcte : 40 h")
In [ ]:
releves = [21, 101, 18]
sauvegarde = list(releves) # ou releves[:] , ou releves.copy()
releves.append(999)
print("releves :", releves)
print("sauvegarde:", sauvegarde)
In [ ]:
assert sauvegarde == [21, 101, 18]
assert releves == [21, 101, 18, 999]
print("OK. La sauvegarde est bien indépendante")
In [ ]:
SEUIL_CRITIQUE = 80
SEUIL_ALERTE = 95
In [ ]:
def niveau_pression(pression):
if pression < 80:
print("CRITIQUE")
else:
print("NOMINAL")
resultat = niveau_pression(45)
print("resultat vaut :", resultat)
# Ma prédiction : CRITIQUE puis resultat vaut : None
# La fonction AFFICHE mais ne RENVOIE rien. Une fonction sans return renvoie None.
# On ne peut donc rien faire du résultat : ni le tester, ni le stocker, ni le réutiliser.
In [ ]:
def niveau_pression(pression):
if pression < 80:
return "CRITIQUE"
elif pression < 95:
return "ALERTE"
else:
return "NOMINAL"
In [ ]:
assert niveau_pression(45) == "CRITIQUE"
assert niveau_pression(79) == "CRITIQUE"
assert niveau_pression(80) == "ALERTE"
assert niveau_pression(94) == "ALERTE"
assert niveau_pression(95) == "NOMINAL"
assert niveau_pression(120) == "NOMINAL"
print("OK. Protocole de pression opérationnel")
In [ ]:
compteur_alertes = 0
def signaler_alerte():
compteur_alertes = compteur_alertes + 1
return compteur_alertes
print(signaler_alerte())
# Ma prédiction : UnboundLocalError.
# Comme `compteur_alertes` reçoit une affectation DANS la fonction, Python la considère
# comme une variable LOCALE. Au moment du calcul `compteur_alertes + 1`, cette variable
# locale n'a encore aucune valeur : erreur.
# La bonne solution n'est PAS `global` : c'est de passer la valeur en PARAMÈTRE
# et de renvoyer la nouvelle (voir cellule suivante).
In [ ]:
def signaler_alerte(compteur):
return compteur + 1
compteur_alertes = 0
compteur_alertes = signaler_alerte(compteur_alertes)
compteur_alertes = signaler_alerte(compteur_alertes)
print(compteur_alertes)
In [ ]:
assert signaler_alerte(0) == 1
assert signaler_alerte(41) == 42
assert compteur_alertes == 2
print("OK. Compteur d'alertes réparé")
In [ ]:
def diagnostic(pression, temperature):
return "Pression " + niveau_pression(pression) + " / Temperature " + str(temperature)
In [ ]:
assert diagnostic(101, 18) == "Pression NOMINAL / Temperature 18"
assert diagnostic(45, -3) == "Pression CRITIQUE / Temperature -3"
assert diagnostic(88, 0) == "Pression ALERTE / Temperature 0"
print("OK. Diagnostic complet opérationnel")
In [ ]:
def verrouiller(module, code_acces="0000"):
if code_acces == "0000":
return "MODULE VERROUILLE"
else:
return "CODE REFUSE"
In [ ]:
assert verrouiller("Sas") == "MODULE VERROUILLE"
assert verrouiller("Sas", "0000") == "MODULE VERROUILLE"
assert verrouiller("Sas", "1234") == "CODE REFUSE"
print("OK. Verrouillage opérationnel")
In [ ]:
mesures = [12, 45, 7, 88, 23, 91, 4]
In [ ]:
i = 0
while i < 5:
print(i)
i = i + 2
print("fin, i vaut", i)
# Ma prédiction : 0, 2, 4 (trois lignes), puis « fin, i vaut 6 ».
# Le test est réévalué AVANT chaque tour. Après le tour où i valait 4, i passe à 6 :
# 6 < 5 est faux, la boucle s'arrête. i vaut donc 6 à la sortie, pas 5.
In [ ]:
# Ma réponse :
# La condition `carburant > 0` reste vraie éternellement parce que le corps de la boucle
# remet carburant à 100 au lieu de le faire décroître. Rien ne rapproche le programme de
# la condition d'arrêt.
# Plus petite correction : remplacer `carburant = 100` par une décrémentation,
# par exemple `carburant = carburant - 10`.
#
# Règle : dans un while, une variable au moins doit évoluer VERS la condition d'arrêt.
In [ ]:
for i in range(len(mesures)): # range(len(...)) commence à 0, pas à 1
print("capteur", i, ":", mesures[i])
# La version initiale commençait à l'indice 1 et sautait donc mesures[0] (la valeur 12).
# En Python le premier indice d'une liste est 0.
In [ ]:
def maximum(valeurs):
plus_grand = valeurs[0] # on part du premier élément, pas de 0 !
for v in valeurs:
if v > plus_grand:
plus_grand = v
return plus_grand
In [ ]:
assert maximum([12, 45, 7, 88, 23, 91, 4]) == 91
assert maximum([5]) == 5
assert maximum([3, 3, 3]) == 3
assert maximum([-10, -3, -50]) == -3, "attention aux valeurs négatives : ne partez pas de 0"
print("OK. Détection du maximum opérationnelle")
In [ ]:
def premier_defaillant(valeurs, seuil):
for i in range(len(valeurs)):
if valeurs[i] < seuil:
return i # return sort immédiatement de la fonction
return -1 # atteint seulement si la boucle s'est terminée
In [ ]:
assert premier_defaillant([12, 45, 7, 88], 20) == 0
assert premier_defaillant([45, 88, 7, 4], 10) == 2
assert premier_defaillant([45, 88, 91], 10) == -1
assert premier_defaillant([], 10) == -1
print("OK. Détection de défaillance opérationnelle")
In [ ]:
def somme_jusqu_a_sentinelle(flux):
total = 0
i = 0
while i < len(flux) and flux[i] != -1:
total = total + flux[i]
i = i + 1
return total
In [ ]:
assert somme_jusqu_a_sentinelle([10, 20, 30, -1, 999, 999]) == 60
assert somme_jusqu_a_sentinelle([-1, 5, 5]) == 0
assert somme_jusqu_a_sentinelle([1, 2, 3]) == 6
assert somme_jusqu_a_sentinelle([]) == 0
print("OK. Lecture du flux opérationnelle")
In [ ]:
soute = ["eau", "vivres", "outils", "piles", "filtres"]
# Chaque sous-liste est un rayonnage : [rayon_0, rayon_1, rayon_2]
# Chaque ligne = un étage de la soute.
stock = [[12, 5, 0],
[3, 8, 7],
[0, 0, 4],
[9, 1, 2]]
In [ ]:
print(soute[0])
print(soute[-1])
print(soute[1:3])
print(len(soute[1:3]))
# Ma prédiction :
# eau
# filtres
# ['vivres', 'outils']
# 2
# Une tranche [a:b] va de l'indice a INCLUS à l'indice b EXCLU : elle contient b - a
# éléments. L'indice -1 désigne le dernier élément.
In [ ]:
soute_test = ["piles", "pinces", "eau", "outils"]
# Version corrigée : on construit une nouvelle liste au lieu de modifier celle qu'on parcourt
soute_gardee = []
for objet in soute_test:
if objet[0] != "p":
soute_gardee.append(objet)
soute_test = soute_gardee
print(soute_test) # ['eau', 'outils']
# Pourquoi la version initiale échouait : après avoir retiré "piles" (indice 0), tous les
# éléments se décalent d'un cran. La boucle passe alors à l'indice 1, qui contient
# désormais "eau" : "pinces" a été SAUTÉ.
In [ ]:
assert soute_test == ["eau", "outils"]
print("OK. Purge de la soute correcte")
In [ ]:
def total_rayon(grille, r):
total = 0
for etage in grille: # etage est une liste : [rayon_0, rayon_1, rayon_2]
total = total + etage[r]
return total
In [ ]:
assert total_rayon(stock, 0) == 24
assert total_rayon(stock, 1) == 14
assert total_rayon(stock, 2) == 13
print("OK. Inventaire par rayon opérationnel")
In [ ]:
def au_dessus(valeurs, seuil):
return [v for v in valeurs if v > seuil]
In [ ]:
assert au_dessus([12, 45, 7, 88, 23], 20) == [45, 88, 23]
assert au_dessus([1, 2, 3], 10) == []
assert au_dessus([], 0) == []
print("OK. Filtrage opérationnel")
In [ ]:
def fusion(a, b):
resultat = []
i = 0
j = 0
while i < len(a) and j < len(b):
if a[i] <= b[j]:
resultat.append(a[i])
i = i + 1
else:
resultat.append(b[j])
j = j + 1
# une des deux listes est épuisée : on recopie ce qui reste de l'autre
while i < len(a):
resultat.append(a[i])
i = i + 1
while j < len(b):
resultat.append(b[j])
j = j + 1
return resultat
In [ ]:
assert fusion([1, 4, 9], [2, 3, 10]) == [1, 2, 3, 4, 9, 10]
assert fusion([], [2, 3]) == [2, 3]
assert fusion([5], []) == [5]
assert fusion([1, 1], [1]) == [1, 1, 1]
print("OK. Fusion opérationnelle, vous venez d'écrire la moitié d'un tri fusion")
In [ ]:
equipage = {
"Kowalski": "pilote",
"Ndiaye": "medecin",
"Reyes": "ingenieur",
"Sokolova": "pilote",
"Tanaka": "ingenieur",
}
# Plan de la station : à chaque module, la liste des modules directement accessibles
plan = {
"Sas": ["Couloir"],
"Couloir": ["Sas", "Cockpit", "Soute", "Labo"],
"Cockpit": ["Couloir"],
"Soute": ["Couloir", "Reacteur"],
"Labo": ["Couloir"],
"Reacteur": ["Soute"],
}
In [ ]:
print(equipage["Reyes"])
print(len(equipage))
print("Bowman" in equipage)
# print(equipage["Bowman"])
# Ma prédiction :
# ingenieur
# 5 (len d'un dictionnaire = son nombre de clés)
# False
# La 4e ligne lèverait une KeyError : accéder à une clé absente est une ERREUR,
# ce n'est pas None. Pour éviter ça : equipage.get("Bowman", "inconnu").
In [ ]:
def poste_de(registre, nom):
return registre.get(nom, "inconnu")
# Variante explicite, tout aussi correcte :
# def poste_de(registre, nom):
# if nom in registre:
# return registre[nom]
# return "inconnu"
print(poste_de(equipage, "Tanaka"))
print(poste_de(equipage, "Bowman"))
In [ ]:
assert poste_de(equipage, "Tanaka") == "ingenieur"
assert poste_de(equipage, "Bowman") == "inconnu"
print("OK. Registre sécurisé")
In [ ]:
def compter_postes(registre):
comptes = {}
for poste in registre.values():
if poste in comptes:
comptes[poste] = comptes[poste] + 1
else:
comptes[poste] = 1
return comptes
In [ ]:
resultat = compter_postes(equipage)
assert resultat == {"pilote": 2, "medecin": 1, "ingenieur": 2}
assert compter_postes({}) == {}
assert compter_postes({"A": "pilote"}) == {"pilote": 1}
print("OK. Recensement de l'équipage opérationnel")
In [ ]:
def voisins(plan, module):
return plan.get(module, [])
def nb_liaisons(plan):
total = 0
for liste_voisins in plan.values():
total = total + len(liste_voisins)
return total
In [ ]:
assert voisins(plan, "Cockpit") == ["Couloir"]
assert voisins(plan, "Couloir") == ["Sas", "Cockpit", "Soute", "Labo"]
assert voisins(plan, "Hangar") == []
assert nb_liaisons(plan) == 10
print("OK. Lecture du plan opérationnelle")
In [ ]:
def par_poste(registre):
groupes = {}
for nom, poste in registre.items():
if poste not in groupes:
groupes[poste] = []
groupes[poste].append(nom)
return groupes
In [ ]:
attendu = {"pilote": ["Kowalski", "Sokolova"],
"medecin": ["Ndiaye"],
"ingenieur": ["Reyes", "Tanaka"]}
assert par_poste(equipage) == attendu
assert par_poste({}) == {}
print("OK. Regroupement opérationnel")
In [ ]:
plan = {
"Sas": ["Couloir"],
"Couloir": ["Sas", "Cockpit", "Soute", "Labo"],
"Cockpit": ["Couloir"],
"Soute": ["Couloir", "Reacteur"],
"Labo": ["Couloir"],
"Reacteur": ["Soute"],
"Serre": ["Cellule"], # compartiment isolé du reste !
"Cellule": ["Serre"],
}
In [ ]:
def atteignables(plan, depart):
a_visiter = [depart]
visites = []
while len(a_visiter) > 0:
module = a_visiter.pop() # retire et renvoie le dernier élément
if module not in visites:
visites.append(module)
for v in plan.get(module, []):
a_visiter.append(v)
return visites
In [ ]:
r = atteignables(plan, "Sas")
assert sorted(r) == ["Cockpit", "Couloir", "Labo", "Reacteur", "Sas", "Soute"]
assert "Serre" not in r, "La serre ne doit PAS être atteignable depuis le sas"
assert sorted(atteignables(plan, "Serre")) == ["Cellule", "Serre"]
assert atteignables(plan, "Hangar") == ["Hangar"]
print("OK. Cartographie terminée, 2 compartiments isolés détectés : Serre et Cellule")
In [ ]:
def compte_a_rebours(n):
if n == 0:
print("DECOLLAGE")
else:
print(n)
compte_a_rebours(n - 1)
print("verif", n)
compte_a_rebours(3)
# Ma prédiction :
# 3
# 2
# 1
# DECOLLAGE
# verif 1
# verif 2
# verif 3
#
# Les « verif » sortent dans l'ORDRE INVERSE : chaque appel est mis en attente pendant
# que l'appel suivant se déroule, puis reprend là où il s'était arrêté. C'est exactement
# la PILE D'APPELS du chapitre en cours.