Consignes

Si certains exercices n'ont pas pu être terminés dans le cadre de cette séance, il est fortement conseillé de les terminer par vous-même chez vous ou en salle libre service.

Liens utiles

Objectifs du TP

Le but de ce TP est de poursuivre l'apprentissage de la manipulation des tableaux. Il vous permet également d'être confronté à une démarche d'analyse descendante d'un problème donné.

1. Ecriture des fonctions de base pour manipuler une date

On représente une date à l'aide d'un tableau de trois entiers correspondant, dans l'ordre d'apparition dans le tableau, au jour, au mois et à l'année. Ainsi, par exemple :

Pour rendre plus lisibles les programmes que nous allons écrire dans ce TP, et pour anticiper sur un éventuel changement dans la représentation des dates (par exemple, les anglo-saxons notent les dates au format mois-jour-année), nous allons introduire :

Exemple :

>>> aujourdhui = cree_date(2, 11, 2015)
>>> aujourdhui
[2, 11, 2015]

>>> get_jour(aujourdhui)
2
>>> get_mois(aujourdhui)
11
>>> get_an(aujourdhui)
2015

Ecrire les fonctions cree_date, get_jour, get_mois et get_an. Vous les utiliserez obligatoirement dans la suite du TP. Nous changerons le format des dates manipulées à la fin du TP pour passer des dates "françaises" aux dates "anglo-saxones".

2. Retour vers le futur : décalage de n jours dans le temps

Écrire une fonction decale_date qui prend en paramètres :

et renvoie la date correspondant à une avancée de n jours dans le temps à partir de la date donnée. Par exemple :

Exemple :

>>> decale_date(aujourdhui, 10)
[12, 11, 2015]
>>> aujourdhui
[2, 11, 2015]
>>> decale_date(cree_date(31, 12, 2014), 1)
[1, 1, 2015]

Pour écrire cette fonction, vous supposerez qu'il existe une fonction lendemain prenant une date en paramètre et renvoyant la date du lendemain. Utilisez-la pour définir decale_date : cela simplifiera grandement votre travail.

Faites valider ce que vous avez écrit à votre enseignant de TP. Il ne vous sera en effet pas possible, pour le moment, de tester votre fonction puisque la fonction lendemain n'existe pas encore. C'est l'objectif de la question suivante que de définir lendemain. Lorsqu'elle sera définie, vous pourrez alors tester decale_date. Nous laissons de fait de côté, pour le moment, le test de decale_date et nous passons à la définition de lendemain.

Calcul de la date du lendemain - 1ère version

Nous allons dans cet exercice écrire une première version de la fonction lendemain qui prend une date en paramètre et renvoie la date du lendemain. Dans le cas général, il suffit d'ajouter 1 au n° du jour pour obtenir la date du lendemain. Ainsi par exemple :

>>> lendemain(aujourdhui)
[3, 11, 2015]
>>> lendemain(cree_date(21, 12, 2015))
[22, 12, 2015]

Cette règle est correcte pour presque tous les jours de l'année sauf ceux qui correspondent à des fins de mois et fin d'année. Elle est de fait correcte pour 353 jours sur 365.

Ecrire la fonction lendemain telle que définie ci-dessus, qui renverra un résultat correct pour tous les cas sauf les fins de mois et d'année. Testez votre fonction.

On aura ainsi :

>>> lendemain(aujourdhui)
[3, 11, 2015]
>>> lendemain(cree_date(31, 10, 2015))
[32, 10, 2015]
>>> lendemain(cree_date(31, 12, 2015))
[32, 12, 2015]

Décalage de n jours dans le temps : 1er retour (pour tests)

Nous avions laissé de côté le test de la fonction decale_date car il fallait au préalable définir lendemain. C'est maintenant chose faite, même si la fonction lendemain est partiellement définie. Il est de fait possible de tester decale_date.

Tester la fonction decale_date en prenant des exemples de dates pertinents.

Calcul de la date du lendemain - 2ème version : fin d'année

Dans sa première version, la fonction lendemain a été définie sans tenir compte des fins de mois et d'année. Nous allons maintenant en écrire une seconde version qui traitera également le cas de la fin d'année. Pour cela, nous allons introduire, ici aussi, une fonction qui va nous "faciliter la vie". Dans le cadre d'une démarche d'analyse descendante, nous allons supposer que cette fonction existe et l'utiliser pour écrire la version 2 de lendemain; nous la définirons ensuite.

