Sujet original : Imprimer des numéros de table en piles
■ ■ ■ SOMMAIRE DU BILLET ■ ■ ■
Imprimer des numéros de table en piles
Simulation
Algorigramme LCP
Programme "post_itBDD.ace"
Les tables de la BDD sollicitées par le programme "post_itBDD.ace"
Le programme source "post_itBDD.ace"
Les requêtes SQL
La pédagogie LCP
Méthodologie « logique de Construction de programme » (LCP)
LCP et le programme "post_itBDD.ace"
Structuration des données de Sortie (FLS)
Structuration des données d’entrée (FLE)
Structuration du programme (PRG)
Algorigramme
Structuration in extenso du programme
Édition des numéros de table
Le Programme source "post_itALL.ace"
L'Algorigramme
Le shell complet
Exemple d'état
Méthodologie de programmation LCP
■ § 1. Imprimer des numéros de table en piles
Juste pour vous faire partager le plus sympathique sujet d’algorithmique auquel j’ai été confronté.
Anecdote :
Nous sommes début mars 1992 et je développe l’application examens-concours depuis à peine plus d’un mois lorsqu’une gestionnaire vient s’installer en face de moi. Je la vois inscrire des chiffres avec un gros feutre noir sur des morceaux cartonnés découpés dans des intercalaires.
- « Vous faites quoi ? »
- « Je prépare des numéros de table pour le concours qui va avoir lieu la semaine prochaine, j’ai besoin de calme, les collègues sont trop bruyantes. »
- « Mais c’est fastidieux, ce travail ! Vous ne faites quand même pas ça pour tous les concours ? Si ?... Pour le prochain concours, je résous votre problème… »
Mais bien sûr, il n’est pas question de remplacer l’inconvénient d’inscrire des numéros par l’inconvénient de les trier. L’idée est donc d’imprimer ces numéros de table, quatre par page mais en piles, c’est-à-dire que sous le numéro « un » il y a le « deux », puis le « trois », etc. Deux coups de massicot, il ne suffit plus qu’à réunir les quatre piles, mettre un élastique autour et le tour est joué.
Et tant qu’à faire, plutôt que de se contenter d’un numéro sur un quart de feuille, autant y mettre le libellé du concours, la date, le lieu, la salle, les noms-prénoms et la consigne « Numéro de place à reporter sur votre copie ».
Avant l’envoi des convocations à un concours, un placement des candidatures par ordre alphabétique affecte un numéro de place à chaque candidat. Pour pouvoir imprimer en piles 4 numéros de place par page, il faut nécessairement affecter un nouveau numéro à chaque candidature de façon à ce que les candidatures triées sur ce nouveau numéro permettent au programme d’édition d’imprimer sur chaque page les quatre numéros de place qui conviennent.
Facile de créer ces nouveaux numéros ! Il suffit de connaître le nombre d’inscrits, de diviser par quatre et de prendre en compte l’éventuel reste.
Oui, mais… Car il y a toujours un « Oui, mais » ! Certains candidats peuvent s’inscrire aux deux concours interne et externe. Avant la date d’examen, ils doivent obligatoirement se déterminer pour l’un des deux concours. Cela implique la suppression d’une candidature dans l’un des deux, ce qui génère fatalement une place libre. Mais comment traiter une candidature qui n’existe plus dans la table des candidatures ?
Je vous laisse réfléchir à l’algorithme de création de ces nouveaux numéros… si toutefois cette problématique vous inspire.
Bonnes vacances !
§ 1.1. Simulation
Création d’un jeu d’essai avec 22 candidatures (sans places libres)
La réflexion consiste à s’intéresser aux lignes avec le même numéro de page pour comprendre comment évolue le numéro de post-it par rapport au numéro de place.
Le placement des candidats se réalise au dernier moment avant l’édition et l’envoi des convocations.
Les candidatures postérieures à la date limite d’inscription ne sont pas prises en compte (hors délais) mais une candidature émise avant la date limite d’inscription peut toujours être reçue accidentellement après le placement. L’application gère cette situation mais ce n’est pas le problème présentement. Pour être exhaustif, il y a également le cas des candidats dits COTOREP. Des places particulières doivent alors être attribuées à ces candidats si leur handicap nécessite un aménagement particulier. On leur attribue un numéro de place au-delà du nombre d’inscrits. Mais c’est vraiment pour l’anecdote.
Places libres
Je n’ai pas concrétisé de place libre dans ma simulation mais c’est facile à faire. Il suffit par exemple de désister le candidat placé en 13. Il faut alors supprimer la place 13 et le post_it 3. On garde les informations Pile (3) et Page (1) pour visualiser notre simulation.
Le programme d’édition va s’apercevoir qu’il manque le post_it 3 et imprimera un numéro de table 13 avec « Place libre » comme nom-prénom.
§ 1.2. Algorigramme LCP
Lorsque la Logique de Construction de Programme est acquise, les structurations et l’algorigramme restent à l’état de construction mentale quasi inconsciente. Le programme "post_itBDD.ace" n’utilise que 20 instructions et gère deux compteurs que l’on peut assimiler à des tables (voir la simulation ci-dessus) dont le contenu est leur rang (numéro), autrement dit leur indice courant (i_page et i_pile) :
une table des pages (nombre d’items = (nombre d’inscrits + 3) /4)
et une table des piles de 4 items.
Si le programme a été écrit le 10/03/1992, son algorigramme a été réalisé le 26/06/2019 pour créer ce Billet, soit 27 ans plus tard. Dans un souci pédagogique plus rigoureux, les structurations FLS, FLE et PRG ont quant à elles été réalisées encore plus récemment en juillet 2021, suite à la découverte sur internet d’un ancien support de cours LCP qui se transforme progressivement en tutoriel :
Le problème consiste, à partir des numéros de place, à déterminer de nouveaux numéros de façon à ce que les candidatures triées sur ce nouveau numéro (post_it) permettent d’imprimer les numéros de place en piles (4 numéros de place par page), sachant toutefois que certaines candidatures ont pu être supprimées après le placement suite à des désistements.
PLACE : Le traitement « PLACE » correspond au « CANDIDAT ». Un numéro de place a été affecté aux candidats lors du placement par ordre alphabétique qui précède l’envoi des convocations.
PLACE LIBRE : Le traitement « PLACE_LIBRE » est en fait le traitement d’un numéro de place référent qui palie les éventuelles candidatures supprimées.
PAGE : Lorsque la dernière place ne correspond pas à un multiple de 4, le nombre de pages n’est pas le même selon la pile.
PILE : C’est le nombre de pages qui détermine le changement de pile.
Cet exercice d’algorithmie n’est autre que le programme "post_itBDD.ace" d’une application Examens-Concours développée avec le SGBD Informix de 1992 à 2007.
Dans un environnement SGBD, c’est le programme qui constitue et structure le FLE dont il a besoin.
Fichier Logique de Sortie (FLS)
tmp (table temporaire)
Fichier Logique d’Entrée (FLE)
ec (examens-concours),
cec (candidatures examens-concours),
ln (logname).Fichier Logique de Sortie (FLS)
tmp (table temporaire)
§ 1.3.1. Les tables de la BDD sollicitées par le programme "post_itBDD.ace"
Table ec
Pour les besoins de l’édition des post_it, la table « ec » s’est enrichie de l’attribut « place » correspondant à la dernière place, donc au nombre de candidats inscrits au concours. Les attributs « place » et « inscrits » sont valorisés lors du placement des candidats, effectué une seule fois juste avant l’impression des convocations.
Pour différentes raisons, le nombre d’inscrits peut évoluer après le placement et l’envoi des convocations. Il peut exceptionnellement augmenter mais surtout diminuer suite à des désistements. Le placement ne pouvant plus être relancé, l’ajout éventuel d’une candidature peut toujours se faire mais manuellement par le DBA (DataBase Administrator). Un désistement a pour conséquences la suppression physique de la candidature et l’impression d’un post-it « Place libre » lors de l’édition des numéros de table (post-it).
Table cec
La table « cec » s’est enrichie de l’attribut « post-it » afin de pouvoir imprimer les numéros de table en piles. L’objectif du programme "post_itBDD.ace" consiste à associer un numéro de post-it à chaque numéro de place de façon à ce que les numéros de place puissent être imprimés quatre par page dans l’ordre des numéros de post-it (voir le jeu d’essai, ci-dessous).
Table ln
Chaque gestionnaire est identifié par son logname lors de sa connexion. Transmis en paramètre au programme, le logname permet de s’assurer que le terminaliste exécutant le programme est bien habilité à le faire.
Les attributs concernant le « suivi… » permettent de renseigner les coordonnées du gestionnaire-référent dans certains états comme les convocations.
Chaque bureau de gestionnaires est doté d’une imprimante HP Laser, mais le parc des imprimantes n’est pas strictement homogène. La table ln permet d’adapter les impressions à l’imprimante de destination associée au gestionnaire.
Table tmp
Cette table est utilisée dans l’application pour intervenir sur la table cec (candidatures) via des requêtes SQL.
Le fichier out créé par le programme "post_itBDD.ace" sera chargé dans la table tmp pour renseigner via une requête SQL l’attribut cec.post_it de la table cec (candidatures).
§ 1.3.2. Le programme source "post_itBDD.ace"
{================================= post_itBDD =================================}
{ }
{ ACE : post_itBDD.ace }
{ }
{ SHELL : ../shell_1/post_itBDD }
{ }
{ AUTEUR : APL-AML }
{ }
{ Objet : Création du fichier "$(LOGNAME).out" à loader dans la table tmp }
{ pour mise à jour de l'information cec.post_it }
{ à l'aide du sql "post_itBDD.sql" }
{ }
{ L'édition des post_it s'effectue à l'aide du shell "post_itALL" }
{ }
{ "post_itBDD.ace" et "post_itALL.ace" gèrent les places libres. }
{ Il est donc possible de relancer éventuellement cette chaine. }
{ }
{ Date : 10 Mars 1992 }
{ }
{==============================================================================}
{========================}
{==========================} DATABASE concours END {==========================}
{========================}
{================================} DEFINE {==================================}
{} {}
{} PARAM[1] p_c_ec CHAR(5) {}
{} PARAM[2] p_t_ec CHAR(2) {}
{} PARAM[3] p_s_ec CHAR(2) {}
{} PARAM[4] p_logname CHAR(8) {}
{} {}
{} VARIABLE j_page INTEGER {}
{} VARIABLE i_page INTEGER {}
{} VARIABLE i_pile INTEGER {}
{} VARIABLE v_post_it INTEGER {}
{} VARIABLE v_place INTEGER {}
{} VARIABLE v_reste INTEGER {}
{} {}
{==================================} END {===================================}
{================================== INPUT ===================================}
{} {}
{ PROMPT FOR v_dp USING " CONCOURS : " }
{} {}
{=================================== END ====================================}
{================================} OUTPUT {==================================}
{} {}
{ REPORT TO PRINTER }
{} REPORT TO PIPE "cat > ${LOGNAME}.out" {}
{} TOP MARGIN 0 {}
{} BOTTOM MARGIN 0 {}
{} LEFT MARGIN 0 {}
{} PAGE LENGTH 58 {}
{} {}
{==================================} END {===================================}
{=================================} SELECT {=================================}
ec.cts ec_cts,
ec.c_ec ec_c_ec,
ec.t_ec ec_t_ec,
ec.s_ec ec_s_ec,
ec.place ec_place,
cec.n_cec cec_n_cec,
cec.place cec_place
FROM ec,
cec,
ln
WHERE ec.c_ec = $p_c_ec
AND ec.t_ec = $p_t_ec
AND ec.s_ec = $p_s_ec
AND ec.cts = cec.cts
AND (cec.c_decision = "A" OR cec.c_decision = "C")
AND cec.place IS NOT NULL
AND ln.logname = $p_logname
AND (ln.service IS NULL OR ln.service = ec.service)
{===============================} ORDER BY {================================}
ec_cts,
cec_place
{==================================} END {===================================}
{=================================} FORMAT {=================================}
{------------------------} BEFORE GROUP OF ec_cts {-----------------------}
LET j_page = ec_place / 4
LET v_reste = ec_place - (j_page * 4)
LET j_page = (ec_place + 3) / 4
LET i_page = 0
LET i_pile = 1
LET v_place = 1
{---------------------------- FIRST PAGE HEADER ----------------------------}
{------------------------------ PAGE HEADER ------------------------------}
{------------------------------- PAGE TRAILER -------------------------------}
{------------------------------} ON EVERY ROW {------------------------------}
WHILE v_place < cec_place
DO BEGIN
IF i_page = j_page
THEN BEGIN
LET i_pile = i_pile + 1
LET i_page = 0
IF v_reste > 0
THEN LET v_reste = v_reste - 1
IF v_reste = 0
THEN LET j_page = ec_place / 4
END
LET i_page = i_page + 1
LET v_place = v_place + 1
END
IF i_page = j_page
THEN BEGIN
LET i_pile = i_pile + 1
LET i_page = 0
IF v_reste > 0
THEN LET v_reste = v_reste - 1
IF v_reste = 0
THEN LET j_page = ec_place / 4
END
LET v_post_it = i_pile + (i_page * 4)
PRINT cec_n_cec USING "<<<<<<<<<<<<", "||",
ec_c_ec CLIPPED, "|", ec_t_ec, "|", ec_s_ec, "|-|-|-|-|||",
cec_place USING "<<<<", "||", v_post_it USING "<<<<", "|||||||||"
LET i_page = i_page + 1
LET v_place = v_place + 1
{-------------------------- TRAITEMENT FIN DE PAGE --------------------------}
{------------------------ TRAITEMENT EN-TETE DE PAGE ------------------------}
{------------------------ TRAITEMENT LIGNE COURANTE ------------------------}
{------------------------- AFTER GROUP OF ec_cts -------------------------}
{------------------------------} ON LAST ROW {-------------------------------}
PRINT cec_n_cec USING "<<<<<<<<<<<<", "||",
ec_c_ec CLIPPED, "|", ec_t_ec, "|", ec_s_ec, "|-|-|-|-|||",
cec_place USING "<<<<", "||", v_post_it USING "<<<<", "||||||||-|"
{ - Reinitialisation de l'imprimante "HP LASERJET III Si" }
{==================================} END {===================================}
§ 1.3.3. Les requêtes SQL
{
post_itBDD.sed
}
{ Renseignement ec.place = dernière place du concours }
{ La dernière place déterminera le nombre de pages = (ec.place + 3) / 4 }
lock table ec in exclusive mode;
update ec
set ec.place = (select max(cec.place)
from cec
where cec.c_ec = "C_EC"
and cec.t_ec = "T_EC"
and cec.s_ec = "S_EC")
where ec.c_ec = "C_EC"
and ec.t_ec = "T_EC"
and ec.s_ec = "S_EC";
unlock table ec;
{------------------------------------------------------------------------------}
{ Renseignement de cec.post_it depuis le fichier "LOGNAME.out" }
{ créé par le programme "post_itBDD.ace" }
lock table tmp in exclusive mode;
delete from tmp where tmp.n_cec is not null;
load from "LOGNAME.out" insert into tmp;
update cec
set (cec.post_it)
= ((select tmp.post_it
from tmp
where cec.n_cec = tmp.n_cec))
where cec.c_ec = "C_EC"
and cec.t_ec = "T_EC"
and cec.s_ec = "S_EC";
{------------------------------------------------------------------------------}
{ Renseignement ec.place = dernière place du concours }
{ Le programme post_itBDD a flagué la dernière place du fichier "LOGNAME.out" }
{ Cette requête SQL est inutile puisque ec.place a déjà été renseigné }
{ Elle a servi à vérifier le résultat de la première requête }
update ec
set ( ec.place)
= ((select tmp.place
from tmp
where tmp.c_ec = ec.c_ec
and tmp.t_ec = ec.t_ec
and tmp.s_ec = ec.s_ec
and tmp.flag = "-"))
where ec.c_ec = "C_EC"
and ec.t_ec = "T_EC"
and ec.s_ec = "S_EC";
unlock table tmp;
{------------------------------------------------------------------------------}
§ 2. La pédagogie LCP
§ 2.1. Méthodologie « Logique de Construction de Programme » (LCP)
LCP procède par structuration :
La structure hiérarchique d'un programme se déduisant logiquement de la structure des données utilisées (FLS/FLE), la construction du programme commence par la structuration des données qu'il doit produire en sortie.
Au-delà de la structuration hiérarchique du programme déterminée par la structure des données, le degré de décomposition algorithmique peut descendre jusqu’au niveau de l’instruction. Cela dépend de la capacité d’abstraction du programmeur. La seule règle qui régit la réflexion :
« Penser hiérarchiquement par traitements, autrement dit : raisonner du plus global vers le plus détaillé, par décompositions hiérarchiques successives sur la base des actions et non sur celle des conditions ».
Structuration du FLS, du FLE et du PRG
Concernant ce programme post_itBDD.ace, la structuration classique LCP est rudimentaire puisqu’il s’agit de créer une seule information en sortie (post_it) à partir d’une seule information en entrée (place).
Structuration des données de sortie (informations présentes).
Les données de sortie ne sont pas exclusivement des données destinées à être imprimées. Ce peut être des données de la BDD (écran de saisie) ou le résultat d’un traitement particulier comme c’est le cas pour le programme "post_itBDD.ace" proposé.
Structuration des données d’entrée (informations utiles).
LCP est une méthode de programmation conçue à l’origine dans un contexte batch où le Fichier Logique en Entrée (FLE) était constitué en amont du programme. Dans un contexte BDD, c’est le développeur qui constitue et structure le FLE dont le programme a besoin.
C’est la conception et la structuration préalable du FLS qui inspire la conception et la structuration du FLE.
Structuration du programme.
La structuration du programme se déduit de celle du FLE pour ce qui concerne les Ensembles De Données (EDD), mais la décomposition structurelle du programme peut devoir être poussée plus finement, au-delà des EDD, tout en respectant la logique LCP qui consiste à penser par traitements. C’est le cas pour ce programme "post_itBDD.ace".
§ 2.2. LCP et le Programme "post_itBDD.ace"
Structuration des données de Sortie (FLS)
Représentation des Ensembles De Données (EDD) sous forme de patatoïdes :
Les candidatures supprimées n’apparaissent pas bien sûr dans le FLE. La structuration du programme prenant en compte les places libres générées par la suppression possible de certaines candidatures ne peut se réaliser que par la réflexion, tout comme la détermination du numéro de post_it. Symboliser cette réflexion sous forme d’un diagramme avec des accolades peut s’avérer très vite compliqué.
Traduction d’un début de cette réflexion sous forme d’un diagramme avec des accolades :
┌ ┌ ┌ ┌
│ D-PRG │ D-PLACE │ D-PLACE LIBRE │ D-PAGE
│ │ │ PLACE (0,1) │ T-PAGE (0,1)
│ │ PLACE LIBRE (PL) < PAGE (0,1) <
│ │ │ │ T-PAGE (0,1)
│ │ │ F-PLACE LIBRE │ F-PAGE
PRG < PLACE (P’) < INTER └ └
│ │
│ │ T-PAGE (0,1)
│ │ T-PAGE (0,1)
│ │
│ F-PRG │ F-PLACE
└ └
Niveau : Niveau 1 Niveau 2 Niveau 3 Niveau 4
Référentiel : Place CEC Place Référente Place libre Page
■ § 3 Édition des numéros de table
■ § 3.1. Programme source "post_itALL.ace"
Le programme imprime l’ensemble des POST-IT (numéros de table). On retrouve évidemment le problème des places libres au moment de l’impression. Facile !
Comme pour le programme précédent, l’algorigramme a été réalisé à postériori, le 07/07/2019 pour décrypter le raisonnement par traitements réalisé au moment de la conception. Si l’algorgramme parait simple, la programmation est assez technique.
L’idée est d’imprimer les numéros de table, deux par deux. Pour simplifier la programmation, les deux numéros de table sont traités de la même façon. L’impression se réalise après le traitement du deuxième numéro de table.
La séquence logique « F_PROG » doit prévoir l’éventualité d’un dernier numéro de table à imprimer lorsque le nombre total de numéros de tables est impair.
Pour en savoir davantage sur LCP, vous trouverez trois billets dans mon blog dont le billet Méthodologie de programmation LCP qui m'a permis d'alimenter cette discussion. Ce billet est une ébauche de tutoriel LCP en cours de rédaction.
Adepte LCP, j’expose dans ce billet mon expérience de la méthode en respectant au mieux la pédagogie originelle. Certains aspects de cette pédagogie qui se réfèrent à des supports de cours des années 70 peuvent décourager le lecteur. Il suffit de les survoler ou de passer outre en utilisant la navigation internet « Rechercher dans la page ».
Le Club Developpez.com n'affiche que des publicités IT, discrètes et non intrusives.
Afin que nous puissions continuer à vous fournir gratuitement du contenu de qualité,
merci de nous soutenir en désactivant votre bloqueur de publicités sur Developpez.com.