PROGRAM ELECTIONS;

(* Pour l'‚nonc‚, voir le contenu de la proc‚dure AVERTIS
   Principe du programme :
   trois vecteurs de 20 cases afin d'accueillir
   - les noms des candidat(e)s
   - le nombre de voix obtenues par chacun(e)
   - le pourcentage que repr‚sente le nombre de voix obtenu par rapport au total des votes
   Chaque ‚tape fera l'objet d'une proc‚dure param‚tr‚e. *)

USES CRT;

TYPE STR20 = ARRAY [1..20] OF STRING;
     INT20 = ARRAY [1..20] OF LONGINT;
     REA20 = ARRAY [1..20] OF REAL;

VAR  NOM: STR20;           (* Pour contenir les noms des candidat(e)s               *)
     VOIX: INT20;          (* Pour contenir le nombre de voix de chaque candidat(e) *)
     POURCENTAGE: REA20;   (* Pour contenir le pourcentage de chaque candidat(e)    *)
     MAX: INTEGER;         (* Contiendra le nombre r‚el de candidat(e)s participant *)

PROCEDURE AVERTIS;
          BEGIN
          WRITELN ('Ce programme gŠre des ‚lections pouvant compter jusqu''… 20 candidat(e)s.');
          WRITELN ('Le nombre r‚el de candidat(e)s participant … l''‚lection sera d''abord demand‚');
          WRITELN ('Ensuite, pour chacun(e), le programme demandera :');
          WRITELN ('- le nom');
          WRITELN ('- le nombre de voix obtenues.');
          WRITELN ('Le programme classera alors les candidat(e)s');
          WRITELN ('et affichera alors par ordre d‚croissant des pourcentages :');
          WRITELN ('- le nom du/de la candidat(e)');
          WRITELN ('- le nombre de voix obtenu');
          WRITELN ('- le pourcentage obtenu.');
          WRITELN;
          END;

PROCEDURE NOMBRE_CANDIDATS (VAR MAX: INTEGER);
          BEGIN
          WRITELN ('Combien de candidat(e)s participent … cette ‚lection (entre 2 et 20)');
          READLN  (MAX); (* Robustesse: n'accepter qu'un nombre compatible avec les contraintes *)
          WHILE (MAX < 2) OR (MAX > 20) DO
                BEGIN
                WRITELN ('ERREUR! Il faut donner un nombre entre 2 et 20 y compris.');
                WRITELN ('Combien de candidat(e)s participent aux ‚lections ?');
                READLN  (MAX);
                END;
          END;

PROCEDURE COORDONNEES_CANDIDATS (MAX: INTEGER; VAR NOM: STR20; VAR VOIX: INT20);
          VAR i: INTEGER;

          BEGIN
          FOR i := 1 TO MAX DO
              BEGIN
              WRITE  ('Quel est le nom du/de la candidat(e) num‚ro ',i:2,' ? ');
              READLN (NOM [i]);
              WRITE  ('Combien de voix a-t-il/elle obtenu ? ');
              READLN (VOIX [i]);
              WRITELN;
              END;
          END;

PROCEDURE CLASSE (MAX: INTEGER; VAR NOM: STR20; VAR VOIX: INT20);
          VAR i, ATTENTE_VOIX: LONGINT;
              ATTENTE_NOM: STRING;
              PERMUTATION: BOOLEAN;

          BEGIN
(* M‚thode de tri peu performante, mais facile … comprendre. On rebalaiera les tableaux
jusqu'… ce que plus aucune permutation n'ait lieu, signe que les tableaux sont bien class‚s *)
          REPEAT
                PERMUTATION := FALSE;      (* Qui signalera si une permutation a eu lieu ou non *)
                FOR i := 1 TO MAX-1 DO     (* On s'arrˆte … MAX-1 car on v‚rifie toujours par rapport … la case
                                              qui suit. On ‚vite donc ainsi le d‚passement de la fin du tableau *)
                    IF VOIX [i] < VOIX [i+1] THEN  (* Comparaison des deux cases VOIX successives
Si la case VOIX en cours est inf‚rieure … celle qui suit, on va les permuter.
Il ne faut pas oublier de permuter les noms en parallŠle pour que les voix soient toujours au bon nom *)
                       BEGIN
(* Un serveur se trompe. Il remplit de limonade un verre … biŠre et de biŠre un verre … limonade.
Il veut inverser les deux contenus. Pour cela il a besoin d'un troisiŠme verre vide. Les variables ATTENTE
jouent le r“le des "verres vides" qui permettront de vider un verre avant de mettre le contenu de l'autre *)
                       ATTENTE_VOIX := VOIX [i];
                       ATTENTE_NOM  := NOM  [i];
                       VOIX [i] := VOIX [i+1];
                       NOM  [i] := NOM  [i+1];
                       VOIX [i+1] := ATTENTE_VOIX;
                       NOM  [i+1] := ATTENTE_NOM;
                       PERMUTATION := TRUE;        (* On signale qu'une permutation a eu lieu *)
                       END;
          UNTIL NOT PERMUTATION;   (* On n'arrˆte la boucle que quand il n'y a pas eu de permutation *)
          END;

PROCEDURE CALCULE (MAX: INTEGER; VOIX: INT20; VAR POURCENTAGE: REA20);
          VAR i: INTEGER;
              SOMME: LONGINT;

          BEGIN
          SOMME := 0;
(* Pour calculer le pourcentage, il faut le total des voix AVANT le calcul *)
          FOR i := 1 TO MAX DO
              SOMME := SOMME + VOIX [i];
(* Le pourcentage s'obtient en faisant le nombre de voix divis‚ par le total fois 100 *)
          FOR i := 1 TO MAX DO
              POURCENTAGE [i] := VOIX [i] / SOMME * 100;
          END;

PROCEDURE AFFICHE (MAX: INTEGER; NOM: STR20; VOIX: INT20; POURCENTAGE: REA20);
          VAR i: INTEGER;

          BEGIN
          CLRSCR;
          FOR i := 1 TO MAX DO
              WRITELN ('Candidat(e) ',NOM [i]:20,' a obtenu ',VOIX [i]:5,' voix, soit ',POURCENTAGE [i]:5:2,' % des votes');
          END;

BEGIN (* du programme principal *)
CLRSCR;
AVERTIS;
NOMBRE_CANDIDATS (MAX);
COORDONNEES_CANDIDATS (MAX, NOM, VOIX);
CLASSE (MAX, NOM, VOIX);
CALCULE (MAX, VOIX, POURCENTAGE);
AFFICHE (MAX, NOM, VOIX, POURCENTAGE);
READLN;
END.
