Épreuve écrite · 2026 · Jour 2

Bac NSI 2026 Amérique du Nord jour 2

Ce sujet relie l’ordonnancement d’un processeur, la progression d’un tournoi et l’analyse des résultats d’une course. Les 37 corrections s’appuient sur des traces d’état et des tests de bornes : qui attend, qui gagne, quelle donnée doit changer ? Les trois exercices indépendants sont à traiter en 3 h 30 sans calculatrice.

Dans ce sujet

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é.

Exercice 1 · 6 points

Processus : états, interblocage et ordonnancement tourniquet

Le système d’exploitation répartit le temps d’un processeur entre des processus issus d’une ou plusieurs applications. Dans le modèle à un seul cœur utilisé ici, un processus s’exécute à un instant donné, mais les alternances rapides donnent une impression de simultanéité. Interrompre un processus pour en exécuter un autre s’appelle la préemption.

La figure 1 comporte un état à gauche recevant « création », un à droite menant à « fin », et un état en bas. Une flèche gauche→droite est à nommer, la flèche droite→gauche est déjà nommée préemption, les flèches droite→bas et bas→gauche sont à nommer.

Question 1

#

Compléter le schéma avec élu, prêt, bloqué, élection, blocage et déblocage.

Indice

Le processus qui peut se terminer est celui qui est en train de s’exécuter.

Comprendre la correction
Élément du schémaTerme à placer
État après création (à gauche)Prêt
État avant fin (à droite)Élu
État inférieurBloqué
Prêt → éluÉlection
Élu → prêtPréemption, déjà indiquée
Élu → bloquéBlocage
Bloqué → prêtDéblocage

Prêt signifie apte à s’exécuter mais en attente de processeur. Élu signifie actuellement exécuté. Bloqué signifie en attente d’une ressource ou d’un événement. Un déblocage ne donne pas automatiquement le processeur : il remet le processus parmi les prêts.

Voir la question dans le sujet PDF, p. 2 (nouvel onglet)

P1 gère l’interface (listes de morceaux, lecture/pause), P2 télécharge la musique et remplit un cache, P3 décode le son. L’utilisateur cache l’interface en mettant l’application en arrière-plan ; P2 attend la carte Wi-Fi ; P3 décode et envoie le flux au système.

Question 2

#

Donner les états de P1, P2 et P3 dans la situation de streaming décrite.

Indice

Une fenêtre en arrière-plan ne définit pas à elle seule un état du processus.

Comprendre la correction

P2 est bloqué en attendant l’accès à la carte Wi-Fi ; P3 est élu puisqu’il effectue le décodage au processeur. Pour P1, la lecture attendue est prêt s’il reste exécutable mais n’a pas le processeur. Le seul fait que sa fenêtre soit cachée ne suffit toutefois pas, dans un système réel, à déterminer son état : un processus d’interface attendant un événement pourrait être bloqué. Il faut donc annoncer l’hypothèse « P1 reste prêt à s’exécuter » plutôt que confondre visibilité de la fenêtre et état système.

Voir la question dans le sujet PDF, p. 3 (nouvel onglet)

Question 3

#

Quand un interblocage de processus peut-il survenir ?

Indice

Il faut une dépendance circulaire persistante, pas seulement un processus temporairement bloqué.

Comprendre la correction

Plusieurs processus attendent indéfiniment des ressources détenues par d’autres processus du même groupe, sans qu’aucun puisse avancer jusqu’à la libération attendue. Avec des ressources exclusives, un cycle d’attente peut ainsi bloquer tout le groupe : P1 garde A et attend B, pendant que P2 garde B et attend A. Une simple attente d’une ressource qui sera libérée normalement n’est pas un interblocage.

Voir la question dans le sujet PDF, p. 3 (nouvel onglet)

GPU, MIC, CAM et CAL sont chacune utilisables par un seul processus à la fois. Ordres des opérations :

P1P2P3P4
demander MICdemander CALdemander CAMdemander GPU
demander CALdemander MIClibérer CAMdemander CAL
libérer CALlibérer MICdemander CALdemander CAM
libérer MIClibérer CALdemander MIClibérer CAM
demander CAMdemander CAMlibérer MIClibérer CAL
demander GPUlibérer CAMlibérer CALdemander MIC
libérer CAM-demander GPUlibérer GPU
libérer GPU-libérer GPUlibérer MIC

Question 4

#

Justifier qu’un interblocage peut apparaître pour les quatre programmes de demandes de ressources.

Indice

Les deux premières demandes de P1 et P2 sont dans l’ordre inverse.

Comprendre la correction

Un scénario suffit : P1 obtient MIC ; avant qu’il demande CAL, P2 obtient CAL. P1 demande alors CAL et attend P2 ; P2 demande MIC et attend P1. Aucun n’atteint ses instructions de libération. Le cycle MIC/P1 → CAL/P2 → MIC est établi. Il n’est pas nécessaire de bloquer aussi P3 et P4 pour prouver qu’un interblocage est possible. Ce n’est pas garanti pour toutes les exécutions : l’entrelacement choisi le rend possible.

Voir la question dans le sujet PDF, p. 3 (nouvel onglet)

Question 5

#

Quel intérêt présente une machine équipée de plusieurs processeurs ?

Indice

Distinguez alternance sur un processeur et exécution simultanée sur plusieurs unités.

Comprendre la correction

