Épreuve écrite · 2025 · Jour 1

Bac NSI 2025 Asie jour 1

Ce sujet pose une question profonde : peut-on écrire un programme qui prédit l’arrêt de tous les autres ? Il passe ensuite à un calcul concret de compression de Huffman et à la gestion des adhérents d’un club de judo. Les corrections insistent sur les preuves, les conventions de codage et les cas d’égalité souvent oubliés en Python.

Traitez les trois exercices, indépendants, en 3 h 30 sans calculatrice pour une simulation de l’épreuve. Les interactions permettent ensuite d’expérimenter sans exécuter de programme arbitraire.

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

Peut-on décider si un programme s’arrête ?

Les triples guillemets Python permettent de représenter un programme par une chaîne sur plusieurs lignes. On définit :

programme1 = """
x = 10
y = 10
while x > 0:
    x = x - 1
    y = y + 1
"""

programme2 = """
def boucle_infinie():
    while True:
        pass # Ne rien faire
boucle_infinie()
"""

La fonction Python exec exécute le texte passé en paramètre. Ainsi, exec("r = 42") donne ensuite r == 42 ; après exec(programme1), x + y vaut 20. L’appel exec(programme2) ne termine pas.

Question 1

#

On suppose que l’on exécute le programme contenu dans programme1. Donner les valeurs de x et y après exécution.

Comprendre la correction

x = 0 et y = 20. La boucle s’exécute dix fois : à chaque tour, x perd 1 et y gagne 1. L’invariant x + y = 20 est conservé et la condition devient fausse pour x nul.

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

Question 2

#

Expliquer pourquoi tout programme Python peut être vu comme une chaîne de caractères.

Comprendre la correction

Le code source d’un programme est une suite finie de caractères : lettres, chiffres, espaces, retours à la ligne et symboles. Cette suite peut donc être stockée dans une chaîne. Il faut conserver ses retours à la ligne et son indentation pour préserver le sens du programme.

Voir la question dans le sujet PDF, p. 2 (nouvel onglet)
programme3 = """
x = 10
while x != 0:
    x = x - 2
"""
programme4 = """
x = 10
while x > 0:
    x = x + 2
"""
programme5 = """
x = 10
while x < 0:
    x = x + 4
"""
programme6 = """
x = 10
while x != 0:
    x = x - 4
"""

Question 3

#

On exécute programme3, programme4, programme5 et programme6 avec exec. Déterminer lesquels terminent et lesquels ne terminent pas.

Indice

Pour programme 6, regardez la valeur après2 puis après3 tours.

Comprendre la correction
ProgrammeTermine ?Raison
3Oui10, 8, 6, 4, 2, 0 : cinq tours, puis x == 0.
4Nonx reste positif et augmente de 2 à chaque tour.
5OuiLa condition 10 < 0 est fausse dès le départ : aucun tour.
6Nonx = 10 - 4 k ; aucun entier k ne donne 0. La suite passe de 2 à -2.

Une variable qui décroît n’assure pas à elle seule l’arrêt : la condition doit devenir fausse. Dans le programme 6, on teste l’égalité à 0 et non le signe de x.

Voir la question dans le sujet PDF, p. 3 (nouvel onglet)
def arret_essai1(programme):
    exec(programme)
    return True

Question 4

#

Indiquer ce que réalise le programme suivant et s’il permet de répondre au problème posé : construire arret(programme), qui renvoie True si le programme termine et False sinon, tout en s’arrêtant elle-même dans tous les cas.

Comprendre la correction

arret_essai1 exécute le programme puis renvoie True si l’exécution arrive à son terme. Si le programme boucle indéfiniment, la fonction reste bloquée dans exec et ne renvoie jamais False. Elle ne décide donc pas le problème de l’arrêt.

Attendre plus longtemps ou ajouter une limite de temps ne résout pas le problème : un programme peut finir après cette limite.

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

Question 5

#

Expliquer succinctement le principe de l’algorithme de Boyer-Moore qui permet d’implémenter recherche(mot, texte), renvoyant si le mot est présent dans le texte.

Comprendre la correction

On aligne le motif sur une portion du texte et on compare ses caractères en partant de la droite. À la première différence, des informations pré-calculées sur le motif permettent de décaler cet alignement de plusieurs positions sans perdre d’occurrence possible. Si tous les caractères correspondent, une occurrence est trouvée.

