Épreuve pratique · 2026 · Sujet 10

Bac NSI pratique 2026 sujet 10 : Consommation d’eau, fuite nocturne et moyenne glissante

Un compteur fournit des mesures triées par jour et heure croissants. Chaque dictionnaire contient jour au format AAAA-MM-JJ, heure au format HH: MM et les volumes entière chaude et froide consommés depuis la mesure précédente. Le total est leur somme. On doit distinguer un jour sans mesure d’un jour avec consommation nulle, détecter trois mesures nocturnes consécutives positives puis lisser une série sans changer sa longueur.

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

Application

Consommation d’eau, fuite nocturne et moyenne glissante

Un compteur fournit des mesures triées par jour et heure croissants. Chaque dictionnaire contient jour au format AAAA-MM-JJ, heure au format HH: MM et les volumes entière chaude et froide consommés depuis la mesure précédente. Le total est leur somme. On doit distinguer un jour sans mesure d’un jour avec consommation nulle, détecter trois mesures nocturnes consécutives positives puis lisser une série sans changer sa longueur.

HeureExemple sans fuiteExemple avec fuite
00:0052
01:0031
02:0001
03:0030
04:0000
05:0000

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 : analyse_eau.py
donnees = [
    {"jour": "2025-02-04", "heure": "00:00", "chaude": 2, "froide": 3},
    {"jour": "2025-02-04", "heure": "01:00", "chaude": 1, "froide": 2},
    {"jour": "2025-02-04", "heure": "02:00", "chaude": 0, "froide": 0},
    {"jour": "2025-02-04", "heure": "03:00", "chaude": 0, "froide": 0},
    {"jour": "2025-02-04", "heure": "04:00", "chaude": 0, "froide": 1},
    {"jour": "2025-02-04", "heure": "05:00", "chaude": 0, "froide": 0},
    {"jour": "2025-02-04", "heure": "06:00", "chaude": 4, "froide": 6},
    {"jour": "2025-02-04", "heure": "07:00", "chaude": 6, "froide": 8},
    {"jour": "2025-02-05", "heure": "00:00", "chaude": 0, "froide": 0},
    {"jour": "2025-02-05", "heure": "01:00", "chaude": 1, "froide": 1},
    {"jour": "2025-02-05", "heure": "02:00", "chaude": 1, "froide": 1},
    {"jour": "2025-02-05", "heure": "03:00", "chaude": 1, "froide": 1},
    {"jour": "2025-02-05", "heure": "04:00", "chaude": 0, "froide": 0},
    {"jour": "2025-02-05", "heure": "05:00", "chaude": 0, "froide": 0},
]


# -----------------------------
# Fonctions à compléter
# -----------------------------

def total_conso(donnees, jour):
    # À compléter
    pass


def fuite_possible(donnees, jour):
    # À compléter
    pass


# -----------------------------
# Fonction fournie (erronée)
# -----------------------------

def lissage_conso(valeurs):
    """
    Calcule une moyenne glissante sur les valeurs.
    Pour chaque valeur, on calcule la moyenne avec ses voisins.
    """

    lisse = []
    for i in range(len(valeurs)):
        if i == 0:
            m = (valeurs[i] + valeurs[i+1]) / 2
        elif i == len(valeurs)-1:
            m = (valeurs[i-1] + valeurs[i]) / 2
        else:
            m = (valeurs[i-1] + valeurs[i] + valeurs[i+1]) / 2
        lisse.append(m)

    return lisse


# -----------------------------
# Espace pour les tests
# -----------------------------

def test_lissage():
    # À compléter : écrire au moins 3 assertions (assert) avec des listes
    # de différentes tailles pour révéler les erreurs de la fonction
    pass

Question 1

#

Écrire total_conso(donnees, jour), qui renvoie la somme de l’eau chaude et froide de ce jour. Renvoyer None si aucune mesure n’existe. Le 04 février 2025 doit donner 33 ; le 25 décembre 2025 ne possède pas de mesure.

Indice

Un total nul ne prouve pas l’absence de mesure.

Comprendre la correction
def total_conso(donnees, jour):
    total = 0
    trouve = False
    for mesure in donnees:
        if mesure['jour'] == jour:
            trouve = True
            total += mesure['chaude'] + mesure['froide']
    return total if trouve else None