Elle peut exécuter réellement plusieurs processus en parallèle, améliorer la réactivité et augmenter le débit de calcul lorsque les tâches sont parallélisables. Cela ne multiplie pas automatiquement la vitesse de tout programme : les parties séquentielles, les ressources partagées et les synchronisations limitent le gain. Plusieurs processeurs n’éliminent pas non plus les interblocages.

Voir la question dans le sujet PDF, p. 3 (nouvel onglet)

Question 6

#

Donner un avantage et un inconvénient d’un système sur puce de smartphone.

Indice

L’intégration réduit l’encombrement mais réduit aussi la modularité.

Comprendre la correction

Un SoC intègre plusieurs fonctions sur une même puce, par exemple CPU, GPU et contrôleurs. Avantage : un ensemble compact et économe en énergie, adapté à une batterie et à un appareil léger. Inconvénient : une réparation ou une évolution séparée d’un composant est difficile ; la panne ou l’obsolescence d’un élément peut imposer de remplacer l’ensemble. Les échanges courts entre composants peuvent aussi améliorer les performances.

Voir la question dans le sujet PDF, p. 3 (nouvel onglet)

Partie B : ordonnanceur tourniquet

Le processus en tête est élu pendant au plus 2 ms. S’il termine, on le retire ; sinon il rejoint la queue. D’autres processus arrivent pendant l’exécution. La figure 2 commence par P1 entre 0 et 2 ms et repère les instants d’arrivée ci-dessous.

ProcessusArrivée (ms)Exécution totale (ms)
P106
P214
P335
P453

Question 7

#

Compléter le chronogramme round-robin avec quantum 2 ms, en tenant compte des arrivées.

Indice

Tenez une file des processus prêts à chaque fin de quantum, en intégrant les arrivées survenues pendant le créneau.

Comprendre la correction
Intervalle (ms)ProcessusTemps restant à la fin
0-2P14
2-4P22
4-6P12
6-8P33
8-10P20
10-12P41
12-14P10
14-16P31
16-17P40
17-18P30

Les nouveaux processus rejoignent la queue dès leur arrivée. Après 0-2, P2 est donc devant P1 replacé en queue. À la fin du créneau 4-6, P4 arrivé à 5 ms précède le retour de P1. Lorsqu’un processus n’a plus qu’une milliseconde à faire, on passe immédiatement au suivant : le quantum est une durée maximale, pas un créneau qui doit rester inutilisé jusqu’à son terme. Le temps total est 6+4+5+3 = 18 ms, sans inactivité ni surcoût de commutation dans ce modèle.

Voir la question dans le sujet PDF, p. 4 (nouvel onglet)
P1 = {'nom': 'P1', 'arrivee': 0, 'temps': 6}
P2 = {'nom': 'P2', 'arrivee': 1, 'temps': 4}
P3 = {'nom': 'P3', 'arrivee': 3, 'temps': 5}
P4 = {'nom': 'P4', 'arrivee': 5, 'temps': 3}
quantum = 2

creer_file_vide() crée ; est_vide(f) teste ; enfiler(f,x) ajoute en queue et renvoie None ; defiler(f) retire la tête et renvoie cet élément.

Question 8

#

Créer une file fp contenant P1, P2, P3, P4 par ordre d’arrivée, le premier arrivé en tête.

Indice

Enfilez dans l’ordre chronologique sans affecter le résultat de enfiler.

Comprendre la correction
fp = creer_file_vide()
enfiler(fp, P1)
enfiler(fp, P2)
enfiler(fp, P3)
enfiler(fp, P4)

Enfiler ajoute en queue : le premier élément ajouté reste donc en tête. Les dictionnaires de processus sont conservés comme objets dans la file. La fonction enfiler modifie la file et renvoie None ; il ne faut pas écrire fp = enfiler(fp,P1). Cette construction fournit une liste d’attente ordonnée, sans simuler à elle seule les instants d’arrivée du chronogramme.

Voir la question dans le sujet PDF, p. 5 (nouvel onglet)
def execute_un_processus(file_d_attente, t):
    processus = defiler(file_d_attente)
    if processus["temps"] ... quantum:
        processus["temps"] = ...
        ...
        return t + ...
    else:
        return t + ...

Question 9

#

Compléter execute_un_processus(file_d_attente,t) pour exécuter un créneau et renvoyer sa date de fin.

PythonExécuter un créneau de tourniquet sans perdre de tempsÉcrivez votre solution et mettez-la à l’épreuve

Complétez execute_un_processus(file_d_attente, t). La file non vide contient des dictionnaires avec nom, arrivee et temps, ce dernier étant le temps restant positif. Le quantum vaut 2. Défilez un processus ; s’il reste plus d’un quantum, réduisez son temps et réenfilez le même objet. Sinon, il termine et reste hors de la file. Renvoyez la nouvelle date. Comme le code du sujet, ne remettez pas à zéro le champ temps de l’objet terminé : cette partie ne conserve pas d’historique et ignore les nouvelles arrivées.

def execute_un_processus(file_d_attente,t):
    # À vous de jouer
    pass

Les cas de test proposés :

  • Un processus doit revenir en queue : Deux unités sont consommées et le même objet A se place derrière B.
  • Un processus court termine avant la fin maximale du créneau : Le quantum est une limite, pas une durée imposée de 2 pour tout processus.
  • Exactement un quantum : Une égalité termine le processus : il ne doit pas revenir avec un temps nul.
  • Respecter l’objet terminé du code fourni : L’état restant d’un objet retiré n’est pas utilisé par cette simulation. On conserve ici l’effet exact du squelette.
  • Deux créneaux successifs : L’ordre FIFO sert B avant le dernier morceau de A ; la date renvoyée remplace t au prochain appel.