Dans la variante du « mauvais caractère » étudiée en NSI, le caractère du texte responsable de l’échec sert à choisir un décalage cohérent avec ses positions dans le motif.

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

Question 6

#

Écrire arret_essai2(programme), qui renvoie True si la chaîne "while" n’est pas utilisée dans le programme, et False sinon.

Comprendre la correction
def arret_essai2(programme):
    return not recherche("while", programme)

recherche renvoie déjà un booléen ; not inverse sa valeur. Ce test porte sur du texte brut, même si « while » apparaît dans une chaîne ou un commentaire.

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

Question 7

#

Montrer que arret_essai2 peut renvoyer True alors que le programme ne s’arrête pas, et False alors qu’il s’arrête. Il n’y a pas que les boucles while qui peuvent poser des problèmes de non-terminaison.

Indice 1

Une boucle for peut parcourir un itérateur sans fin.

Indice 2

Une condition fausse dès le départ suffit à une boucle while pour terminer.

Comprendre la correction
for element in iter(int, 1):
    pass

Ce premier contre-exemple ne contient pas « while ». L’itérateur appelle int(), qui renvoie toujours 0, jusqu’à rencontrer 1 : cela n’arrive jamais. Le test textuel renvoie donc True alors que la boucle ne termine pas.

while False:
    pass

Le second texte contient « while », mais la boucle n’effectue aucun tour : le programme termine. Une fonction qui s’appelle récursivement sans fin illustre aussi l’idée dans un modèle théorique, mais en Python concret elle finit généralement par lever RecursionError ; le premier contre-exemple évite cette confusion.

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

Question 8

#

En supposant l’existence de arret, écrire terminaison_inverse(programme), qui termine si le programme ne termine pas et ne termine pas s’il termine. On pourra utiliser boucle_infinie.

Indice

Inversez le comportement annoncé par le décideur supposé.

Comprendre la correction
def terminaison_inverse(programme):
    if arret(programme):
        boucle_infinie()

Si arret annonce une terminaison, on lance une boucle infinie. Sinon, le corps conditionnel est ignoré et la fonction atteint sa fin. L’existence de arret est ici une hypothèse pour raisonner, pas une fonction disponible en Python.

Voir la question dans le sujet PDF, p. 4 (nouvel onglet)
programme_paradoxal = "terminaison_inverse(programme_paradoxal)"

Question 9

#

Étudier si exec(programme_paradoxal) termine ou non, avec programme_paradoxal = "terminaison_inverse(programme_paradoxal)".

Indice

Étudiez successivement les deux réponses possibles du décideur.

Comprendre la correction

Supposons que ce programme termine. Alors arret(programme_paradoxal) est vrai, donc terminaison_inverse boucle indéfiniment : contradiction.

Supposons maintenant qu’il ne termine pas. arret renvoie alors faux, donc terminaison_inverse atteint sa fin : nouvelle contradiction. Les deux réponses possibles contredisent le comportement exigé ; l’hypothèse d’un décideur universel est impossible.

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

Question 10

#

Indiquer ce que l’on peut conclure sur la fonction arret.

Comprendre la correction

Il n’existe pas de fonction calculable qui, pour tout programme, termine toujours et répond correctement s’il termine. Le problème de l’arrêt est indécidable. Cela n’interdit pas de prouver la terminaison de programmes particuliers, comme les programmes 1 ou 3.

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

Question 11

#

Expliquer si l’impossibilité d’écrire une telle fonction arret est due aux limitations du langage Python.

Comprendre la correction

Non. La contradiction utilise la capacité à représenter un programme comme une donnée, à effectuer un test et à boucler. Elle concerne le calcul algorithmique général, pas une faiblesse de la syntaxe de Python. Changer de langage universel ou accélérer la machine ne supprime pas cette impossibilité.

Voir la question dans le sujet PDF, p. 4 (nouvel onglet)
Une suite décroissante finit-elle toujours ?Un atelier pour expérimenter

Choisissez l’un des quatre programmes et le nombre d’itérations observées. Comparez la valeur calculée à la condition de boucle. Une simulation finie observe un préfixe ; la preuve explique la suite entière.

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