On considère que la fonction suivante existe :

Ecrire la fonction lendemain en utilisant fin_d_annee

Il n'est pas possible à ce stade de tester l'application de lendemain. Il va nous falloir attendre pour cela que la fonction fin_d_annee soit définie. C'est ce que nous allons faire dans ce qui suit. Laissons de fait de côté, pour le moment, le test de la fonction lendemain. Nous y reviendrons plus tard.

Écrire une fonction fin_d_annee qui prend une date en paramètre et teste si cette date correspond à la fin de l'année (c'est-à-dire au 31 décembre).

fin_d_annee a été écrite. Il vous est maintenant possible de tester la version 2 de la fonction lendemain et de vérifier que le résultat obtenu est correct pour toutes les dates (sauf les fins de mois qui ne sont pas fin d'année bien sûr)

Tester la fonction lendemain en prenant des exemples de dates pertinents.

Calcul de la date du lendemain - 3ème version : fin de mois

Dans sa version actuelle (V2), la fonction lendemain ne traite pas le cas des fins de mois qui ne sont pas fin d'année. Nous allons maintenant en écrire une troisième et dernière version, qui sera correcte pour toutes les dates, quelles qu'elles soient. Pour cela, nous allons introduire, encore une fois, une fonction qui va nous "faciliter la vie". Dans le cadre d'une démarche d'analyse descendante, nous allons supposer que cette fonction existe et l'utiliser pour écrire la version 3 de lendemain; nous la définirons ensuite.

On considère que la fonction suivante existe :

Exemple :

>>>fin_de_mois(aujourdhui)
False
>>> fin_de_mois(cree_date(31, 12, 2014))
True
>>> fin_de_mois(cree_date(31, 10, 2014))
True
>>> fin_de_mois(cree_date(28, 2, 2012))
False
>>> fin_de_mois(cree_date(29, 2, 2012))
True

Ecrire la version finale de la fonction lendemain en utilisant fin_de_mois

Il n'est pas possible à ce stade de tester l'application de lendemain. Il va nous falloir attendre pour cela que la fonction fin_de_mois soit définie. C'est ce que nous allons faire dans ce qui suit. Laissons de fait de côté, pour le moment, le test de la fonction lendemain. Nous y reviendrons plus tard.

Fin de mois - pour V3 lendemain

Ecrire une fonction fin_de_mois qui prend une date en paramètre et teste si cette date correspond à une fin de mois.

Exemple :

>>>fin_de_mois(aujourdhui)
False
>>> fin_de_mois(cree_date(31, 12, 2014))
True
>>> fin_de_mois(cree_date(31, 10, 2014))
True
>>> fin_de_mois(cree_date(28, 2, 2012))
False
>>> fin_de_mois(cree_date(29, 2, 2012))
True

Pour écrire cette fonction, nous avons besoin de la fonction nb_jours_ds_mois. Vous supposerez qu'elle existe et l'utiliserez pour écrire fin_de_mois. Là encore, il ne sera pas possible de tester fin_de_mois tant que nb_jours_ds_mois n'est pas définie, ce que nous allons faire dans ce qui suit. Laissons de fait de côté pour le moment le test de fin_de_mois.

Calcul du nombre de jours d'un mois donné

La fonction nb_jours_ds_mois prend en paramètres :

et renvoie le nombre de jours dans un mois donné, étant donné une année donnée. Le paramètre année est nécessaire du fait des années bissextiles : février n'a en effet pas le même nombre de jours selon que l'année est bissextile ou pas.

Exemple :

>>> nb_jours_ds_mois(5, 2014)
31
>>> nb_jours_ds_mois(2, 2012)
29
>>> nb_jours_ds_mois(2, 2014)
28

Ecrire la fonction nb_jours_ds_mois. Vous écrirez au préalable la fonction est_bissextile qui teste si une année est bissextile. Pour rappel, une année A est bissextile si A est multiple de 4, mais pas de 100, ou multiple de 400.

Exemple :

>>> est_bissextile(2014)
False
>>> est_bissextile(2012)
True
>>> est_bissextile(2000)
True
>>> est_bissextile(1900)
False

La fonction nb_jours_ds_mois a été écrite lors du TP2.

Fin de mois : le retour (pour tests)

Nous avions laissé de côté le test de la fonction fin_de_mois car il fallait au préalable écrire nb_jours_dans_mois. Cette fonction est maintenant écrite; fin_de_mois est de fait complètement définie et il est possible de la tester.

Tester la fonction fin_de_mois en prenant des exemples de dates pertinents.

Calcul de la date du lendemain : 3ème version - le retour (pour tests)

Nous avions laissé de côté le test de la fonction lendemain car il fallait au préalable en définir d'autres (fin_de_mois, fin_d_annee, etc.). Ces fonctions sont maintenant écrites; lendemain est de fait complètement définie et il est possible de la tester.

Tester la fonction lendemain en prenant des exemples de dates pertinents.

Décalage de n jours dans le temps : 2ème retour (pour tests)

Nous avions laissé de côté le test de la fonction decale_date car il fallait au préalable définir complètement lendemain. C'est maintenant chose faite; il est de fait possible de tester decale_date.

Tester la fonction decale_date en prenant des exemples de dates pertinents.

Dessinez la "grappe" de fonctions qu'il a fallu introduire pour résoudre le problème initial, à savoir le décalage de n jours dans le temps à partir d'une date donnée

3. Calendrier perpétuel

- Maman, c'était quel jour quand je suis né ?
- Ououououh... je ne me rappelle plus bien. Il me semble que c''était un lundi... mais peut-être un samedi aussi. J''hésite... Demande donc à ton père.
- ...
- Papa, tu sais quel jour c'était quand je suis né ?
- C'était un mercredi ! Je suis sûr, parce que ce jour-là, ta mère ... blablabla, blablabla...

Vous voilà bien avancé : ni Maman, ni Papa ne se souviennent exactement. Et cette question fondamentale va vous hanter pendant tout le reste de votre existence. Et si vous épatiez Papa et Maman en leur apportant vous-même la réponse ? Et si, non content de cela, vous leur donniez, en plus, le jour de leur propre naissance ? Quelle gloire ce serait pour vous ! C'est ce que nous vous proposons de faire dans cette partie en travaillant sur la notion de calendrier perpétuel.

Un calendrier perpétuel (voir Wikipedia) est un calendrier qui donne le jour de la semaine (lundi, mardi, mercredi, ...) correspondant à une date donnée. Nous allons, dans cette partie, écrire une fonction calendrier_perpetuel prenant une date en paramètre et renvoyant une chaîne de caractères correspondant au jour de la semaine de cette date. Nous ne traiterons que les dates appartenant au calendrier grégorien, c'est-à-dire à partir du 20 décembre 1582 en France.

Exemple :

>>> calendrier_perpetuel(cree_date(20, 10, 2014))
"lundi"
>>> calendrier_perpetuel(cree_date(8, 10, 2003))
"mercredi"
>>> calendrier_perpetuel(cree_date(1, 6, 2014))
"dimanche"
>>> calendrier_perpetuel(cree_date(7, 1, 1994))
"vendredi"

C'est M. Moret qui a proposé ce calendrier. Il est composé, dans sa version initiale, de 3 tableaux dans lesquels il faut aller chercher des chiffres en fonction de la date en entrée et faire ensuite des calculs sur ces chiffres. Une version simplifiée a été proposée. Elle consiste à attribuer :

et à faire leur somme. Tous ces nombres sont définis modulo 7 (ex : 5 est équivalent à 12, 19, 26, ...). Le résultat de l'addition, modulo 7 lui aussi, est un nombre compris entre 0 et 6, qui donne le jour de la semaine selon la correspondance suivante :

Nous allons définir, dans ce qui suit, des fonctions permettant de calculer les nombres séculaire, annuel, mensuel et le quantième d'une date donnée. Nous les utiliserons pour définir la fonction calendrier_perpétuel.

Nombre séculaire

Le « nombre séculaire » est le même pour toutes les années commençant par les deux mêmes chiffres. Par exemple, toutes les années du 21ème siècle (années 2001 à 2099) auront un nombre séculaire égal à 0. C'est également le cas de l'année 2000.

Le tableau suivant donne les nombres séculaires pour chaque siècle :

Il est à noter que ce nombre diminue de deux unités chaque siècle (modulo 7) sauf lorsque les deux premiers chiffres sont un multiple de 4 (1600 à 1699, 2000 à 2099).

Ecrire une fonction nombre_seculaire qui prend une année en paramètre et renvoie le nombre séculaire associé à cette année.

Exemple :

>>> nombre_seculaire(2014)
5
>>> nombre_seculaire(1996)
1

Vous pourrez introduire des fonctions intermédiaires pour écrire cette fonction, par exemple la fonction siecle qui prend en paramètre une année A et renvoie le nombre correspondant au siècle de A.

Exemple :

>>> siecle(2014)
20
>>> siecle(1996)
19
>>> siecle(1900)
19

Nombre annuel

La ligne ci-dessous mentionne les années pour lesquelles le nombre annuel est égal à 0. À partir de ces années, le nombre annuel augmente d'une unité chaque année et de deux si l'année est bissextile.

Années dont le nombre annuel est 0 :

..04 ..10 ..21 ..27 ..32 ..38 ..49 ..55 ..60 ..66 ..77 ..83 ..88 ..94

Exemple :

On peut aussi remarquer que le résultat est donné par la formule suivante :

Exemple pour l'année 2010 :

Exemple pour l'année 2016 :

Ecrire une fonction nombre_annuel qui prend une année en paramètre et renvoie le nombre annuel associé à cette année.

Exemple :

>>> nombre_annuel(2010)
0
>>> nombre_annuel(2016)
1

Vous pourrez introduire des fonctions intermédiaires pour écrire cette fonction, par exemple la fonction an qui prend en paramètre une année A et renvoie le nombre correspondant aux 2 derniers chiffres de A.

Exemple :

>>> an(2014)
14
>>> an(1996)
96
>>> an(1900)
0

Nombre mensuel

Le tableau suivant donne le nombre mensuel pour chaque mois de l'année (cf. Nombre mensuel sur Wikipedia):

Exemple : le mois de janvier a un nombre mensuel de 4 en 1995 et de 3 en 1996 (année bissextile).

Ecrire une fonction nombre_mensuel qui prend en paramètres :

et qui renvoie le nombre mensuel associé à ces données.

Exemple :

>>> nombre_mensuel(1, 1995)
4
>>> nombre_mensuel(1, 1996)
3

Quantième

Le quantième correspond au jour d'une date donnée. Ainsi par exemple :

Ecrire une fonction quantième qui prend une date en paramètre et renvoie le quantième de la date donnée.

Ecriture de la fonction "calendrier_perpetuel"

Ecrire la fonction calendrier_perpetuel qui prend une date en paramètre et renvoie une chaîne de caractères correspondant au jour de la semaine de la date donnée. Vous utiliserez pour cela les fonctions nombre_seculaire, nombre_annuel, nombre_mensuel et quantieme que vous venez d'écrire.

Il vous faut revenir au début de cette partie pour relire les explications sur le calendrier perpétuel et la manière de calculer le jour de la semaine en utilisant les 4 fonctions définies ci-dessus, ainsi que le tableau de correspondance entre un numéro et un jour de la semaine.

Vendredi 13...

Les vendredis 13 ont toujours hanté l'imaginaire collectif. Pour certains, c'est une date maudite et il convient de rester confiné à la maison ce jour-là si l'on ne veut pas prendre le ciel sur la tête. Pour d'autres, c'est une date porte-bonheur.

Ecrire la fonction vendredi_13 qui prend en paramètres :

et calcule le nombre de vendredis 13 qu'il y a entre le 1er janvier de l'année initiale et le 1er janvier de l'année finale. Vous introduirez au préalable une fonction nb_jours permettant de compter le nombre de jours entre ces 2 dates (vous en aurez besoin pour écrire vendredi_13 Pour rappel, une année comporte 365 jours si elle n'est pas bissextile, 366 sinon.

Exemple :

>>> vendredi_13(2014, 2015)
1
>>> vendredi_13(2010, 2014)
7
>>> vendredi_13(2009, 2010)
3

Utilisez cette fonction pour compter le nombre de vendredis 13 entre 1600 et 2000. Que remarquez-vous ?