Indice

La fonction doit avancer le temps d’une durée différente selon les deux cas.

Comprendre la correction
def execute_un_processus(file_d_attente, t):
    processus = defiler(file_d_attente)
    if processus["temps"] > quantum:
        processus["temps"] -= quantum
        enfiler(file_d_attente, processus)
        return t + quantum
    else:
        return t + processus["temps"]

Si le temps restant dépasse le quantum, on le diminue puis remet le même dictionnaire en queue. Sinon le processus finit, reste hors de la file et consomme exactement son temps restant. L’égalité temps = quantum appartient à la branche de fin : réenfiler un processus de temps nul serait inutile. Le code demandé ne remet pas explicitement temps à zéro pour l’objet terminé ; il suffit à la simulation puisque cet objet n’est plus planifié. Une application conservant un historique pourrait mettre à jour ce champ après avoir sauvé la durée à ajouter.

Voir la question dans le sujet PDF, p. 5 (nouvel onglet)

Désormais tous les processus à traiter sont déjà présents ; les champs arrivee sont ignorés. On simule jusqu’à vider la file.

def execute_tous_processus(file_d_attente):
    t = 0
    while ...:
        t = ...
    return t

Question 10

#

Compléter execute_tous_processus lorsque tous les processus sont déjà arrivés, en commençant à t=0.

Indice

La condition de boucle doit porter sur l’état de la file après les étapes, pas sur sa taille initiale.

Comprendre la correction
def execute_tous_processus(file_d_attente):
    t = 0
    while not est_vide(file_d_attente):
        t = execute_un_processus(file_d_attente, t)
    return t

L’appel renvoie la nouvelle date courante ; il faut l’affecter à t plutôt que l’ajouter encore une fois. Chaque créneau diminue le travail restant et finit par retirer un processus, donc la boucle termine si les durées et le quantum sont positifs. Une file vide renvoie 0 immédiatement. Cette partie ignore explicitement les arrivées : elle ne reproduit donc pas exactement l’ordre de la question 7, même si le total de travail reste 18 ms.

Voir la question dans le sujet PDF, p. 6 (nouvel onglet)
Un quantum plus grand termine-t-il plus vite ?Un atelier pour expérimenter

Faites varier le quantum et décidez si les arrivées réelles sont prises en compte. Le modèle trace chaque créneau et les instants de fin, sans coût de commutation.

Lire le résultat de l’expérience initiale

Toutes les tâches sont terminées à 18 ms

Le quantum change le partage et les dates individuelles de fin. Sans surcoût et sans temps mort, la somme du travail reste 18 ms. Les nouveaux arrivants sont insérés avant le retour du processus préempté.

Début (ms)Fin (ms)ProcessusReste (ms)
02P14
24P22
46P12
68P33
810P20
1012P41
1214P10
1416P31
1617P40
1718P30

Le tourniquet vise le partage et la réactivité. Dans ce modèle, le quantum ne réduit pas la quantité totale de calcul.

Revoir les notions de cet exercice

Exercice 2 · 6 points

Tennis : objets, tri et arbre du tournoi

L’exercice modélise des matchs de tennis en simple et un tournoi à partir des quarts de finale. Les noms, âges, points et résultats ci-dessous sont les données du sujet, parfois fictives ou datées ; ils ne décrivent pas le classement WTA actuel. La WTA est citée comme contexte de l’organisation du tennis professionnel féminin.

class Joueuse:
    def __init__(self, nom, prenom, pays, age, point):
        self.nom = nom
        self.prenom = prenom
        self.pays = pays
        self.age = age
        self.point = point
        self.victoire = 0
        self.defaite = 0

nom, prenom, pays sont des chaînes ; age et point des entiers.

Question 1

#

Instancier pegula : nom Pegula, prénom Jessica, pays USA, 29 ans, 6101 points.

Indice

Le nom précède le prénom dans la signature du constructeur.

Comprendre la correction
pegula = Joueuse("Pegula", "Jessica", "USA", 29, 6101)

Les arguments suivent l’ordre du constructeur. Les compteurs de victoire et défaite sont initialisés automatiquement à zéro et ne sont pas à fournir.

Voir la question dans le sujet PDF, p. 7 (nouvel onglet)
VariableNomPrénomPaysÂgePoints du sujet
gauffGauffCocoUSA206063
paloniPaloniMartaEspagne234843
sabalenkaSabalenkaArynaBiélorussie2510541
swiatekSwiatekIgaPologne227470
def ajouter_victoire(self, adversaire):
    ...
    ...

Question 2

#

Compléter ajouter_victoire(self,adversaire), qui incrémente la victoire de la joueuse et la défaite de son adversaire.

Indice

La victoire et la défaite concernent deux objets distincts.

Comprendre la correction
def ajouter_victoire(self, adversaire):
    self.victoire += 1
    adversaire.defaite += 1

self est la gagnante sur laquelle la méthode est appelée. adversaire est un autre objet Joueuse. Les deux compteurs changent sur deux instances différentes ; on ne doit pas incrémenter les défaites de self. Les points WTA ne sont pas modifiés, faute de règle d’attribution fournie.

