Un corrigé pédagogique pour comprendre et justifier vos réponses. Les conseils de rédaction ne constituent pas un barème officiel détaillé.
Application
Évacuation d’une pièce et choix de la sortie la plus proche
Une Piece est une grille rectangulaire, chaque case contenant de 0 à 5 occupants. ajouter_occupants(i, j, nb) ajoute au maximum la place disponible. Les portes sont stockées par coordonnées de case sur un bord et affichées par P. À chaque alerte, les occupants se déplacent d’une case vers une sortie, et chaque sortie ne laisse passer qu’une personne. Le moteur alerter est fourni, ainsi qu’une IHM tkinter à utiliser sans la modifier. Le modèle sert à programmer une simulation, pas à valider des normes réelles de sécurité.
p1 = Piece(5,7)
p1.ajouter_occupants(2,0,4)
p1.ajouter_occupants(3,4,1)
p1.ajouter_occupants(0,5,2)
p1.ajouter_sortie('N',5)
print(p1)État initial ; sortie au nord, colonne 5.
| 0 | 1 | 2 | 3 | 4 | 5(P au nord) | 6 |
|---|---|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 0 | 2 | 0 |
| 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 4 | 0 | 0 | 0 | 0 | 0 | 0 |
| 0 | 0 | 0 | 0 | 1 | 0 | 0 |
| 0 | 0 | 0 | 0 | 0 | 0 | 0 |
Exemple du PDF après 1 alerte(s). La sortie reste au nord, colonne 5.
| 0 | 1 | 2 | 3 | 4 | 5(P au nord) | 6 |
|---|---|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 0 | 1 | 0 |
| 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 0 | 4 | 0 | 0 | 0 | 0 | 0 |
| 0 | 0 | 0 | 0 | 0 | 1 | 0 |
| 0 | 0 | 0 | 0 | 0 | 0 | 0 |
Exemple du PDF après 2 alerte(s). La sortie reste au nord, colonne 5.
| 0 | 1 | 2 | 3 | 4 | 5(P au nord) | 6 |
|---|---|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 0 | 4 | 0 | 0 | 0 | 0 | 0 |
| 0 | 0 | 0 | 0 | 0 | 1 | 0 |
| 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 0 | 0 | 0 | 0 | 0 | 0 | 0 |
Exemple du PDF après 3 alerte(s). La sortie reste au nord, colonne 5.
| 0 | 1 | 2 | 3 | 4 | 5(P au nord) | 6 |
|---|---|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 0 | 0 | 4 | 0 | 0 | 1 | 0 |
| 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 0 | 0 | 0 | 0 | 0 | 0 | 0 |
Le dossier comporte le sujet et les fichiers listés dans les téléchargements. Les codes de départ sont reproduits ci-dessous. Travaillez sur une copie. Les appels professeur signalés dans les questions servent à présenter votre démarche ; vous pouvez aussi demander de l’aide en cas de difficulté.
Code fourni : IHM_evacuation.py
from simulation_evacuation import Piece, evacuation
from tkinter import *
from random import randint
################################################################################
# Il n'est pas nécessaire de comprendre (ni modifier) le code de ce programme. #
# Son execution ouvre une interface graphique qui facilitera vos tests. #
################################################################################
def creation_piece():
global choix_largeur, choix_profondeur, choix_nboccupants, piece_test
global dessin, dernier_affichage, nb_tour_evac
piece_test = Piece(choix_profondeur.get(), choix_largeur.get())
n = min(choix_nboccupants.get(), piece_test.capacite)
while n > 0:
i = randint(0, piece_test.i_max)
j = randint(0, piece_test.j_max)
nb = piece_test.ajouter_occupants(i, j, randint(1, min(5, n)))
n = n - nb
dernier_affichage = [[[None, None] for _ in range(
piece_test.j_max + 1)] for _ in range(piece_test.i_max + 1)]
dessin.delete(ALL)
nb_tour_evac.configure(text="")
def affichage_grille():
global piece_test, dessin, mode_daltonien, dernier_affichage, nb_occ_restants
if piece_test is not None:
couleurs = ["white", "blue", "green", "yellow", "orange", "red"]
for (lg, cl) in piece_test.sorties:
if lg == 0:
dessin.create_text(15*cl+22, 7, text="P")
elif cl == 0:
dessin.create_text(7, 15*lg+22, text="P")
elif lg == piece_test.i_max:
dessin.create_text(15*cl+22, 15*lg+37, text="P")
else:
dessin.create_text(15*cl+37, 15*lg+22, text="P")
for lg in range(piece_test.i_max + 1):
for cl in range(piece_test.j_max + 1):
nb = piece_test.grille[lg][cl]
case = dernier_affichage[lg][cl]
if case[0] is None:
case[0] = dessin.create_rectangle(
15*cl+15, 15*lg+15, 15*cl+30, 15*lg+30, fill="white")
if case[1] is None:
case[1] = dessin.create_text(15*cl+22, 15*lg+22, text="")
if dessin.itemcget(case[0], "fill") != couleurs[nb]:
dessin.itemconfig(case[0], fill=couleurs[nb])
if mode_daltonien.get() == "oui" and dessin.itemcget(case[1], "text") != str(nb):
dessin.itemconfig(case[1], text=str(nb))
if mode_daltonien.get() == "non" and dessin.itemcget(case[1], "text") != "":
dessin.itemconfig(case[1], text="")
nb_occ_restants.configure(text=str(piece_test.nb_occupants_restants()))
dessin.after(100, affichage_grille)
def clic_gauche(event):
global piece_test
if piece_test is not None:
cl, lg = event.x // 15, event.y // 15
if lg == 0:
# ajout d'une sortie au nord
piece_test.ajouter_sortie("N", min(cl-1, piece_test.j_max))
elif cl == 0:
# ajout d'une sortie à l'ouest
piece_test.ajouter_sortie("O", min(lg-1, piece_test.i_max))
elif lg > piece_test.i_max:
# ajout d'une sortie au sud
piece_test.ajouter_sortie("S", min(cl-1, piece_test.j_max))
elif cl > piece_test.j_max:
# ajout d'une sortie à l'est
piece_test.ajouter_sortie("E", min(lg-1, piece_test.i_max))
else:
# ajout d'occupants
piece_test.ajouter_occupants(lg-1, cl-1, 5)
def alerter_occupants():
global piece_test
if piece_test is not None and piece_test.sorties != []:
nb_tour_evac.configure(text="")
piece_test.alerter()
def evacuer_occupants():
global piece_test, nb_tour_evac
if piece_test is not None and piece_test.sorties != []:
nbT = evacuation(piece_test)
if piece_test.nb_occupants_restants() == 0:
nb_tour_evac.configure(
text="Evacuation effectuée en " + str(nbT) + " tours.")
else:
nb_tour_evac.configure(text="Echec de l'évacuation.")
if __name__ == "__main__":
global fen, choix_largeur, choix_profondeur, choix_nboccupants
global piece_test, dessin, mode_daltonien, nb_occ_restants, nb_tour_evac
piece_test = None
# création de la fenêtre
fen = Tk()
fen.title("IHM de simulation d'évacuation")
fen.geometry("430x650")
# ajout des zones de saisie permettant de paramétrer la simulation
Label(fen, text="Largeur de la pièce").grid(row=1, column=1, columnspan=2)
choix_largeur = Scale(fen, from_=10, to=20, orient=HORIZONTAL)
choix_largeur.set(10)
choix_largeur.grid(row=1, column=3)
Label(fen, text="Profondeur de la pièce").grid(
row=2, column=1, columnspan=2)
choix_profondeur = Scale(fen, from_=10, to=20, orient=HORIZONTAL)
choix_profondeur.set(10)
choix_profondeur.grid(row=2, column=3)
Label(fen, text="Nombre d'occupants placés aléatoirement \n(dans la limite de capacité de la pièce)").grid(
row=3, column=1, columnspan=2)
choix_nboccupants = Scale(fen, from_=10, to=2000, orient=HORIZONTAL)
choix_nboccupants.set(200)
choix_nboccupants.grid(row=3, column=3)
Label(fen, text="Affichage des nombres en plus des couleurs \n (mode daltonien)").grid(
row=4, column=1, columnspan=2)
mode_daltonien = StringVar()
Checkbutton(fen, text="", var=mode_daltonien, onvalue="oui",
offvalue="non").grid(row=4, column=3)
mode_daltonien.set("non")
btn_grille = Button(fen, text="Créer la pièce", command=creation_piece)
btn_grille.grid(row=5, column=2)
# ajout du canvas où sera dessinée la pièce
Label(fen, text="Un clic sur un côté de la pièce permet d'ajouter une sortie. \nPour ajouter des occupants, cliquer dans la pièce.").grid(
row=6, column=1, columnspan=3)
dessin = Canvas(fen, bg="grey", height=330, width=330)
dessin.grid(row=7, column=1, columnspan=3)
dessin.bind("<Button-1>", clic_gauche)
dessin.after(100, affichage_grille)
Label(fen, text="Nombre d'occupants actuellement dans la pièce :").grid(
row=8, column=1, columnspan=2)
nb_occ_restants = Label(fen, text="")
nb_occ_restants.grid(row=8, column=3)
# ajout des boutons d'alerte et d'évacuation
btn_alerte = Button(
fen, text="Alerter (un pas vers la sortie la plus proche)", command=alerter_occupants)
btn_alerte.grid(row=9, column=1, columnspan=2)
btn_evacuer = Button(fen, text="Evacuer", command=evacuer_occupants)
btn_evacuer.grid(row=9, column=3)
nb_tour_evac = Label(fen, text="")
nb_tour_evac.grid(row=10, column=1, columnspan=3)
# affichage de la fenêtre
fen.mainloop()
Code fourni : simulation_evacuation.py
from random import randint, shuffle
from copy import deepcopy
class Piece:
def __init__(self, profondeur, largeur):
self.grille = [[0 for _ in range(largeur)] for _ in range(profondeur)]
self.i_max = profondeur-1
self.j_max = largeur-1
self.capacite = profondeur * largeur * 5
self.sorties = []
def ajouter_occupants(self, i, j, nb):
''' permet d'ajouter jusqu'à nb occupants dans la case située ligne i et colonne j.
Le nombre d'occupants ajoutés est limité par la capacité d'accueil de la case (5).
Cette méthode renvoie le nombre d'occupants effectivement ajoutés.
'''
nb_add = min(nb, 5 - self.grille[i][j])
if nb_add > 0:
self.grille[i][j] = self.grille[i][j] + nb_add
return nb_add
def nb_occupants_restants(self):
''' renvoie le nombre d'occupants restants dans la pièce.
A FAIRE (QUESTION 1)
'''
pass
def ajouter_sortie(self, direction, position):
''' permet d'ajouter des sorties à la pièce.
A COMPLETER (QUESTION 3) (Pour l'instant, on n'utilise que deux directions !)
'''
if direction == "N":
self.sorties.append((0, position))
elif direction == "O":
self.sorties.append((position, 0))
def choix_sortie(self, i, j):
''' renvoie la sortie à utiliser pour une personne positionnée sur la ligne i et la colonne j.
A CORRIGER (QUESTION 4) (Pour l'instant, seule la 1ère sortie est utilisée !)
'''
assert len(self.sorties) > 0, "Aucune sortie"
choix = self.sorties[0]
distance = abs(i - choix[0]) + abs(j - choix[1])
for k in range(1, len(self.sorties)):
autre_sortie = self.sorties[k]
if k < 0:
choix = autre_sortie
distance = d2
return choix
def deplacer(self, i, j, nb, direction, silencieux=True):
''' effectue le déplacement dans la direction demandée d'au maximum
nb occupants actuellement en ligne i et colonne j.
Le déplacement est limité par la capacité d'accueil (5) de la case visée.
Cette fonction renvoie le nombre d'occupants déplacés.
IL N'EST PAS NECESSAIRE DE COMPRENDRE LE CODE DE CETTE METHODE.
'''
d = {"N": (-1, 0), "S": (1, 0), "E": (0, 1), "O": (0, -1)}
nv_i, nv_j = i + d[direction][0], j + d[direction][1]
nb_dep = min(nb, 5 - self.grille[nv_i][nv_j], self.grille[i][j])
if nb_dep > 0:
if not silencieux:
print("déplacement de ", nb_dep,
" occupant(s) (", i, ",", j, ") vers ", direction)
self.grille[i][j] = self.grille[i][j] - nb_dep
self.grille[nv_i][nv_j] = self.grille[nv_i][nv_j] + nb_dep
return nb_dep
def alerter(self, silencieux=True):
''' permet de simuler une alerte : chaque occupant se déplace d'une case
vers la sortie qui lui est conseillée par la méthode choix_sortie.
Cette méthode renvoie True si des déplacements ont pu avoir lieu, False sinon.
IL N'EST PAS NECESSAIRE DE COMPRENDRE LE CODE DE CETTE METHODE.
'''
old_grille = deepcopy(self.grille)
modif = False
for i in range(len(self.grille)):
for j in range(len(self.grille[i])):
if old_grille[i][j] > 0:
sortie_i, sortie_j = self.choix_sortie(i, j)
dx, dy = sortie_j-j, sortie_i-i
if dx == 0 and dy == 0:
if not silencieux:
print("évacuation d'un occupant (", i, ",", j, ")")
self.grille[i][j] = self.grille[i][j] - 1
nb_dep = 1
else:
mvt_possibles = []
if dx > 0:
mvt_possibles.append("E")
elif dx < 0 and j > 0:
mvt_possibles.append("O")
if dy > 0:
mvt_possibles.append("S")
elif dy < 0 and i > 0:
mvt_possibles.append("N")
shuffle(mvt_possibles)
nb_dep = self.deplacer(
i, j, old_grille[i][j], mvt_possibles[0], silencieux)
if nb_dep == 0 and len(mvt_possibles) > 1:
nb_dep = self.deplacer(
i, j, old_grille[i][j], mvt_possibles[1], silencieux)
if nb_dep > 0:
modif = True
return modif
def __str__(self):
''' Cette méthode permet de convertir une pièce en chaîne de caractères.
Ainsi, si p1 est une pièce, l'instruction print(p1) permettra d'afficher l'état actuel de la pièce dans la console.
IL N'EST PAS NECESSAIRE DE COMPRENDRE LE CODE DE CETTE METHODE.
'''
s = " "
for j in range(self.j_max+1):
if (0, j) in self.sorties:
s = s + "P "
else:
s = s + " "
s = s + "\n"
for i in range(len(self.grille)):
if (i, 0) in self.sorties:
s = s + "P"
else:
s = s + " "
s = s + str(self.grille[i])
if i != 0 and i != self.i_max and (i, self.j_max) in self.sorties:
s = s + "P\n"
else:
s = s + "\n"
s = s + " "
for j in range(self.j_max+1):
if (self.i_max, j) in self.sorties:
s = s + "P "
else:
s = s + " "
return s + "\n"
def evacuation(p, silencieux=True):
''' simule l'évacuation de la pièce et renvoie le nombre de tours nécessaire.
A chaque tour, chacun des occupants se déplace, si possible, d'une case
vers la sortie la plus proche. Si le paramètre silencieux vaut false,
l'état de la pièce à chaque tour est affiché dans la console.
A FAIRE EN QUESTION 2
'''
pass
def test_nb_occupants_restants():
''' Jeux de tests proposés pour la méthode nb_occupants_restants de la classe Piece.
'''
p1 = Piece(5, 7)
p1.ajouter_sortie("N", 5)
reussite = True
if p1.nb_occupants_restants() != 0:
print("La méthode nb_restants devrait renvoyer 0 quand la pièce est vide.")
reussite = False
n1 = randint(1, 5)
cases_occupees = {(0, 3): 4, (0, 1): 2, (3, 4): 3, (4, 0): n1, (4, 3): 2}
for c in cases_occupees:
p1.ajouter_occupants(c[0], c[1], cases_occupees[c])
if p1.nb_occupants_restants() != 11 + n1:
print("La méthode nb_restants renvoie",
p1.nb_occupants_restants(), " au lieu", 11 + n1)
reussite = False
if reussite == True:
print("Pas de problème détecté pour l'instant avec nb_occupants_restants. Il faudra vérifier que l'IHM affiche maintenant le bon nombre d'occupants restants.")
def test_evacuation(silencieux: bool = True):
''' Jeux de tests proposés pour la fonction evacuation.
'''
p1 = Piece(5, 7)
p1.ajouter_sortie("N", 5)
situations = [{"nom": "essai1", "cases_occupees": {(0, 3): 3, (1, 1): 1, (3, 2): 5}, "temps_attendu": 11},
{"nom": "essai2", "cases_occupees": {
(0, 3): 4, (0, 1): 2, (3, 4): 3, (4, 0): 1, (4, 3): 2}, "temps_attendu": 14},
{"nom": "essai3", "cases_occupees": {(0, 3): 1, (0, 1): 2, (3, 4): 1, (4, 0): 3, (4, 3): 5}, "temps_attendu": 15}]
verif = True
for s in situations:
for c, nb in s["cases_occupees"].items():
p1.ajouter_occupants(c[0], c[1], nb)
nbT = evacuation(p1, silencieux)
if nbT != s["temps_attendu"]:
print("La fonction evacuation renvoie ", nbT,
" au lieu de ", s["temps_attendu"], " pour ", s["nom"])
verif = False
if verif:
print("Pas de problème détecté pour l'instant avec l'évacuation. Il faudra vérifier avec l'IHM que les évacuations n'échouent plus.")
def test_ajouter_sortie():
''' Jeux de tests proposés pour tester les modifications apportées à la méthode ajouter_sortie de la classe Piece.
'''
p1 = Piece(5, 7)
p1.ajouter_sortie("N", 5)
n1 = randint(1, 5)
p1.ajouter_sortie("S", n1)
n2 = randint(1, 5)
p1.ajouter_sortie("E", n2)
p1.ajouter_sortie("O", 1)
if p1.sorties == [(0, 5), (4, n1), (n2, 6), (1, 0)]:
print("Pas de problème détecté avec le jeu de tests pour la méthode ajouter_sortie. Il faudra vérifier que l'ajout de sortie à l'est ou au sud de la pièce est maintenant possible via l'IHM.")
else:
print("L'ajout des sorties ne fonctionne pas correctement.")
def test_choix_sortie():
''' Jeux de tests proposés pour tester les modifications apportées à la méthode choix_sortie de la classe Piece.
'''
p1 = Piece(5, 7)
# Afin de pouvoir tester choix_sortie indépendamment de ajouter_sortie,
# on effectue ici une modification directe de l'attribut sorties de p1
p1.sorties = [(0, 5), (4, 1), (3, 6), (1, 0)]
try:
assert p1.choix_sortie(0, 3) == (0, 5)
assert p1.choix_sortie(0, 1) == (1, 0)
assert p1.choix_sortie(1, 2) == (1, 0)
assert p1.choix_sortie(3, 4) == (3, 6)
assert p1.choix_sortie(4, 0) == (4, 1)
assert p1.choix_sortie(4, 3) == (4, 1)
print("Pas de problème détecté avec le jeu de tests pour la méthode choix_sortie. Il faudra vérifier avec l'IHM que les occupants n'utilisent plus uniquement la première sortie lors des alertes.")
except:
print("La méthode choix_sortie ne renvoie pas la réponse attendue sur au moins l'un des tests.")
if __name__ == "__main__":
test_nb_occupants_restants()
test_evacuation(False)
test_ajouter_sortie()
test_choix_sortie()
Question 1
#Compléter nb_occupants_restants pour renvoyer le nombre total d’occupants dans la pièce. Utiliser test_nb_occupants_restants.
Indice
Une case peut contenir plusieurs personnes.
Comprendre la correction
def nb_occupants_restants(self):
total = 0
for ligne in self.grille:
for nombre in ligne:
total += nombre
return totalLa somme parcourt les personnes, pas seulement les cases occupées. Dans l’exemple initial,4+1+2=7 occupants. La méthode ne modifie pas la grille. Sur une pièce vide, toutes les valeurs valent 0, donc le résultat est 0.
Question 2
#Compléter evacuation(p, silencieux=True) pour simuler l’évacuation et renvoyer le nombre de tours. Si silencieux vaut False, afficher l’état à chaque tour. alerter renvoie True si des déplacements ont lieu et False sinon. Utiliser test_evacuation.
Indice
Utiliser le résultat de alerter comme signal de progression.
Comprendre la correction
def evacuation(p, silencieux=True):
tours = 0
while p.nb_occupants_restants() > 0:
if not p.alerter(silencieux):
break
tours += 1
if not silencieux:
print(p)
return toursLe compteur augmente après un tour effectif. Une pièce déjà vide demande 0 tour. Le retour False empêche de boucler sans fin si la simulation est bloquée ; dans ce cas, le nombre renvoyé compte les tours effectués mais ne prouve pas une évacuation complète. L’IHM fournie vérifie justement le nombre d’occupants restants avant d’afficher un succès. Les tests du fichier annoncent 11,14 et 15 tours pour leurs trois situations ; les déplacements peuvent inclure un choix aléatoire, d’où l’intérêt de tester aussi la conservation des personnes et la fin de simulation.
Question 3
#Étendre ajouter_sortie à S et E. position est l’indice de la case sur le côté correspondant. Utiliser test_ajouter_sortie puis vérifier les quatre directions dans l’IHM, sans modifier celle-ci.
Comprendre la correction
def ajouter_sortie(self, direction, position):
if direction == 'N':
self.sorties.append((0, position))
elif direction == 'O':
self.sorties.append((position, 0))
elif direction == 'S':
self.sorties.append((self.i_max, position))
elif direction == 'E':
self.sorties.append((position, self.j_max))| Direction | Coordonnées enregistrées |
|---|---|
| N | (0, position) |
| O | (position,0) |
| S | (self.i_max, position) |
| E | (position,self.j_max) |
Les indices maximaux valent dimension−1. Au sud la ligne est fixée, à l’est c’est la colonne. La méthode de clic de l’IHM sait déjà envoyer S ou E : seule la classe métier doit être complétée. Le test fourni tire parfois une position 5 pour le bord est d’une pièce de profondeur 5 ; cet indice est hors grille. C’est une faiblesse du test fourni : pour vérifier une porte utilisable, choisir une ligne entre 0 et 4.
Question 4
#Dans choix_sortie, identifier la condition logique incorrecte et la variable non définie, puis renvoyer la sortie la plus proche. Utiliser test_choix_sortie et poursuivre dans l’IHM.
PythonChoisir selon les déplacements réellement possiblesÉcrivez votre solution et mettez-la à l’épreuve
Corrigez choix_sortie(self, i, j). Parmi self.sorties, renvoyez le couple (ligne, colonne) minimisant la distance de Manhattan : abs(i-ligne) + abs(j-colonne). En cas d’égalité, conservez la première sortie enregistrée. Une assertion refuse l’absence de sortie. Le défi isole ce choix, sans simuler les mouvements ni l’IHM.
class Piece:
def __init__(self, profondeur, largeur):
self.grille = [[0 for _ in range(largeur)] for _ in range(profondeur)]
self.i_max = profondeur-1
self.j_max = largeur-1
self.capacite = profondeur * largeur * 5
self.sorties = []
def ajouter_sortie(self, direction, position):
if direction == 'N':
self.sorties.append((0, position))
elif direction == 'O':
self.sorties.append((position, 0))
elif direction == 'S':
self.sorties.append((self.i_max, position))
elif direction == 'E':
self.sorties.append((position, self.j_max))
def choix_sortie(self, i, j):
# Complétez cette méthode
pass
Les cas de test proposés :
- La seconde sortie est plus proche : Les distances sont 7 et 4 ; la seconde sortie doit remplacer la première.
- Manhattan et non Euclide : Vers (0,0) : 6 pas ; vers (3,8) : 5 pas. La diagonale euclidienne donnerait un autre choix.
- Première sortie en cas d’égalité : Les deux distances valent 2 ; l’ordre d’enregistrement départage.
- Déjà devant une sortie : Une distance nulle est le minimum possible.
- Refuser une pièce sans sortie : L’assertion doit intervenir avant le premier accès à la liste.
Indice
La valeur comparée doit mesurer la proximité, pas l’indice dans la liste.
Comprendre la correction
k provient de range(1,len(sorties)) : la condition k<0 est donc toujours fausse. En outre d 2 n’est jamais calculée. Il faut calculer pour chaque sortie la distance de Manhattan |i−ligne|+|j−colonne| et la comparer à la meilleure distance rencontrée.
def choix_sortie(self, i, j):
assert len(self.sorties) > 0, 'Aucune sortie'
choix = self.sorties[0]
distance = abs(i - choix[0]) + abs(j - choix[1])
for autre_sortie in self.sorties[1:]:
d2 = abs(i - autre_sortie[0]) + abs(j - autre_sortie[1])
if d2 < distance:
choix = autre_sortie
distance = d2
return choixCette distance compte les déplacements horizontaux et verticaux, contrairement à une diagonale euclidienne que les occupants ne peuvent pas parcourir directement. En cas d’égalité, le test strict conserve la première sortie enregistrée. L’assertion existante interdit le choix quand aucune sortie n’existe.
Pour un occupant en ligne 3, colonne 4 et une sortie en (3, 6), il faut deux pas horizontaux et aucun pas vertical : la distance vaut 2. Vers (0, 5), il faut trois pas verticaux et un horizontal, soit 4. Les distances sont comparées sur la même base et la sortie de distance 2 remplace celle de distance 4. Le programme ne calcule pas un trajet complet ; il choisit une destination selon cette distance. Les contraintes d’occupation des cases et les mouvements effectifs restent gérés par alerter, qu’il ne faut pas réécrire pour répondre à cette question.
Comprendre le minimumUn atelier pour expérimenter
Choisissez une réponse puis confrontez votre intuition à l’explication. Vous pouvez modifier vos choix.
Lire les réponses et leurs explications
- Pourquoi k<0 ne sélectionne aucune sortie ?
k commence à 1 et reste positif.. La condition ne peut jamais réussir.
- Deux sorties à même distance : laquelle garde le code corrigé ?
La première enregistrée.. Le test strict préserve le choix précédent.
Appuyez votre explication sur les valeurs et les conditions exactes du programme.
Quelle porte conseiller à cet occupant ?Un atelier pour expérimenter
Déplacez une personne dans la pièce 5×7. Les quatre sorties sont celles du test fourni. Comparez leurs distances et la porte retenue.
Lire le résultat de l’expérience initiale
Sortie conseillée : (3, 6), distance2.
Chaque pas change soit la ligne, soit la colonne. En cas d’égalité, la première sortie du tableau est conservée.
| Sortie | Distance | Choix |
|---|---|---|
| (0, 5) | 4 | |
| (4, 1) | 4 | |
| (3, 6) | 2 | Retenue |
| (1, 0) | 6 |
Le bon critère de distance dépend des déplacements autorisés dans le modèle.
Du sujet à la méthode
Votre prochaine séance de révision
- Tester les fonctions de la classe avant de vérifier leur raccordement à l’IHM.
- Un compteur de tours ne doit pas être confondu avec la preuve que la pièce est vide.
Retrouver ces notions dans d’autres sujets
Toutes les annales de NSI · Le guide pour préparer le bac NSI 2027
Énoncé : sujet 26_BCG_NSI_14 (PDF). Corrigé et explications pédagogiques proposés par Sofien.