assert total_conso(donnees,'2025-02-04') == 33
assert total_conso(donnees,'2025-12-25') is None
assert total_conso([{'jour':'x','heure':'00:00','chaude':0,'froide':0}], 'x') == 0

Le booléen trouve distingue absence et zéro. Tester seulement total==0 confondrait ces deux situations. La somme du 04 février vaut 5+3+0+0+1+0+10+14=33 litres.

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

Question 2

#

Écrire fuite_possible(donnees, jour). Une fuite est suspectée s’il existe au moins trois mesures consécutives entre 00:00 et 05:00 inclus dont chaque consommation totale est positive. Renvoyer True ou False.

PythonDistinguer trois consommations de trois consommations consécutivesÉcrivez votre solution et mettez-la à l’épreuve

Écrivez fuite_possible(donnees, jour). Les mesures horaires sont triées. Cherchez au moins trois mesures consécutives entre 00:00 et 05:00 inclus, le jour demandé, dont chacune a chaude + froide > 0. Un zéro interrompt la série. Les tests conservent le contrat d’une série horaire régulière ; ils ne demandent pas de reconstituer des mesures manquantes.

def fuite_possible(donnees, jour):
    # À vous de jouer
    pass

Les cas de test proposés :

  • Trois premières heures positives : La série atteint trois sans devoir examiner toute la nuit.
  • Trois valeurs positives dispersées : Le zéro remet la longueur de série à zéro.
  • Série terminant à 05:00 : 05:00 est inclus et l’eau froide compte aussi.
  • 06:00 ne complète pas la série : La plage de détection s’arrête après la mesure de 05:00.
  • Le jour est un filtre : Une fuite d’un autre jour ne répond pas à la question posée.
  • Aucune mesure : Aucune série ne peut commencer.
Indice

Conserver le nombre de positifs consécutifs, pas leur nombre total.

Comprendre la correction
def fuite_possible(donnees, jour):
    suite = 0
    for mesure in donnees:
        if mesure['jour'] == jour and '00:00' <= mesure['heure'] <= '05:00':
            if mesure['chaude'] + mesure['froide'] > 0:
                suite += 1
                if suite >= 3:
                    return True
            else:
                suite = 0
    return False

suite mesure la longueur de la série positive en cours. Un zéro interrompt cette série et remet le compteur à zéro. Trois mesures positives dispersées ne suffisent pas. Comme les heures sont au format fixe HH: MM, leur comparaison lexicographique respecte l’ordre chronologique. Le sujet parle de mesures consécutives dans une série horaire triée ; si des relevés horaires peuvent manquer, il faudrait en plus contrôler l’écart d’une heure entre relevés, ce qui est une extension du contrat.

assert not fuite_possible(donnees,'2025-02-04')
assert fuite_possible(donnees,'2025-02-05')
assert not fuite_possible([], '2025-02-05')

Sur la suite 5, 3, 0, 3, 0, 0, le compteur prend successivement les valeurs 1, 2, 0, 1, 0, 0 : aucune série n’atteint 3. Sur 2, 1, 1, 0, 0, 0, il atteint 3 au troisième relevé et permet un retour immédiat. Cette trace montre pourquoi compter simplement le nombre de relevés positifs serait insuffisant : la première série contient aussi trois valeurs positives, mais séparées par des zéros. Le test doit donc inclure ces deux formes, pas seulement une suite entièrement positive.

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

Question 3

#

La fonction lissage_conso moyenne les voisins : deux valeurs aux extrémités et trois à l’intérieur. Expliquer le résultat incorrect sur [10,20,30,40,50] et proposer une correction.

PythonLisser sans réutiliser une valeur déjà lisséeÉcrivez votre solution et mettez-la à l’épreuve

Corrigez lissage_conso(valeurs) : chaque case intérieure devient la moyenne de ses deux voisines et d’elle-même ; les extrémités moyennent deux valeurs. Pour zéro ou une valeur, renvoyez une copie inchangée, comme le cas limite de la question 4. Conservez la liste source.

def lissage_conso(valeurs):
    # À vous de jouer
    pass