Voir la question dans le sujet PDF, p. 7, 8 (nouvel onglet)

Question 3

#

Marta Paloni a été battue par Iga Swiatek dans le scénario du sujet. Enregistrer ce résultat.

Indice

Appelez la méthode sur celle qui a gagné.

Comprendre la correction
swiatek.ajouter_victoire(paloni)

L’objet placé avant le point est la gagnante, puisque la méthode augmente sa victoire. L’adversaire transmis reçoit la défaite.

Voir la question dans le sujet PDF, p. 8 (nouvel onglet)

L’opérateur < des objets Joueuse est supposé redéfini pour comparer leurs points : swiatekFalse et swiatekTrue. On trie par points croissants la liste [swiatek,gauff,paloni,sabalenka,pegula] avec :

def tri_insertion(liste):
    for i in range(1, len(liste)):
        j = i
        while j > 0 and liste[j] < liste[j - 1]:
            liste[j], liste[j - 1] = liste[j - 1], liste[j]
            j = j - 1

Question 5

#

Compléter les étapes du tri, une ligne pour chaque échange.

Indice

Comparez les nombres de points, pas les noms des joueuses.

Comprendre la correction
ÉtapeListe après l’échange
0swiatek, gauff, paloni, sabalenka, pegula
1gauff, swiatek, paloni, sabalenka, pegula
2gauff, paloni, swiatek, sabalenka, pegula
3paloni, gauff, swiatek, sabalenka, pegula
4paloni, gauff, swiatek, pegula, sabalenka
5paloni, gauff, pegula, swiatek, sabalenka

Le préfixe traité reste trié après chaque itération externe. Paloni, à 4 843 points, remonte deux places ; Sabalenka, à 10 541, ne bouge pas lors de son insertion. Pegula, à 6 101, dépasse Sabalenka puis Swiatek, mais reste après Gauff, à 6 063. On n’ajoute pas de ligne lorsqu’aucun échange n’a lieu, car le tableau demande les échanges, pas les tours de boucle.

Voir la question dans le sujet PDF, p. 9 (nouvel onglet)

Un score est une liste de couples (jeux joueuse1, jeux joueuse2). Exemple de la finale de Madrid 2024 donnée : Swiatek contre Sabalenka, [(7,5),(4,6),(7,6)]. Aucun set ni match terminé ne finit à égalité dans le modèle.

class Match:
    def __init__(self, intitule, joueuse1, joueuse2):
        self.intitule = intitule
        self.joueuse1 = joueuse1
        self.joueuse2 = joueuse2
        self.gagnante = None
        self.perdante = None
        self.score = None

    def resultat_match(self, score):
        self.score = score
        nb_set_joueuse1 = 0
        nb_set_joueuse2 = 0
        # code incomplet
finale_mad_24 = Match("finale Madrid 24", swiatek, sabalenka)
finale_mad_24.resultat_match([(7,5), (4,6), (7,6)])

Question 6

#

Compléter resultat_match : enregistrer le score, trouver gagnante/perdante puis mettre à jour leurs bilans.

Indice

Comptez les sets remportés, puis utilisez ajouter_victoire sur la gagnante.

Comprendre la correction
def resultat_match(self, score):
    self.score = score
    nb_set_joueuse1 = 0
    nb_set_joueuse2 = 0
    for jeux1, jeux2 in score:
        if jeux1 > jeux2:
            nb_set_joueuse1 += 1
        else:
            nb_set_joueuse2 += 1
    if nb_set_joueuse1 > nb_set_joueuse2:
        self.gagnante = self.joueuse1
        self.perdante = self.joueuse2
    else:
        self.gagnante = self.joueuse2
        self.perdante = self.joueuse1
    self.gagnante.ajouter_victoire(self.perdante)

Chaque tuple décrit les jeux gagnés dans un set. Le match se décide au nombre de sets gagnés, pas à la somme des jeux. Pour [(7,5),(4,6),(7,6)], la joueuse 1 gagne les sets 1 et 3 : elle remporte le match 2-1. Les références gagnante et perdante pointent vers les objets déjà existants ; on ne crée pas de nouvelles joueuses. L’appel final met à jour les deux bilans une seule fois.

On suppose un score terminé et valide sans égalité, comme l’indique l’énoncé. Cette méthode doit être appelée une fois pour enregistrer le match ; si l’application permet de corriger un score déjà saisi, il faudrait d’abord annuler l’ancien effet sur les compteurs ou gérer explicitement cet état. Cette extension n’est pas fournie par le simple squelette.

Voir la question dans le sujet PDF, p. 10 (nouvel onglet)

Partie B : arbre du tournoi

Finale F
├─ Demi-finale D1
│  ├─ Quart Q1
│  └─ Quart Q2
└─ Demi-finale D2
   ├─ Quart Q3
   └─ Quart Q4
class Arbre:
    def __init__(self, racine, gauche, droit):
        self.racine = racine
        self.gauche = gauche
        self.droit = droit

racine est un Match ; gauche et droit sont des Arbre ou None.

Question 7

#

Pourquoi un tournoi se modélise-t-il par un arbre binaire ?

Indice

La finale dépend de deux demi-finales, chacune de deux quarts.

Comprendre la correction

