Une solution de l'examen terminal du 11 janvier 2001

EXERCICE

1.)

Ce programme affiche :        X=10, Y=9

    En effet le deuxième paramètre, noté M, de la procédure P est "passé par adresse". Cela signifie que, quand on exécute P(X,Y), la variable Y elle-même sera modifiée dans la mesure où le paramètre M le sera. Ainsi l'affectation M:=M-1 enlèvera 1 à la variable globale Y. Par conséquent, à la fin de l'exécution de la procédure P, la variable Y contiendra 9.
    Par contre, le premier paramètre, noté N, de la procédure P est "passé par valeur". Cela signifie que, quand on exécute P(X,Y), la valeur de la variable X elle-même ne sera pas modifiée par une quelconque modification de N.  Par conséquent, à la fin de l'exécution de la procédure P, la variable X contiendra toujours 10.

2.)

Nous avons choisi ici une fonction retournant la nouvelle valeur de M.

PROGRAM PassageDeParametres ;
    Var X, Y : integer ;
FUNCTION P(N,M : integer) : integer ;
    Begin
    N:=N-1 ; M:=M-1 ;
    P:=M ;
    End ;
BEGIN
    X:=10 ; Y:=10 ;
    Y:=P(X,Y) ;
    writeln('X= ',X:1,' , Y=',Y:1) ;
END.

3.)

    En Pascal, une fonction retourne une valeur ce qui n'est pas le cas d'une procédure. Par conséquent, on utilise une procédure comme une nouvelle instruction du programme (instruction qui possède éventuellement des  paramètres) ; au contraire une fonction sera utilisée comme une expression et pourra être intégrée comme telle dans une affectation, un test, etc.
    Le choix alternatif entre fonction et procédure dans un programme sera donc déterminé par ce qu'on veut faire. Pour fixer les idées : pour décomposer un bloc de programme trop long, par exemple, on utilisera une procédure, on utilisera une fonction par contre pour effectuer un calcul donnant un résultat (comme le fait une fonction mathématique).
    Pour aller plus loin, ce qui précède doit être nuancé par le fait qu'une "function", en Turbo Pascal, ne peut pas retourner tout type de variable et qu'on est parfois amené à remplacer une "function" par une "procedure". Au contraire, on ne peut pas toujours remplacer, en Pascal, une "procedure" par une "function".


PROBLEME

Première partie :

1.1.)
 

Affichage* pour S='aha' :
  1 , a : OK
Retour : TRUE
Affichage* pour S='houhou' :
  2 , o : OK
Retour : FALSE
Affichage* pour S='ahaha' :
  1 , a : OK
  2 , h : OK
Retour : TRUE
Affichage* pour S='ohe' :
 

Retour : FALSE

* la fonction AGREABLE vérifie si une chaîne de caractère est un palindrome.

1.2.) On a choisi une fonction :

FUNCTION CREER(M:integer) : CHAINE ;
Var S, T : CHAINE ;
    i : integer ;
    c : char ;
Begin
(* initialisation *)
randomize ;
S:='' ; T:='' ;
(* construction de la chaîne par les deux bouts S et T *)
for i:=1 to (M div 2) do
    begin
    c:=CHR(random(26)+97) ;
    S:=S+c ; T:=c+T ;
    end ;
(* si la chaîne est de longueur impaire *)
(* il faut rajouter le caractère du milieu *)
if (M mod 2)=1
    then S:=S+CHR(random(26)+97) ;
(* on retourne la chaîne obtenue *)
CREER:=S+T ;
End ;

Deuxième partie :

2.1.)

CONST NMAX=20 ; MMAX=25 ; (* par exemple *)
TYPE GRILLE = array[1..NMAX,1..MMAX] of char ;

2.2.) on a choisi ici une procédure.

PROCEDURE SAISIR(N,M : integer ; Var G : GRILLE) ;
Var i, j : integer ;
    S : CHAINE ;
Begin
writeln('saisie de ',n,' chaînes de caractères') ;
for i:=1 to n do
    (* pour chaque ligne *)
    begin
    (* saisie d'une chaine de longueur M *)
    repeat
        write(i,'-ième chaîne ? ') ; readln(S) ;
        if length(S)>M
            then writeln('chaîne trop longue') ;
        if length(S<M)
            then writeln('chaîne trop courte) ;
        until length(S)=M ;
    (* rajouter la i-ième chaîne *)
    (* dans la i-ième ligne de la grille *)
    for j:=1 to M do G[i,j]:=S[j] ;
    end ;
End ;

2.3.) on a choisi ici une procédure.

PROCEDURE MODIFIER(N,M : integer ; Var G: GRILLE) ;
Var i, j : integer ;
    c : char ;
Begin
writeln('Modifier une case G[ligne,colonne]')
(* saisir le numéro de la ligne *)
repeat
    write('quelle ligne (1 à ',n,') ? ') ; readln(i) ;
    until (i>=1) and (i<=N) ;
(* saisir le numéro de la colonne *)
repeat
    write('quelle colonne (1 à ',M,') ? ') ; readln(j) ;
    until (j>=1) and (j<=M) ;
(* saisir le nouveau caractère *)
writeln('l''ancien caractère en ',i,',',j,' est ',G[i,j]) ;
repeat
    write('quel nouveau caractère (entre ''a'' et ''z'') ? ') ;
    readln(c) ;
    until (c>='a') and (c<='z') ;
(* modifier la grille *)
G[i,j]:=c ;
End ;

2.4.)

