Baccalauréat — Épreuve pratique — 2026 — NSI
Épreuve pratique NSI 2026 — Sujet 03 (sujet zéro 1) : cycle menstruel
Sujet
Épreuve pratique d'une heure sur ordinateur. Le candidat dispose de l'énoncé et de fichiers de code et de données. Il agit en autonomie ; aux « appels professeur » indiqués dans le sujet, il présente son travail à l'examinateur ou le sollicite en cas de difficulté.
Ce sujet zéro est devenu le sujet n°03 de la banque nationale 2026 de l'épreuve pratique. Le texte est le même, à la présentation près ; la banque corrige seulement la coquille « phase lutérale » du sujet zéro, déjà rectifiée ici.
Cycle menstruel
Le cycle menstruel désigne l'ensemble des transformations physiologiques cycliques qui se répètent en moyenne tous les 28 jours chez une femme, de la puberté à la ménopause. Il est constitué de deux phases séparées par l'ovulation : avant l'ovulation, la phase folliculaire ; après, la phase lutéale. Par convention, le cycle commence le premier jour des règles, et l'ovulation se produit toujours 14 jours avant le début des menstruations.
On veut concevoir une application qui calcule et prédit les étapes du cycle à partir de dates fournies. On suppose un cycle régulier de 28 jours, découpé de façon simplifiée en quatre phases :
| Phase | Numéro | Jours du cycle | Description |
|---|---|---|---|
| Règles | 1 | 1 à 5 | Écoulement menstruel |
| Phase folliculaire | 2 | 6 à 13 | Développement d'un follicule dans l'ovaire |
| Ovulation | 3 | 14 | Libération de l'ovocyte |
| Phase lutéale | 4 | 15 à 28 | Développement de la muqueuse utérine |
Une date est représentée par le tuple d'entiers (jour, mois, annee), supposé toujours correctement formé et valide dans le calendrier grégorien : le 7 septembre 2025 s'écrit (7, 9, 2025).
Une année est bissextile (366 jours au lieu de 365) si elle est divisible par 4, à l'exception des années divisibles par 100, sauf si ce sont des multiples de 400. Ainsi 2024 est bissextile (divisible par 4 et pas par 100) ; 2100 ne l'est pas (divisible par 4 et par 100, mais pas par 400) ; 2000 l'est (divisible par 4, par 100 et par 400).
1. Écrire une fonction est_bissextile qui prend en paramètre un entier correspondant à une année et renvoie un booléen indiquant si elle est bissextile, en appliquant la règle ci-dessus.
Appel 1 — Appeler le professeur en cas de difficulté de compréhension du codage.
2. Écrire une fonction determiner_phase qui prend en paramètre un entier compris entre 1 et 28 inclus, le jour d'un cycle, et renvoie le numéro de la phase associée. À l'aide d'une assertion, on garantira que l'entier donné en argument est compris entre 1 et 28 inclus.
Appel 2 — Appeler le professeur pour lui présenter votre fonction et son fonctionnement, ou en cas de difficultés.
3. La fonction ajouter_jours, déjà fournie, prend en paramètres une date et un nombre de jours, et renvoie la date obtenue après ajout de ces jours. Compléter la fonction test_ajouter_jours en ajoutant au moins trois autres tests pertinents. Pour chaque test ajouté, justifier brièvement pourquoi ce cas est important à vérifier.
Pour inscrire les dates de début des règles d'une année dans un agenda en ligne, on veut créer un fichier au format iCalendar. Un calendrier a la structure suivante :
BEGIN:VCALENDAR
VERSION:2.0
PRODID: le nom du calendrier
une suite d'événements
END:VCALENDARChaque événement d'une journée est décrit par une entrée de la forme :
BEGIN:VEVENT
DTSTART: la date JJ/MM/AAAA écrite sous la forme AAAAMMJJ
SUMMARY: la description de l'événement
END:VEVENTLes nombres strictement inférieurs à 10 sont complétés par un 0, pour que la valeur de DTSTART ait toujours 8 chiffres : le 3 juillet 2026 s'écrit DTSTART:20260703.
4. La fonction calendrier_cycles, fournie, prend en paramètre la date du premier jour des dernières règles et renvoie, au format iCalendar sous forme de chaîne de caractères, la liste chronologique des dates de début de règles qui se présentent dans les 100 jours suivant cette date, date incluse. Observer avec la fonction test_calendrier_cycles que le calendrier renvoyé n'est pas dans un format valide. Identifier le problème dans calendrier_cycles, proposer une démarche de résolution et la mettre en œuvre.
Appel 3 — Appeler le professeur pour lui présenter votre démarche, ou en cas de difficultés.
Fichier fourni : cycle_menstruel.py
Le code nécessite la bibliothèque ics (pour la dernière question).
import calendar
#############################################################################
# Écrire le code de la fonction est_bissextile de la question 1 #
#############################################################################
#############################################################################
# Écrire le code de la fonction determiner_phase de la question 2 #
#############################################################################
#############################################################################
# Fonctions fournies pour la question 3 #
#############################################################################
def jours_dans_mois(annee, mois):
"""Renvoie le nombre de jours dans un mois donné d'une année donnée.
Utilise le module calendar pour gérer les années bissextiles."""
if mois == 2: # février
return 29 if calendar.isleap(annee) else 28
elif mois in [1, 3, 5, 7, 8, 10, 12]:
return 31
else:
return 30
def ajouter_jours(date, nb_jours):
"""Ajoute nb_jours à une date donnée et renvoie la nouvelle date.
La date est représentée par un tuple (jour, mois, année)."""
jour, mois, annee = date
jour = jour + nb_jours
# Ajustement du jour et du mois si dépassement
while jour > jours_dans_mois(annee, mois):
jour = jour - jours_dans_mois(annee, mois)
mois = mois + 1
if mois > 12: # passage à l'année suivante
mois = 1
annee = annee + 1
return (jour, mois, annee)
def test_ajouter_jours():
assert ajouter_jours((7, 9, 2025), 3) == (10, 9, 2025)
#############################################################################
# Fonction fournie pour la question 4 #
#############################################################################
def calendrier_cycles(date_regles):
"""Renvoie une chaîne de caractère contenant au format iCalendar, l'ensemble
des dates de début de règles qui se présentent dans les 100 jours suivants
`date_regles`, date incluse.
Hypothèse : cycle régulier de 28 jours. """
cal_lignes = ['BEGIN:VCALENDAR', 'VERSION:2.0', 'PRODID:']
date_courante = date_regles
jours_ecoules = 0
# On ajoute les dates tant que l'on ne dépasse pas 100 jours écoulés
while jours_ecoules + 28 <= 100:
jour, mois, annee = date_courante
cal_lignes.append('BEGIN:VEVENT')
cal_lignes.append('SUMMARY: Règles')
date = str(annee)+str(mois)+str(jour)
cal_lignes.append('DTSTART:'+date)
cal_lignes.append('END:VEVENT')
date_courante = ajouter_jours(date_courante, 28)
jours_ecoules += 28
cal_lignes.append('END:VCALENDAR')
# La méthode join va renvoyer ici une unique chaîne contenant toutes les
# chaînes de la liste séparées par des sauts de lignes.
return '\n'.join(cal_lignes)
def test_calendrier_cycles():
'''Crée un calendrier et le charge avec le module ics pour vérifier sa
validité.
Nécessite que le module ics soit présent sur la machine (pip install ics).
'''
from ics import Calendar
c = calendrier_cycles( (12,3,2026) )
print(c)
cal = Calendar(c)
print(cal.events)