Chaque match d’un tour réunit les gagnantes de deux matchs du tour précédent. Le nœud du match possède donc deux sous-arbres, un par provenance. À partir des quarts seulement, les quatre quarts sont les feuilles, les demi-finales leurs parents et la finale la racine. Ce sont les matchs, et non directement les joueuses, qui constituent les nœuds du modèle.

Voir la question dans le sujet PDF, p. 10 (nouvel onglet)
Q1 = Match("Quart de finale 1", gauff, pilar)
Q2 = Match("Quart de finale 2", paloni, inie)
Q3 = Match("Quart de finale 3", pegula, sabalenka)
Q4 = Match("Quart de finale 4", swiatek, jabeur)
D1 = Match("Demi-finale 1", None, None)
D2 = Match("Demi-finale 2", None, None)
F = Match("Finale", None, None)

pilar, inie et jabeur sont supposées instanciées. D1 reçoit les gagnantes de Q1 et Q2 ; D2 celles de Q3 et Q4 ; F celles de D1 et D2.

Question 8

#

Instancier tournoi à partir des matchs de Madrid 2025 indiqués.

Indice

Conservez les deux niveaux de modèles : un Arbre contient un Match.

Comprendre la correction
tournoi = Arbre(F,
    Arbre(D1, Arbre(Q1, None, None), Arbre(Q2, None, None)),
    Arbre(D2, Arbre(Q3, None, None), Arbre(Q4, None, None)))

Chaque feuille doit aussi être un objet Arbre contenant son Match. Les enfants absents sont None. L’objet F est la valeur racine de tournoi, pas l’arbre lui-même. Les mêmes objets Match sont partagés avec les variables Q1, D1, etc. : modifier un match par sa variable se voit donc dans l’arbre.

Voir la question dans le sujet PDF, p. 11 (nouvel onglet)
Q1.resultat_match([(6,4), (7,5)])

Question 9

#

Q1 est gagné par gauff 6-4, 7-5. Compléter tournoi. ... = gauff pour la placer en joueuse1 de D1.

Indice

Descendez d’un niveau d’arbre avant d’accéder à l’objet Match.

Comprendre la correction
tournoi.gauche.racine.joueuse1 = gauff

tournoi.gauche est l’arbre de la demi-finale D1 ; .racine est le Match D1 ; .joueuse1 est l’emplacement réservé à la gagnante du quart gauche Q1. Le détour par racine est indispensable car Arbre ne possède pas directement d’attribut joueuse1.

Voir la question dans le sujet PDF, p. 11 (nouvel onglet)

Question 10

#

Qu’est-ce qu’un programme récursif ?

Indice

Identifiez l’auto-appel et le cas qui empêche de descendre indéfiniment.

Comprendre la correction

Il comporte une fonction qui s’appelle elle-même, directement ou indirectement, pour résoudre un sous-problème. Un mécanisme de terminaison arrête ces appels, par exemple l’arrivée sur un sous-arbre absent ou un état déjà renseigné. Une simple répétition par boucle n’est pas de la récursivité.

Voir la question dans le sujet PDF, p. 11 (nouvel onglet)
def mise_a_jour(self):
    if self.racine.joueuse1 is None:
        if self.gauche is not None:
            if ...:
                ... = self.gauche.racine.gagnante
            else:
                self.gauche.mise_a_jour()
    if self.racine.joueuse2 is None:
        if self.droit is not None:
            if ...:
                ... = self.droit.racine.gagnante
            else:
                ...

Question 11

#

Compléter mise_a_jour aux lignes 6,7,13,14,16.

Indice

Le nœud enfant possède un Match dans racine ; sa gagnante doit être non None pour remonter.

Comprendre la correction
def mise_a_jour(self):
    if self.racine.joueuse1 is None:
        if self.gauche is not None:
            if self.gauche.racine.gagnante is not None:
                self.racine.joueuse1 = self.gauche.racine.gagnante
            else:
                self.gauche.mise_a_jour()
    if self.racine.joueuse2 is None:
        if self.droit is not None:
            if self.droit.racine.gagnante is not None:
                self.racine.joueuse2 = self.droit.racine.gagnante
            else:
                self.droit.mise_a_jour()

Pour chaque côté, on ne remplit qu’un emplacement encore vide. Si le match enfant a déjà une gagnante, on la copie au tour supérieur. Sinon on descend dans ce sous-arbre pour mettre à jour ses matchs précédents. Les feuilles n’ont pas d’enfants, ce qui arrête naturellement la descente. Cette fonction ne joue pas les matchs et ne détermine pas une gagnante : elle propage seulement les résultats déjà saisis.

Par exemple, après les résultats de Q1 et Q2, un appel sur la racine F descend vers D1 et complète ses deux participantes, mais F n’a toujours pas de joueuse1 tant que la demi-finale D1 n’a pas été jouée. Après saisie de son résultat, un nouvel appel copie sa gagnante dans F. Le test des emplacements déjà renseignés évite d’effacer un résultat existant.

Voir la question dans le sujet PDF, p. 12 (nouvel onglet)
Qui gagne le match : les jeux ou les sets ?Un atelier pour expérimenter

Choisissez un score terminé. Le modèle compte les jeux et les sets séparément pour montrer pourquoi le vainqueur du match se décide aux sets remportés.

Lire le résultat de l’expérience initiale

La joueuse 1 gagne le match

Chaque set remporté compte une unité, quelle que soit sa marge en jeux. On peut gagner davantage de jeux au total et perdre le match.