PROCEDURE AFFICHER(N,M : integer ; G : GRILLE) ;
Var i, j : integer ;
Begin
(* afficher l'en-tête *)
writeln('N=',N,' et M=',M) ; writeln ;
(* afficher les numéros de colonnes *)
writeln(' ':4) ;
for j:=1 to M do write(j:3) ;
writeln ;
(* afficher la grille *)
for i:=1 to N do
    (* pour chaque ligne de la grille *)
    begin
    (* afficher le numéro de la ligne... *)
    write(i:4) ;
    (* ... et son contenu *)
    for j:=1 to M do write(G[i,j]:3) ;
    writeln ;
    end ;
End ;

N.B. : Cette affichage est conçu pour des valeurs N<=20 et M<=25 afin de tenir dans un écran 24x80.

2.5.)

Cette première version est basée sur la fonction AGREABLE :

FUNCTION AGRILLABLE(N,M : integer ; G : GRILLE) : boolean ;
Var i, j : integer ;
    test : boolean ;
    S : CHAINE ;
Begin
test:=true ;
(* vérifier les lignes *)
for i:=1 to N do
    begin
    S:='' ;
    for j:=1 to M do s:=s+G[i,j] ;
    test:=(test and AGREABLE(S));
    end ;
(* vérifier les colonnes *)
for j:=1 to M do
    begin
    S:='' ;
    for i:=1 to N do S:=S+G[i,j] ;
    test:=(test and AGREABLE(S)) ;
    end ;
AGRILLABLE:=test ;
End ;

Voici une deuxième version n'utilisant pas la fonction AGREABLE :

FUNCTION AGRILLABLE(N,M : integer ; G : GRILLE) : boolean ;
Var i, j : integer ;
    test : boolean ;
Begin
test:=true ;
for i:=1 to (N mod 2) do
    for j:=1 to (M mod 2) do
        if (G[i,j]<>G[i,M+1-j]) or
           (G[i,j]<>G[N+1-i,j]) or
           (G[i,j]<>G[N+1-i,M+1-j])
           then test:=false ;
AGRILLABLE:=test ;
End ;

2.6.) on a choisi ici aussi une procédure.

PROCEDURE CONSTRUIRE(N, M : integer ; Var G : GRILLE) ;
Var i, j : integer ;
    S : CHAINE ;
Begin
for i:=1 to (N div 2)+(N mod 2) do
    begin
    S:=CREER(M) ;
    for j:=1 to M do
        begin
        G[i,j]:=S[j] ;
        G[N+1-i,M+1-j]:=S[j] ;
        end ;
    end ;
End ;

2.7.)

PROGRAM Probleme ;

CONST NMAX=20 ;
      MMAX=25 ;
TYPE GRILLE = array[1..NMAX,1..MMAX] of char ;
VAR G : GRILLE ;
    N, M : integer ;
    choix : integer ;
BEGIN
(* reprendre au début du programme si on le souhaite *)
repeat
    (* saisir N, M, puis la grille G *)
    repeat
        write('nombre de lignes (1 à ',NMAX,') ? ') ;
        readln(N) ;
        until (N>=1) and (N>=NMAX) ;
    repeat
        write('nombre de colonnes (1 à ',MMAX,') ? ') ;
        readln(M) ;
        until (M>=1) and (M>=MMAX) ;
    SAISIR(N,M,G) ;
    (* afficher la grille *)
    AFFICHER(N,M,G) ;
    (* vérifier si la grille est agréable et sinon ... *)
    if (not AGRILLABLE(N,M,G))
       then begin
            writeln('Cette grille n'est pas agréable') ;
            writeln ;
            (* menu *)
            writeln('Pour avoir une grille agréable : ') ;
            writeln('1 : modifier la grille') ;
            writeln('2 : remplacer la grille automatiquement') ;
            repeat
                write('votre choix ?') ;
                readln(choix) ;
                until (choix=1) or (choix=2) ;
            case choix of
                1 : repeat MODIFIER(N,M,G) ;
                        until AGRILLABLE(N,M,G) ;
                2 : CONSTRUIRE(N,M,G) ;
                end ;
            end ;
    (* demander si on reprend ... *)
    write(reprendre (1 pour oui, 0 pour non) ? ') ;
    readln(choix) ;
    until choix=0 ;
END.