Les cas de test proposés :

  • Série de l’énoncé : Les cases intérieures divisent par trois ; les extrémités par deux.
  • Un pic isolé : Lire les résultats précédents au lieu des valeurs source déformerait la répartition.
  • Une constante reste constante : Une moyenne de valeurs identiques doit conserver cette valeur.
  • Deux valeurs : Les deux cases sont des extrémités.
  • Une seule valeur et liste vide : Aucun voisin inexistant ne doit être lu.
  • Conserver l’original : Le calcul s’appuie entièrement sur la série originale.
Indice

Compter les termes du numérateur de chaque branche.

Comprendre la correction

La branche des éléments intermédiaires additionne trois valeurs puis divise par 2. Elle produit 30,45,60 au lieu de 20,30,40. Les extrémités sont correctes. La sortie attendue est [15.0,20.0,30.0,40.0,45.0]. Voici la version corrigée, incluant le cas limite de la question 4 :

def lissage_conso(valeurs):
    if len(valeurs) <= 1:
        return valeurs.copy()
    lisse = []
    for i in range(len(valeurs)):
        if i == 0:
            m = (valeurs[0] + valeurs[1]) / 2
        elif i == len(valeurs) - 1:
            m = (valeurs[i-1] + valeurs[i]) / 2
        else:
            m = (valeurs[i-1] + valeurs[i] + valeurs[i+1]) / 3
        lisse.append(m)
    return lisse

On lit toujours la liste originale et on écrit dans une nouvelle liste. Modifier les valeurs source au fil du calcul ferait dépendre les moyennes suivantes des résultats déjà lissés.

Le dénominateur exprime combien de mesures ont participé à la moyenne. À une extrémité, on n’a que deux valeurs ; à l’intérieur, on en a trois. Pour une série constante, chaque résultat doit rester cette constante : par exemple [12, 12, 12] doit rester [12, 12, 12]. Ce test est très efficace contre le mauvais diviseur, car la version fournie produit 18 au centre. Il complète le test croissant de l’énoncé et illustre une propriété générale du lissage.

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

Question 4

#

Identifier un autre cas limite que les listes de deux valeurs, non traité correctement par lissage_conso, puis proposer une solution.

Comprendre la correction

Avec une seule valeur, la première branche accède à valeurs[1] : cet indice n’existe pas. La convention naturelle est de conserver la valeur unique. La liste vide était déjà rendue vide par la boucle ; la garde de la correction traite ces deux tailles explicitement et renvoie une copie.

def test_lissage():
    assert lissage_conso([]) == []
    assert lissage_conso([8]) == [8]
    assert lissage_conso([10,20]) == [15.0,15.0]
    assert lissage_conso([10,20,30,40,50]) == [15,20,30,40,45]
    origine = [10,20,30]
    resultat = lissage_conso(origine)
    assert origine == [10,20,30] and resultat is not origine
Distinguer les cas limitesUn 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
  1. Une seule valeur 8 doit être lissée en…

    [8]. La seule mesure disponible est conservée.

  2. Pourquoi écrire dans une nouvelle liste ?

    Pour ne pas réutiliser des valeurs déjà lissées.. Toutes les moyennes doivent utiliser les mesures originales.

Appuyez votre explication sur les valeurs et les conditions exactes du programme.

Voir la question dans le sujet PDF, p. 4 (nouvel onglet)
Chercher une série de trois consommationsUn atelier pour expérimenter

Activez ou désactivez les six relevés nocturnes. Le tableau suit le compteur de mesures positives consécutives. Une case active représente 1 litre, une case inactive 0 litre.

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

Fuite possible selon le critère du sujet.

Un zéro annule la série en cours. Le signal est une suspicion définie par le modèle, pas un diagnostic certain.

HeureLitresLongueur de la série
00:0011
01:0012
02:0013
03:0000
04:0000
05:0000

Un compteur de consécutivité doit être remis à zéro à chaque rupture.

Revoir les notions de cet exercice

Du sujet à la méthode

Votre prochaine séance de révision

  • Distinguer une observation nulle d’une observation absente.
  • Tester les extrémités d’une liste avant de généraliser le calcul.

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_10 (PDF). Corrigé et explications pédagogiques proposés par Sofien.