SetJeux J1Jeux J2Gagnante du set
175Joueuse 1
246Joueuse 2
376Joueuse 1

Un objet Match doit traduire la règle de victoire correcte, puis mettre à jour les objets Joueuse qui lui sont associés.

Revoir les notions de cet exercice

Exercice 3 · 8 points

Course à pied : inscriptions SQL, moyennes et records

Un club organise deux courses, 5 km et 10 km. Un coureur ne peut s’inscrire qu’à une épreuve. La table coureur identifie chaque inscription par un dossard automatiquement incrémenté ; l’organisateur saisit le nom, prénom, année de naissance, sexe H/F et l’épreuve. Le temps en secondes commence à 0. La table epreuve indique distance en km, horaire de départ, prix d’inscription et juge arbitre.

RelationAttributsClé primaireClé étrangère
coureurnum_dossard, nom, prenom, annee, sexe, id_epreuve, tempsnum_dossardid_epreuve → epreuve.id_epreuve
epreuveid_epreuve, distance, horaire, prix, juge_arbitreid_epreuve-
DossardNomPrénomAnnéeSexeÉpreuveTemps
1DA SILVAJosé1980H10
2HANG LILéo2005H20
3BODIANELola2000F20
4BRELETSandra1972F10
id_epreuvedistancehoraireprixjuge_arbitre
151010GAVEAU Philippe
2101120BOULA Awa

On peut utiliser SELECT, FROM, WHERE, AND, OR, JOIN ... ON, INSERT, UPDATE, DELETE, DISTINCT, ORDER BY et COUNT.

Question 1

#

Pourquoi num_dossard est-il choisi comme clé primaire de coureur ?

Indice

La clé doit distinguer des personnes qui portent le même nom.

Comprendre la correction

Il est attribué automatiquement, unique et non nul pour chaque inscription. Deux coureurs homonymes peuvent donc être distingués. Puisque chaque coureur ne participe qu’à une seule épreuve dans le modèle, ce dossard suffit à identifier la ligne sans le combiner à id_epreuve.

Voir la question dans le sujet PDF, p. 14 (nouvel onglet)

Question 2

#

Décrire SELECT nom, prenom FROM coureur ORDER BY nom.

Indice

ORDER BY porte seulement sur nom.

Comprendre la correction

La requête liste les noms et prénoms de tous les inscrits, triés par nom croissant. Dans l’extrait : BODIANE Lola, BRELET Sandra, DA SILVA José, HANG LI Léo. Les personnes portant le même nom ne seraient pas nécessairement triées par prénom, car ce second critère n’est pas demandé. La collation du SGBD détermine les détails de l’ordre alphabétique.

Voir la question dans le sujet PDF, p. 14 (nouvel onglet)

Question 3

#

Lister noms et prénoms des femmes inscrites.

Indice

Utilisez la valeur stockée F, pas le mot femme.

Comprendre la correction
SELECT nom, prenom
FROM coureur
WHERE sexe = 'F';

On filtre avec la codification F du sujet. Aucun filtre sur la distance n’est demandé, donc les deux épreuves sont concernées.

Voir la question dans le sujet PDF, p. 14 (nouvel onglet)

Question 4

#

Connaître le nombre total d’inscrits.

Indice

L’agrégation doit porter sur tous les coureurs, sans WHERE.

Comprendre la correction
SELECT COUNT(*) FROM coureur;

COUNT(*) compte les lignes de la table entière. Les quatre lignes imprimées ne sont qu’un extrait : on ne peut déduire le total réel de la seule illustration.

Voir la question dans le sujet PDF, p. 14 (nouvel onglet)

Bulletin reçu : Nom REMY ; prénom Patrice ; civilité homme ; course 5 km ; année de naissance 1973.

Question 5

#

Inscrire Patrice REMY, homme né en 1973, sur 5 km.

Indice

Regardez l’identifiant de l’épreuve et laissez la base attribuer le dossard.

Comprendre la correction
INSERT INTO coureur (nom, prenom, annee, sexe, id_epreuve, temps)
VALUES ('REMY', 'Patrice', 1973, 'H', 1, 0);

Le dossard n’est pas fourni : il est généré automatiquement par la base. id_epreuve = 1 correspond au 5 km, alors que la valeur 5 décrit une distance, pas un identifiant. Le temps vaut initialement zéro.

Voir la question dans le sujet PDF, p. 15 (nouvel onglet)

Question 6

#

Supprimer l’inscription du dossard 137, blessé avant l’épreuve.

Indice

DELETE doit porter sur coureur et être limité par sa clé.

Comprendre la correction
DELETE FROM coureur WHERE num_dossard = 137;

La suppression cible la clé de l’inscription. On ne supprime pas l’épreuve à laquelle il était inscrit, qui reste partagée par les autres coureurs.

Voir la question dans le sujet PDF, p. 15 (nouvel onglet)

Question 7

#

Donner distance et horaire de départ au dossard 256.

Indice

La clé étrangère relie l’inscription à la fiche de course.

Comprendre la correction
SELECT e.distance, e.horaire
FROM coureur AS c
JOIN epreuve AS e ON c.id_epreuve = e.id_epreuve
WHERE c.num_dossard = 256;

La table coureur fournit l’épreuve choisie ; la table epreuve en donne les caractéristiques. Le dossard 256 n’est pas dans l’extrait, donc seule la requête peut être fournie, pas une distance inventée.

