Corrigé Sujet N°14
- Simulation d'Évacuation d'une Pièce -
Vous pouvez télécharger les éléments suivants en cliquant sur les boutons associés :
Question 1
Écrire le corps de la méthode
nb_occupants_restants de la classe Piece. Cette méthode doit renvoyer le nombre total d'occupants encore présents dans la pièce.
Correction simple : La grille est une liste de listes (matrice 2D). On parcourt chaque ligne puis chaque case et on accumule les valeurs dans un compteur.
def nb_occupants_restants(self) -> int:
"""Renvoie le nombre total d'occupants restants dans la pièce."""
total = 0
for ligne in self.grille:
for case in ligne:
total += case
return total
Correction avancée : On peut condenser les deux boucles imbriquées en une seule expression avec
sum() et une compréhension de liste à double itération.
def nb_occupants_restants(self) -> int:
"""Version concise avec sum et compréhension de liste."""
return sum(case for ligne in self.grille for case in ligne)
Question 2
Écrire le corps de la fonction
evacuation qui simule l'évacuation complète de la pièce et renvoie le nombre de tours nécessaires. Si le paramètre silencieux vaut False, l'état de la pièce doit être affiché à chaque tour.
Correction : On boucle tant qu'il reste des occupants dans la pièce. À chaque itération on appelle
alerter() (qui simule un tour), on incrémente le compteur, et on affiche la pièce si demandé. On ajoute une garde contre les blocages infinis : si alerter() retourne False (aucun déplacement possible) alors qu'il reste des occupants, on interrompt la boucle.
def evacuation(p: Piece, silencieux: bool = True) -> int:
"""Simule l'évacuation complète et renvoie le nombre de tours nécessaires."""
nb_tours = 0
while p.nb_occupants_restants() > 0:
a_bouge = p.alerter(silencieux)
nb_tours += 1
if not silencieux:
print(p)
if not a_bouge:
# Sécurité : plus aucun mouvement possible, on arrête
break
return nb_tours
Remarque : Le paramètre
silencieux=True est passé à alerter() pour que les messages de déplacement internes soient aussi masqués ou affichés de façon cohérente. Le print(p) affiche l'état de la grille après chaque tour grâce à la méthode __str__ déjà définie.
Question 3
Modifier la méthode
ajouter_sortie afin qu'il soit aussi possible d'ajouter une sortie dans les directions "S" (sud) et "E" (est), qui ne sont pas encore prises en compte.
Analyse du code existant : La direction
"N" place une sortie sur la ligne 0 (bord nord) à la colonne position → tuple (0, position). La direction "O" place une sortie à la colonne 0 (bord ouest) sur la ligne position → tuple (position, 0). Par symétrie : "S" doit placer la sortie sur la dernière ligne (i_max) → tuple (i_max, position). "E" doit placer la sortie sur la dernière colonne (j_max) → tuple (position, j_max).
def ajouter_sortie(self, direction: str, position: int):
"""Permet d'ajouter des sorties dans les 4 directions (N, S, E, O)."""
if direction == "N":
self.sorties.append((0, position))
elif direction == "O":
self.sorties.append((position, 0))
elif direction == "S":
# AJOUT : bord sud = dernière ligne (i_max), colonne = position
self.sorties.append((self.i_max, position))
elif direction == "E":
# AJOUT : bord est = dernière colonne (j_max), ligne = position
self.sorties.append((position, self.j_max))
# Test avec test_ajouter_sortie()
# Pour une Piece(5, 7) : i_max=4, j_max=6
# ajouter_sortie("S", n1) → (4, n1)
# ajouter_sortie("E", n2) → (n2, 6)
Question 4
Identifier l'erreur logique et la variable non définie dans le code de la méthode
choix_sortie, puis effectuer les corrections nécessaires afin qu'elle renvoie la sortie la plus proche (distance de Manhattan).
Identification des deux bugs :
Bug 1 — Variable non définie : Dans la boucle, la ligne
distance = d2 fait référence à d2 qui n'est jamais calculé. Il faut calculer la distance de Manhattan de l'autre sortie candidate avant de la comparer : d2 = distance_de_manhattan(autre_sortie).
Bug 2 — Erreur logique dans la condition : La condition
if k < 0 est toujours fausse (k commence à 1 et croît). Le bloc de mise à jour du meilleur choix n'est donc jamais exécuté, et la méthode retourne systématiquement la première sortie de la liste. La condition correcte est if d2 < distance (on remplace par la sortie candidate si elle est plus proche). Il faut aussi renommer la variable distance en distance_min pour éviter un conflit avec la fonction locale du même nom.
def choix_sortie(self, i: int, j: int) -> tuple:
"""Renvoie la sortie la plus proche selon la distance de Manhattan."""
def distance_de_manhattan(destination):
return abs(i - destination[0]) + abs(j - destination[1])
assert len(self.sorties) > 0, "Aucune sortie"
choix = self.sorties[0]
distance_min = distance_de_manhattan(choix) # CORRECTION : renommé distance_min
for k in range(1, len(self.sorties)):
autre_sortie = self.sorties[k]
d2 = distance_de_manhattan(autre_sortie) # CORRECTION : d2 maintenant calculé
if d2 < distance_min: # CORRECTION : condition était "k < 0"
choix = autre_sortie
distance_min = d2
return choix
# Tests
# choix_sortie(0, 3) avec sorties [(0,5),(4,1),(3,6),(1,0)]
# distances : |0-0|+|3-5|=2, |0-4|+|3-1|=6, |0-3|+|3-6|=6, |0-1|+|3-0|=4
# → sortie la plus proche : (0, 5) ✓
Résumé des corrections : Deux erreurs coexistaient dans
choix_sortie : une variable d2 utilisée sans être définie (qui aurait levé une NameError si la condition avait été vraie), et une condition k < 0 logiquement impossible qui neutralisait tout le mécanisme de comparaison. La méthode se contentait donc de toujours retourner self.sorties[0], ignorant toutes les autres sorties.
© 2026 - Clément Legoubé