Nous utilisons un exemple très
connu utilisant la récursivité en pascal : comment placer 8
reines sur un échiquier sans qu'elles soient en prise. Nous allons
l’utiliser comme un autre exemple de contrôle du flux de l’exécution
en Delphi.
1.1 Un listing classique de récursivité
Le programme ci-dessous fournit 92 solutions comme sur un échiquier à deux joueurs sans tenir compte des effets de symétrie.procedure
ecrire(Queen:echiquier); {écrit sur l’écran une représentation d’une solution : c’est à dire un placement des 8 reines sur l’échiquier} var i,j:integer; begin k:=k+1; writeln; writeln('Solution N° : ',k:3); writeln('-------------'); writeln; for i:=1 to 8 do begin for j:=1 to 8 do if Queen[i,j]=Vrai then write('* ') else write('. '); writeln end end;{ecrire} |
procedure
placer(var diag1:diagonale_1;var diag2:diagonale_2;
var ligne:line;var reine:echiquier; var j:integer); {procedure récursive assurant le placement des reines} var i0,i:integer; begin if flag_exit then exit; if j=9 then ecrire(reine) else for i0:=1 to 8 do begin i:=i0; if(ligne[i]=Faux)and(diag1[i-j]=Faux) and(diag2[i+j]=Faux) then begin ligne[i]:=Vrai; diag1[i-j]:=Vrai; diag2[i+j]:=Vrai; reine[i,j]:=Vrai; j:=j+1; placer(diag1,diag2,ligne,reine,j); j:=j-1; ligne[i]:=Faux; diag1[i-j]:=Faux; diag2[i+j]:=Faux; reine[i,j]:=Faux; end end end;{placer} |
procedure
Reines_8; {initialisations et lancement de la récursivité} var i,j:integer; diag1:diagonale_1; diag2:diagonale_2; ligne:line; reine:echiquier; begin for i:=1 to 8 do begin ligne[i]:=Faux; for j:=1 to 8 do begin diag1[i-j]:=Faux; diag2[i+j]:=Faux; reine[i,j]:=Faux; end end; j:=1; k:=0; placer(diag1,diag2,ligne,reine,j); end;{Reines_8} |
Nous obtenons un listing séquentiel
construit ligne par ligne avec des ‘.’ Pour représenter les cases vierges
et des ‘*’ pour représenter la position d’une des huit reines.
![]() |
![]() |
.................. | ![]() |
Nous allons utiliser le RAD
Delphi pour reprendre et réutiliser le maximum de ce programme pascal
tout en améliorant l’interface. Le lecteur se rendra compte que la
réutilisation pascal Delphi est dans ce cas très correcte.
Comme nous l’avons déjà affirmé, il est possible dans
un premier temps, de reprendre un grand nombre d’exemples développés
en pascal pour les réinterfacer avec Delphi.
Nous voulons adopter la stratégie qui a été mise en place dans l’exemple d’interruption d’une itération. C’est-à-dire que nous voulons interrompre non plus la boucle, mais la profondeur de récursivité : à chaque appel récursif nous voulons mettre le logiciel en attente afin que l’utilisateur puisse conserver la vue de l’échiquier autant de temps qu’il le veut. Sur une vue donnée nous laissons à l’utilisateur la possibilité en sélectionnant une reine en place, de visualiser toutes lignes, colonnes et diagonales qui sont en " prise " par la position de cette reine.
Nous allons utiliser une combinaison
des deux outils cités précédemment :
2.1 Interrompre la récursivité avec ProcessMessages
Aspect de l’échiquier dans
la fiche form1
Nous introduisons dans la procédure
écrire une boucle d’attente permettant de savoir si l’utilisateur a
clické sur l’un des deux boutons " arrêt " ou " voir solution
suivante ". La technique employée est celle du chapitre précédent
: utilisation de flags flag_suite et flag_exit qui sont levés chacun respectivement par le bouton " voir
solution suivante " et le bouton " arrêt ".
procedure
ecrire(Queen:echiquier); var i,j:integer; begin flag_suite:=false;{flag de passage au suivant baissé} ...... for i:=1 to 8 do for j:=1 to 8 do if Queen[i,j]=Vrai then {affiche l'icone reine8}
{remplacer la reine par l'image initiale et restaurer l’échiquier} ...... end;{ecrire} |
L’arrêt de la récursivité
est provoqué par le flag_exit qui ferme la fiche " form1 " qui contient l’échiquier.
Nous n’avons qu’une seule modification à apporter dans la procédure
placer :
procedure placer(var diag1:diagonale_1;
var diag2:diagonale_2;var ligne:line;var reine:echiquier; var j:integer); var i0,i:integer; begin
if j=9 then ecrire(reine) else ........( le reste est identique ) |
Dans cette version nous introduisons une nouvelle fonctionnalité sur le contrôle du flux d’exécution. Pendant que le programme attend dans la " boucle infinie " de la procédure écrire, l’utilisateur peut vouloir visualiser pendant quelques instants les cases qui sont en prises pour une reine quelconque de l’échiquier. Cette action s’effectuera par un click sur une case occupée par une reine et nous lui colorions, en rouge par exemple, toutes les lignes en prise pour cette reine (une verticale, une horizontale et deux diagonales).
Nous utilisons un timer nommé " timer1 " qui permettra l’affichage temporisé
des quatre lignes occupées. Nous affichons les quatre lignes en rouge,
puis nous bloquons de nouveau l’exécution séquentielle du programme
par une autre boucle infinie de " temporisation " qui attend que le timer
ait fini son décompte pour continuer ensuite par restaurer l’échiquier.
repeat {boucle de messages
à windows}
|
Résultat de l’action de temporisation :
Au bout de n millisecondes (valeur interval de timer1) l’interface reprend son aspect précédent.
Tout ceci a lieu pendant que la boucle infinie d’attente générale continue à s’exécuter. Nous avons donc deux boucles qui ont été synchronisées entre elles grâce à la méthode ProcessMessages.
Nous pouvons grâce à
ce procédé déporter le flux d’exécution sur une
autre zone d’action de l’interface puis revenir au déroulement antérieur.
Ceci ressemble aux interruptions hiérarchisées dans un système
d’exploitation.