Voir la question dans le sujet PDF, p. 15 (nouvel onglet)

À l’arrivée, l’arbitre note par exemple :

DossardTemps (s)
571242
721845
1831284
21285

Tous les temps ont ensuite été enregistrés. La catégorie Master Femme du problème regroupe les coureuses nées avant 1986.

Question 8

#

Classer les femmes Master du 10 km, nées avant 1986, par temps croissant ; afficher dossard, nom, prénom et temps.

SQLClasser les femmes Master du 10 kmÉcrivez votre solution et mettez-la à l’épreuve

Affichez dossard, nom, prénom et temps des femmes nées avant 1986 inscrites au 10 km, par temps croissant. Les temps des participantes classables sont renseignés.

SELECT ...
FROM ...
WHERE ...;

Les cas de test proposés :

  • Extrait des inscriptions : aucune coureuse admissible : Les lignes initiales sont celles du PDF. Aucune ne satisfait simultanément sexe, année et distance ; leurs temps initiaux à 0 ne participent donc pas au classement.
  • Cas complémentaire : filtrer puis ordonner : Jeu complémentaire pédagogique, distinct des données officielles. 1986 est exclue, la course 5 km est exclue et les hommes sont exclus. Les dossards sont dans un ordre opposé au classement par temps.
  • Cas complémentaire : la distance vient de la table épreuve : Jeu complémentaire pédagogique, distinct des données officielles. L’identifiant 9 correspond ici au 10 km. La jointure doit utiliser le sens du champ distance, pas un identifiant supposé constant.
Indice

Combinez catégorie, année et distance avant le tri.

Comprendre la correction
SELECT c.num_dossard, c.nom, c.prenom, c.temps
FROM coureur AS c
JOIN epreuve AS e ON e.id_epreuve = c.id_epreuve
WHERE c.sexe = 'F' AND c.annee < 1986 AND e.distance = 10
ORDER BY c.temps ASC;

La limite « avant 1986 » est stricte ; 1986 est exclu. Le plus petit temps arrive en tête. L’énoncé suppose tous les temps enregistrés : aucun filtre de résultat manquant n’est nécessaire ici. Dans une application conservant des non-partants à temps 0, il faudrait les exclure du classement, sinon ils seraient incorrectement premiers. Filtrer directement id_epreuve=2 serait également valable pour la table donnée, mais la jointure exprime explicitement la distance demandée.

Voir la question dans le sujet PDF, p. 15 (nouvel onglet)

Partie B : performances sur plusieurs années

Émilie, élève de Terminale NSI dans le scénario, associe à chaque année la liste des meilleurs temps dans cet ordre : JH, JF (moins de 18 ans), SH, SF (18 à 40 ans), MH, MF (plus de 40 ans). Ce sont les catégories simplifiées du sujet. Exemple : en 2024, JF vaut 1010 s et MH vaut 1022 s.

dict_perf_5km = {
  2022: [
    1020,
    1050,
    900,
    1000,
    1018,
    1040
  ],
  2023: [
    1010,
    1048,
    1100,
    1024,
    1080,
    1108
  ],
  2024: [
    1012,
    1010,
    1000,
    1036,
    1022,
    1098
  ],
  2025: [
    998,
    1028,
    1000,
    959,
    1002,
    980
  ]
}

Question 9

#

Donner dict_perf_5km[2025][2].

Indice

Les indices de la liste de catégories commencent à zéro.

Comprendre la correction

1000 secondes, meilleure performance Senior Homme en 2025. La clé externe est l’année ; l’indice 2 sélectionne la troisième catégorie, SH.

Voir la question dans le sujet PDF, p. 16 (nouvel onglet)

Question 10

#

Ajouter les temps 2026 : JH 1004, JF 1016, SH 1000, SF 1140, MH 1023, MF 1024.

Indice

Conservez exactement les six positions conventionnelles.

Comprendre la correction
dict_perf_5km[2026] = [1004, 1016, 1000, 1140, 1023, 1024]

L’ordre des six catégories doit rester identique d’une année à l’autre. La clé 2026 est un entier, comme les années déjà enregistrées. Si cette clé existait, l’affectation remplacerait sa liste ; elle ne créerait pas une seconde entrée pour la même année.

Voir la question dans le sujet PDF, p. 16 (nouvel onglet)

Question 11

#

Écrire scratch(dico,annee), meilleur temps de l’année toutes catégories confondues, sans min ni max. L’année est présente.

Indice

Un record de course minimise le temps.

Comprendre la correction
def scratch(dico, annee):
    meilleur = dico[annee][0]
    for temps in dico[annee]:
        if temps < meilleur:
            meilleur = temps
    return meilleur

Le meilleur temps est le plus petit. Initialiser avec le premier résultat, plutôt qu’avec zéro, garantit une valeur de référence réellement présente. À chaque itération, meilleur est le minimum des temps déjà parcourus. Pour 2024, la liste [1012,1010,1000,1036,1022,1098] donne 1000. La liste contient six catégories selon le contrat, donc son premier élément existe.

Voir la question dans le sujet PDF, p. 16 (nouvel onglet)
def mystere(dico, cat):
    categories = ["JH", "JF", "SH", "SF", "MH", "MF"]
    s = 0
    nb = 0
    for i in range(len(categories)):
        if cat == categories[i]:
            i_cat = i
    for annee in dico.keys():
        s = s + dico[annee][i_cat]
        nb = nb + 1
    return s / nb