Après 5 tour(s), x = -10 : la condition reste vraie

x vaut toujours 10 - 4k, donc est congru à 2 modulo 4 : il ne peut pas être nul.

TourxCondition
010Vraie
16Vraie
22Vraie
3-2Vraie
4-6Vraie
5-10Vraie

Observer mille tours ne démontre pas une boucle infinie. Un invariant ou une formule permet ici de prouver ce qu’aucune attente finie ne peut décider en général.

Revoir les notions de cet exercice

Exercice 2 · 6 points

Compresser SIX ANANAS avec Huffman

Pour transmettre sur un canal non bruité, on cherche à réduire la taille de l’information. Le codage de Huffman, proposé en 1952, est un code de longueur variable optimal dans le cadre des codes préfixes binaires symbole par symbole pour des fréquences données. Le sujet annonce des réductions de taille de 20 % à 90 % ; nous vérifierons ce calcul sur son exemple, sans en faire une garantie universelle.

Partie A : coder du texte

La figure 1 donne ISO/CEI 8859-1, appelé Latin-1 dans le sujet. Chaque caractère y occupe 8 bits, soit deux chiffres hexadécimaux : la ligne puis la colonne. « H », ligne 4 x et colonne x8, a pour code 48. « Hello_World_! » donne 48 65 6C 6C 6F 5F 57 6F 72 6C 64 5F 21. SP représente l’espace.

Table Latin-1 complète de la figure 1
Lignex0x1x2x3x4x5x6x7x8x9xAxBxCxDxExF
0xPosition non utilisée dans la figurePosition non utilisée dans la figurePosition non utilisée dans la figurePosition non utilisée dans la figurePosition non utilisée dans la figurePosition non utilisée dans la figurePosition non utilisée dans la figurePosition non utilisée dans la figurePosition non utilisée dans la figurePosition non utilisée dans la figurePosition non utilisée dans la figurePosition non utilisée dans la figurePosition non utilisée dans la figurePosition non utilisée dans la figurePosition non utilisée dans la figurePosition non utilisée dans la figure
1xPosition non utilisée dans la figurePosition non utilisée dans la figurePosition non utilisée dans la figurePosition non utilisée dans la figurePosition non utilisée dans la figurePosition non utilisée dans la figurePosition non utilisée dans la figurePosition non utilisée dans la figurePosition non utilisée dans la figurePosition non utilisée dans la figurePosition non utilisée dans la figurePosition non utilisée dans la figurePosition non utilisée dans la figurePosition non utilisée dans la figurePosition non utilisée dans la figurePosition non utilisée dans la figure
2xSP!"#$%&'()*+,-./
3x0123456789:;<=>?
4x@ABCDEFGHIJKLMNO
5xPQRSTUVWXYZ[\]^_
6x`abcdefghijklmno
7xpqrstuvwxyz{|}~Position non utilisée dans la figure
8xPosition non utilisée dans la figurePosition non utilisée dans la figurePosition non utilisée dans la figurePosition non utilisée dans la figurePosition non utilisée dans la figurePosition non utilisée dans la figurePosition non utilisée dans la figurePosition non utilisée dans la figurePosition non utilisée dans la figurePosition non utilisée dans la figurePosition non utilisée dans la figurePosition non utilisée dans la figurePosition non utilisée dans la figurePosition non utilisée dans la figurePosition non utilisée dans la figurePosition non utilisée dans la figure
9xPosition non utilisée dans la figurePosition non utilisée dans la figurePosition non utilisée dans la figurePosition non utilisée dans la figurePosition non utilisée dans la figurePosition non utilisée dans la figurePosition non utilisée dans la figurePosition non utilisée dans la figurePosition non utilisée dans la figurePosition non utilisée dans la figurePosition non utilisée dans la figurePosition non utilisée dans la figurePosition non utilisée dans la figurePosition non utilisée dans la figurePosition non utilisée dans la figurePosition non utilisée dans la figure
AxNBSP¡¢£¤¥¦§¨©ª«¬Tiret conditionnel®¯
Bx°±²³´µ·¸¹º»¼½¾¿
CxÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏ
DxÐÑÒÓÔÕÖרÙÚÛÜÝÞß
Exàáâãäåæçèéêëìíîï
Fxðñòóôõö÷øùúûüýþÿ
txt = "SIX ANANAS"

Question 1

#

Calculer la taille en octets du texte contenu dans txt, puis la taille en bits nécessaire pour le stocker.

Comprendre la correction

Il y a 10 caractères, espace compris. Le texte occupe donc 10 octets = 80 bits. Ne pas compter seulement les lettres : l’espace est un symbole codé lui aussi.

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

Question 2

#

Donner le codage de la chaîne txt.

Comprendre la correction
53 49 58 20 41 4E 41 4E 41 53

On lit chaque caractère dans l’ordre : S, I, X, espace, A, N, A, N, A, S. La répétition d’un caractère répète son code fixe ; A vaut 41 et N vaut 4E.

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

Partie B : compression de Huffman

Le nombre d’occurrences d’un symbole est son nombre d’apparitions. Pour « DEECDDEBFACCECCEDBAEE », le sujet donne :

SymboleABCDEF
Occurrences225471

Ce tableau se représente par le dictionnaire {'D': 4, 'E': 7, 'C': 5, 'B': 2, 'F': 1, 'A': 2}.

Question 4

#

Préciser à quoi correspond la somme des nombres d’occurrences.

Comprendre la correction

Elle est égale au nombre total de symboles du texte, donc à sa longueur : chaque position contribue exactement une fois à l’effectif du caractère qu’elle contient. Pour txt, elle vaut 10.

Voir la question dans le sujet PDF, p. 6 (nouvel onglet)
def occurrence(texte):
    dico = {}
    for lettre in ...:
        if lettre in ...:
            dico[lettre] = dico[lettre] + 1
        else:
            ...
    return ...

Question 5

#

Compléter occurrence(texte), qui renvoie le dictionnaire des occurrences.

Comprendre la correction
def occurrence(texte):
    dico = {}
    for lettre in texte:
        if lettre in dico:
            dico[lettre] = dico[lettre] + 1
        else:
            dico[lettre] = 1
    return dico

Un symbole déjà rencontré voit son compteur augmenter de 1 ; un nouveau symbole est initialisé à 1 puisqu’on vient de le lire. Le dictionnaire vide est la bonne réponse pour un texte vide. Le retour vient après le parcours complet.

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

Une forêt contient au départ une feuille par symbole, pondérée par son effectif. On extrait les deux arbres de plus petite fréquence, on les greffe sous une nouvelle racine de poids égal à leur somme, puis on réinsère ce nouvel arbre. Les plus petits poids sont donc les plus prioritaires. À égalité, une nouvelle insertion passe avant les arbres de même priorité déjà présents. On recommence jusqu’à un seul arbre. Les arêtes gauches valent 0 et les droites 1.

La figure 2 montre les fusions de l’exemple à 21 symboles :

ÉtapeFusionForêt après insertion, poids croissants
0AucuneF1, A2, B2, D4, C5, E7
1F1 + A2 → 3B2, (F, A)3, D4, C5, E7
2B2 + 3 → 5D4, (B,(F, A))5, C5, E7
3D4 + 5 → 9C5, E7, 9
4C5 + E7 → 129, 12
59 + 12 → 2121
6Étiqueter les arêtes par 0 et 1Arbre ci-dessous
010101010121912D:45B:23F:1A:2C:5E:7
Figure 2 : arbre final de Huffman pour les effectifs A2, B2, C5, D4, E7, F1
Lire les connexions du schéma
  • 21 relié à 9 : 0
  • 21 relié à 12 : 1
  • 9 relié à D:4 : 0
  • 9 relié à 5 : 1
  • 5 relié à B:2 : 0
  • 5 relié à 3 : 1
  • 3 relié à F:1 : 0
  • 3 relié à A:2 : 1
  • 12 relié à C:5 : 0
  • 12 relié à E:7 : 1

Question 6

#

Construire l’arbre de Huffman associé à txt.

Indice

À chaque fusion, reprenez les deux plus petits poids de la forêt actuelle.

Comprendre la correction
FusionDeux poids minimauxNouveau poids
1I:1 et X:12
2SP:1 et (I, X):23
3S:2 et N:24
4(SP, I, X):3 et A:36
5(S, N):4 et (SP, I, X, A):610
0101010101104S:2N:263A:3SP:12I:1X:1
Une construction de Huffman pour SIX ANANAS : code 0 à gauche, 1 à droite
Lire les connexions du schéma
  • 10 relié à 4 : 0
  • 10 relié à 6 : 1
  • 4 relié à S:2 : 0
  • 4 relié à N:2 : 1
  • 6 relié à 3 : 0
  • 6 relié à A:3 : 1
  • 3 relié à SP:1 : 0
  • 3 relié à 2 : 1
  • 2 relié à I:1 : 0
  • 2 relié à X:1 : 1

On fixe ici l’ordre initial des égalités à I, X, SP, S, N, A, par poids croissant. À poids égal, un nouvel arbre est inséré avant les arbres déjà présents, comme l’impose la règle du sujet. Le choix initial entre symboles de même effectif peut produire d’autres arbres corrects : les codes ne sont pas uniques.

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

Question 7

#

Préciser à quoi correspond le poids de la racine de cet arbre.

Comprendre la correction

Le poids de la racine vaut 10, la somme des occurrences de tous les symboles, donc la longueur du texte. Chaque greffe conserve le poids total de la forêt : les deux poids retirés sont remplacés par leur somme.

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

Le code d’un symbole est la suite de bits du chemin racine-feuille. Dans l’exemple de la figure 2, F se code 0110 et E se code 11.

Question 8

#

Indiquer le type de parcours à utiliser pour réaliser la table de codage à partir de l’arbre de Huffman.

Comprendre la correction

Un parcours en profondeur convient, par exemple préfixe, en transportant le chemin depuis la racine. On ajoute 0 en descendant à gauche et 1 à droite ; lorsqu’on atteint une feuille, la chaîne accumulée est le code de son symbole. Le point essentiel est de conserver le chemin, pas seulement de lister les feuilles.

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

Question 9

#

Donner la table de codage pour txt.

Comprendre la correction
SymboleSNSPIXA
Code00011001010101111

Cette table correspond exactement à notre arbre de la question 6. Un autre arbre valide peut permuter certains bits : il faut surtout assurer la cohérence entre arbre, table et texte codé.

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

Question 10

#

Justifier que le code de Huffman est un code de longueur variable.

Comprendre la correction

Les feuilles n’ont pas toutes la même profondeur : ici S, N et A ont des codes de 2 bits, l’espace de 3 bits, I et X de 4 bits. Les caractères fréquents reçoivent globalement les chemins courts. La propriété de préfixe, aucun code complet n’étant le début d’un autre, permet de les concaténer sans séparateur.

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

Question 11

#

Coder txt à l’aide du code de Huffman et de l’arbre construit à la question 6.

Comprendre la correction
00 | 1010 | 1011 | 100 | 11 | 01 | 11 | 01 | 11 | 00
0010101011100110111011100

Les barres de la première ligne sont des repères de correction : elles ne sont pas stockées. La concaténation finale contient 25 bits.

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

Question 12

#

En reprenant le résultat de la partie A, déduire le taux de compression en pourcentage pour txt et vérifier la réduction annoncée entre 20 % et 90 %. Le taux est (encombrement initial - encombrement final) / encombrement initial.

Comprendre la correction

Le taux vaut (80 - 25) / 80 = 55 / 80 = 0,6875, soit 68,75 %. Cette valeur appartient à l’intervalle annoncé.

Le calcul demandé compare uniquement le texte codé, sans ajouter le stockage de la table ou de l’arbre et sans arrondir aux octets. Sur un si petit message, ces métadonnées peuvent annuler le gain réel d’un fichier complet : c’est une limite du modèle, pas une erreur du calcul.

Voir la question dans le sujet PDF, p. 9 (nouvel onglet)
Regardez les fréquences fabriquer les codesUn atelier pour expérimenter

Choisissez un message puis avancez les fusions. Le tableau montre la forêt réelle et, à la dernière étape, les codes. Comparez une phrase déséquilibrée à des lettres aussi fréquentes.

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

5/5 fusions : 1 arbre(s)

Le texte occupe 25 bits au lieu de 80, hors table de codage. Les égalités peuvent produire d’autres codes de même coût.

SymboleEffectifCodeBits contribués
S2004
N2014
SP11003
I110104
X110114
A3116

Chaque fusion conserve le poids total. Les chemins courts attribués aux symboles fréquents réduisent la somme effectif × longueur du code.

Revoir les notions de cet exercice

Exercice 3 · 8 points

Gérer les kimonos et les licences d’un club de judo

Un club de judo développe son système d’information pour les inscriptions, communications et compétitions. L’exercice a deux parties indépendantes. Pour les listes abstraites, on utilise des listes Python et la méthode append.

Partie A : locations de kimonos

RelationSchéma et clés
adherentnumero-licence (clé primaire), taille-adherent, nom, prenom
kimonoid-kimono (clé primaire), taille-kimono
locationnumero-licence et id-kimono (clé primaire composée, également clés étrangères), debut, fin

location.numero-licence référence adherent.numero-licence ; location.id-kimono référence kimono.id-kimono. Les identifiants de kimonos sont entiers. Les tailles sont en centimètres, multiples de 10 : 100, 110, 120… Les dates sont des chaînes AAAA-MM-JJ. Toutes les valeurs doivent être valides et renseignées, mais fin peut valoir la chaîne vide '' pour une location en cours. COUNT compte les enregistrements. Les mots SQL cités par le sujet sont SELECT, FROM, WHERE, JOIN ON, INSERT INTO, VALUES, COUNT, DELETE.

Les noms de colonnes du sujet contiennent des traits d’union. Les requêtes exécutables ci-dessous les entourent de guillemets doubles, pour ne pas les interpréter comme des soustractions.

Question 1

#

Écrire une requête SQL permettant de connaître le numéro des kimonos en cours de location.

Comprendre la correction
SELECT "id-kimono"
FROM location
WHERE fin = '';

La convention dit « chaîne vide », pas NULL. Le filtre doit donc utiliser une égalité avec deux apostrophes.

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

Question 2

#

Écrire une requête SQL permettant de connaître le nombre de kimonos de taille 130 cm possédés par le club.

Comprendre la correction
SELECT COUNT(*)
FROM kimono
WHERE "taille-kimono" = 130;

On compte les lignes de l’inventaire des kimonos, et non les lignes de location : un kimono jamais loué appartient tout de même au club.

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

Question 3

#

Écrire la requête SQL permettant de connaître le nom et le prénom de l’adhérent qui possède le kimono 42 uniquement si ce kimono est en cours de location. Ne pas renvoyer les anciens locataires.

SQLRetrouver le locataire actuel du kimono 42Écrivez votre solution et mettez-la à l’épreuve

Renvoyez le nom et le prénom de l’adhérent qui loue actuellement le kimono 42. Une location est en cours lorsque fin vaut la chaîne vide ; les anciennes locations doivent être exclues.

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

Les cas de test proposés :

  • Schéma officiel, locations pédagogiques : Les deux identités et licences viennent de l’énoncé. Les tailles et les locations sont des cas pédagogiques ajoutés au schéma officiel, qui ne fournit pas de lignes SQL de location.
  • Cas complémentaire : aucune location actuelle du 42 : Jeu complémentaire pédagogique, distinct des données officielles. Le kimono 42 a été rendu ; une autre location reste active. Le résultat doit être vide.
Comprendre la correction
SELECT adherent.nom, adherent.prenom
FROM adherent JOIN location
ON adherent."numero-licence" = location."numero-licence"
WHERE location."id-kimono" = 42 AND location.fin = '';

La jointure retrouve l’adhérent à partir de sa licence. Les deux conditions du filtre sont indispensables : identifier le kimono et ne conserver que sa location actuelle.

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

Question 4

#

Pour anticiper l’année suivante, le club ajoute arbitrairement 10 cm à la taille de tous ses adhérents mesurant strictement moins de 160 cm. Écrire la requête réalisant cette opération.

Comprendre la correction
UPDATE adherent
SET "taille-adherent" = "taille-adherent" + 10
WHERE "taille-adherent" < 160;

La partie droite utilise l’ancienne valeur pour calculer la nouvelle. Un adhérent de 150 cm passe à 160 cm ; celui qui mesure déjà 160 cm ne change pas. Le mot UPDATE, nécessaire à cette question, complète la liste indicative de mots SQL donnée au début.

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

Question 5

#

Le kimono 25 a été déchiré. Écrire les requêtes SQL permettant de le supprimer de la base.

Comprendre la correction
DELETE FROM location WHERE "id-kimono" = 25;
DELETE FROM kimono WHERE "id-kimono" = 25;

On supprime d’abord ses locations, qui référencent le kimono, puis sa ligne d’inventaire. L’ordre inverse risquerait de violer une contrainte de référence. Dans un service réel, on pourrait archiver le matériel plutôt qu’effacer son historique ; ici le sujet demande bien la suppression.

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

Partie B : tableaux d’adhérents

Chaque adhérent possède nom (plus de cinq caractères), prenom, annee (quatre caractères), mois et jour (deux chiffres), et sexe (F ou M). La licence est une chaîne de 16 caractères : sexe, date JJMMAAAA, cinq premières lettres du nom en majuscules, puis deux chiffres de 01 à 99 pour distinguer des personnes partageant ce préfixe.

Les jumelles Clémence et Stéphanie Dupond, nées le 03/07/1997, ont par exemple F03071997DUPON01 et F03071997DUPON02.

Question 6

#

Déterminer un numéro de licence possible pour Eddie Nirrer né le 12/10/2021.

Comprendre la correction

M12102021NIRRE01 est un numéro possible, en retenant le sexe masculin supposé par la question et le suffixe disponible 01. On assemble M, 12102021, NIRRE, 01. Le suffixe pourrait être un autre entier de 01 à 99 pour distinguer une collision.

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

Question 7

#

Un adhérent a la licence M23091974MARTI01. Donner sa date de naissance et un nom de famille possible.

Comprendre la correction

Il est né le 23 septembre 1974. Un nom possible est Martin : ses cinq premières lettres, MARTI, correspondent au numéro et il possède plus de cinq caractères. Le numéro ne permet pas de retrouver le nom complet de façon unique.

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

tab_adherents est une liste de dictionnaires partageant les clés nom, prenom, annee, mois, jour, sexe, numero-licence. Ses deux premières entrées sont :

tab_adherents = [
    {'nom': 'DUPOND', 'prenom': 'CLEMENCE', 'annee': '1997',
     'mois': '07', 'jour': '03', 'sexe': 'F',
     'numero-licence': 'F03071997DUPON01'},
    {'nom': 'DUPOND', 'prenom': 'STEPHANIE', 'annee': '1997',
     'mois': '07', 'jour': '03', 'sexe': 'F',
     'numero-licence': 'F03071997DUPON02'},
    # autres adhérents...
]

Question 9

#

Écrire l’instruction permettant d’obtenir la valeur 'F03071997DUPON01'.

Comprendre la correction
tab_adherents[0]['numero-licence']

On choisit d’abord le dictionnaire de Clémence à l’indice 0, puis la clé qui contient sa licence.

Voir la question dans le sujet PDF, p. 12 (nouvel onglet)
def nombre_adherents(table, annee):
    compteur = ...
    for adherent in table:
        if ...:
            ...
    ...

Question 10

#

Compléter nombre_adherents(table, annee), qui renvoie le nombre d’adhérents nés pendant l’année indiquée par une chaîne de quatre caractères.

Comprendre la correction
def nombre_adherents(table, annee):
    compteur = 0
    for adherent in table:
        if adherent['annee'] == annee:
            compteur = compteur + 1
    return compteur

On compare deux chaînes de même format. Le compteur augmente pour chaque concordance, et non pour chaque année différente. Une table vide ou une année absente donne 0.

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

Question 11

#

Écrire adherent_plus_age(table), renvoyant la liste des dictionnaires des adhérents les plus âgés. La comparaison porte seulement sur l’année ; garder tous les ex aequo. La table est non vide, personne n’est né après '2024', et la comparaison des années sous forme de chaînes donne le même résultat que celle des entiers.

Indice

Un nouveau minimum efface les anciens candidats ; une égalité les complète.

Comprendre la correction
def adherent_plus_age(table):
    annee_min = table[0]['annee']
    resultat = []
    for adherent in table:
        annee = adherent['annee']
        if annee < annee_min:
            annee_min = annee
            resultat = [adherent]
        elif annee == annee_min:
            resultat.append(adherent)
    return resultat

Une année plus petite désigne une personne plus âgée. Quand on découvre un nouveau minimum, on remplace la liste des candidats ; quand l’année est égale au minimum, on ajoute l’adhérent. Initialiser à la première année évite un seuil artificiel. L’hypothèse de non-vacuité rend table[0] valide.

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

Question 12

#

Écrire verification_licence(adherent), qui renvoie si la licence correspond au sexe, à la date de naissance et au nom de famille. On dispose de extraire(s, i, j), qui renvoie la sous-chaîne d’indice i inclus à j exclu ; extraire('F03071997DUPON01', 5, 9) vaut '1997'.

PythonDétecter une licence qui ne correspond pas à l’adhérentÉcrivez votre solution et mettez-la à l’épreuve

Écrivez verification_licence(adherent). Les champs sexe, jour, mois, annee et nom sont des chaînes ; jour et mois ont deux caractères. Comparez les quatorze premiers caractères de numero-licence au sexe, à la date JJMMaaaa et aux cinq premières lettres du nom en majuscules. Les noms de ce modèle ont au moins cinq caractères. Le suffixe distingue des homonymes et n’est pas calculable à partir de ces seuls champs : ne le validez pas ici.

def verification_licence(adherent):
    # À vous de jouer
    pass

Les cas de test proposés :

  • Le nom est normalisé : dupond fournit DUPON ; le nom entier n’est pas encodé.
  • Un autre jour de naissance : 03 dans la licence ne doit pas correspondre à 04 dans le dictionnaire.
  • Le sexe doit aussi correspondre : Le premier caractère fait partie du contrôle, même si la date et le nom sont corrects.
  • Une erreur à la fin du préfixe : Le quatorzième caractère est inclus dans la comparaison ; une tranche trop courte le manquerait.
  • Le suffixe n’identifie pas les données civiles : 42 peut distinguer un autre adhérent partageant le même préfixe ; cette question ne contrôle pas l’unicité dans le registre.
Indice

Le préfixe informatif comporte 14 caractères, avant le suffixe de collision.

Comprendre la correction
def verification_licence(adherent):
    numero = adherent['numero-licence']
    prefixe = (adherent['sexe'] + adherent['jour'] + adherent['mois']
               + adherent['annee'] + adherent['nom'][:5].upper())
    return extraire(numero, 0, 14) == prefixe

Les quatorze premiers caractères déterminent les renseignements à comparer. Le suffixe de deux chiffres ne se déduit pas du seul dictionnaire : il sert à distinguer des collisions dans le registre. upper() rend la comparaison du nom conforme aux majuscules exigées.

Ce code répond au contrôle de concordance demandé. Pour contrôler en plus le format complet, on peut vérifier une longueur de 16 et un suffixe numérique entre 01 et 99, mais cela ne prouve toujours pas que le numéro est unique dans toute la fédération.

Voir la question dans le sujet PDF, p. 13 (nouvel onglet)
Décodez une licence sans perdre les indicesUn atelier pour expérimenter

Modifiez la date, le début du nom et le suffixe. Le tableau suit les indices exacts de chaque champ, comme la fonction extraire du sujet.

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

F03071997DUPON01

Les bornes droites sont exclues : [5,9) contient 9 - 5 = 4 caractères. Le suffixe distingue des personnes partageant les quatorze premiers caractères ; il ne code pas le prénom.

ChampIndices PythonValeur
Sexe[0,1)F
Jour[1,3)03
Mois[3,5)07
Année[5,9)1997
Nom[9,14)DUPON
Suffixe[14,16)01

Un identifiant structuré se lit avec des bornes exactes. La cohérence de ses champs, la validité de son format et son unicité sont trois contrôles différents.

Revoir les notions de cet exercice

Du sujet à la méthode

Votre prochaine séance de révision

  • Pour une question de décidabilité, exposez les deux branches de la contradiction sans chercher à exécuter réellement le programme paradoxal.
  • Dans Huffman, fixez un ordre pour les égalités, dessinez les poids, puis utilisez votre propre arbre jusqu’au calcul final.
  • Dans le traitement des adhérents, testez un nouveau minimum après plusieurs candidats et plusieurs personnes nées la même année.

Retrouver ces notions dans d’autres sujets

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

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