Question 12

#

Quelle valeur reçoit i_cat dans mystere(dict_perf_5km,"SH") ?

Indice

Repérez SH dans la liste ordonnée des catégories.

Comprendre la correction

2. SH est le troisième élément de categories, donc son indice vaut 2. La boucle repère cet indice avant de consulter chaque liste annuelle.

Voir la question dans le sujet PDF, p. 16 (nouvel onglet)
ChoixMessage proposé
1expected an indented block
2takes 2 positionnals arguments but 3 were given
3local variable 'i_cat' referenced before assignement
4list index out of range

Question 13

#

Quel message parmi les quatre proposés correspond à mystere(...,"SG"), catégorie inexistante ?

Indice

La ligne qui affecte i_cat n’a jamais été exécutée.

Comprendre la correction

Le troisième : « local variable 'i_cat' referenced before assignment ». Aucune comparaison n’a réussi, donc i_cat n’a jamais reçu de valeur ; sa lecture lors de la première année provoque une UnboundLocalError. La formulation exacte du message varie selon la version de Python, mais c’est cette erreur de variable locale non initialisée. Ce n’est ni une erreur d’indentation ni un dépassement d’indice de liste.

Voir la question dans le sujet PDF, p. 17 (nouvel onglet)

Question 14

#

Ajouter une assertion après categories pour signaler une catégorie mal saisie avec un message.

Indice

assert accepte une condition, puis un message après une virgule.

Comprendre la correction
assert cat in categories, "Catégorie inconnue : " + cat

Le test interrompt immédiatement la fonction si le code n’appartient pas aux six catégories. Le message explique la faute plutôt que de laisser apparaître une erreur technique plus loin. Dans une application de production, une validation explicite avec exception contrôlée serait préférable car Python peut désactiver les assertions avec l’option -O ; ici l’assertion est précisément demandée.

Voir la question dans le sujet PDF, p. 17 (nouvel onglet)

Question 15

#

Que renvoie mystere(dict_perf_5km,"SH") ?

Indice

La fonction additionne une valeur par année puis divise par le nombre d’années.

Comprendre la correction

1000.0 : la fonction calcule la moyenne des meilleurs temps SH enregistrés chaque année. Après ajout de 2026 : (900 + 1100 + 1000 + 1000 + 1000) / 5 = 1000. Avant cet ajout, les quatre premières valeurs avaient déjà la même moyenne. L’opérateur / renvoie un flottant en Python. Cette valeur n’est ni le record global SH (900) ni la moyenne de tous les coureurs, puisque le dictionnaire ne contient que les meilleurs temps annuels.

Voir la question dans le sujet PDF, p. 17 (nouvel onglet)

Question 16

#

Écrire records(dico), liste des meilleurs temps de chaque catégorie sur toutes les années, sachant que les temps ne dépassent pas 24 h.

Indice

Gardez six minima indépendants, un à chaque indice de catégorie.

Comprendre la correction
def records(dico):
    meilleurs = [24 * 60 * 60] * 6
    for annee in dico:
        for i in range(6):
            if dico[annee][i] < meilleurs[i]:
                meilleurs[i] = dico[annee][i]
    return meilleurs

Le plafond 86 400 secondes sert de sentinelle supérieure ou égale à tous les temps admis. Chaque catégorie possède son propre minimum, mis à jour pour chaque année. On obtient [998,1010,900,959,1002,980], y compris après ajout de 2026, qui ne bat aucun de ces records. Réinitialiser meilleurs à l’intérieur de la boucle annuelle ferait perdre les records des années précédentes.

Le dictionnaire doit contenir au moins une année pour que la notion de record soit définie. Sur un dictionnaire vide, ce code renvoie les sentinelles ; une version d’application devrait refuser ce cas ou représenter explicitement l’absence de record. On pourrait aussi initialiser à une copie de la première année lorsqu’elle est garantie, ce qui éviterait la sentinelle.

Voir la question dans le sujet PDF, p. 17 (nouvel onglet)
Record et moyenne ne racontent pas la même choseUn atelier pour expérimenter

Sélectionnez une catégorie et choisissez d’inclure les données 2026. Le tableau fait apparaître les meilleurs temps annuels, leur record et leur moyenne.

Lire le résultat de l’expérience initiale

SH : record 900 s

La moyenne porte seulement sur les meilleurs temps annuels. Un temps plus petit est meilleur ; ajouter une année peut modifier la moyenne sans améliorer le record.

AnnéeMeilleur temps de la catégorie (s)Record atteint
2022900Oui
20231100Non
20241000Non
20251000Non
20261000Non

Le sens d’une statistique dépend des données réellement stockées : ici des records annuels par catégorie, pas tous les temps individuels.

Revoir les notions de cet exercice

Du sujet à la méthode

Votre prochaine séance de révision

  • Suivez les mutations des objets : une victoire change deux joueuses, une mise à jour du tournoi ne rejoue aucun match.
  • Avant une agrégation, expliquez quelle population de lignes ou de valeurs est réellement incluse.
  • Distinguez le chronogramme avec arrivées du modèle où tous les processus sont déjà présents.

Retrouver ces notions dans d’autres sujets

Toutes les annales de NSI · Le guide pour préparer le bac NSI 2027

Énoncé : sujet 26-NSIJ2AN1 (PDF). Corrigé et explications pédagogiques proposés par Sofien.