home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
DP Tool Club 26
/
CD_ASCQ_26_1295.iso
/
voxrom
/
textes
/
repwin08
/
annexes
/
dionys
/
d_hanoi
/
hanoi.pas
< prev
Wrap
Pascal/Delphi Source File
|
1995-10-01
|
16KB
|
497 lines
Program JeuHanoi;
Uses Graph, Crt;
(**************** Declarations des TYPES ***********************************)
Type TDisque = Record
Diam : Word; { un disque est représenté par son diamètre }
Coul : Byte; { et par sa couleur }
End;
Type TPoint = Record { Un point à l'écran }
X,Y : Word;
End;
Type TPtPile = ^TElemPile; { Une pile est un pointeur sur un élément d'une pile }
TElemPile = Record { Un élément d'une pile contient: }
Disque : TDisque; { - Un disque }
Reste_Pile : TPtPile; { - Le reste de la pile }
End;
{ Description de l'objet Pile. Une pile est constituée de
- Une liste d'éléments (une liste de disques)
- Les actions associées. On ne peut réaliser que 3 actions sur une pile:
* Empiler un élément (un disque)
* Dépiler un élément
* Tester si la pile est vide }
Type TPile = Object
Pile : TPtPile;
Procedure Init; { Vide la pile }
Procedure Empile(Disque : TDisque);
Procedure Depile(Var Disque : TDisque);
Function EstVide : Boolean;
End;
{ Description d'un Baton qui va contenir une série de disques, et des
2 actions possibles sur un tel baton:
- Enfiler un disque
- Défiler un disque }
Type TBaton = Object
Pile : TPile; { Pile de disques }
NbDisques : Byte; { Nombre de disques emfilés sur le baton }
AuDessus : TDisque; { Disque qui se trouve au dessus du baton, prêt à
être enfilé. }
Position : TPoint; { Position du baton à l'écran. Le baton est repéré
par sa base }
Hauteur : Word; { Hauteur du baton (en points) }
Procedure Init(X,Y,Haut : Word); { Initialise le baton:
- sa position et sa hauteur
- vide la pile de disques }
Function GetNbDisques : Byte; { Renvoi le nombre de disques enfilés }
Procedure PoseDessus(Disque : TDisque); { Pose au dessus du baton, prêt à
enfiler }
Procedure Enfile; { Enfile le disque situé au dessus du baton }
Procedure Defile; { Defile le premier disque qui se trouve ensuite
au dessus du baton }
Procedure Done; { Vide proprement la pile de disques }
End;
{ Le jeu en lui même, avec sa règle unique }
Type THanoi = Object
Baton1, Baton2, Baton3 : TBaton; { Le jeu est composé de 3 batons }
{ Initialise le jeu:
- Sa position (repéré par sa base sur laquelle sont posés les batons)
- La hauteur du jeu
- L'intervalle entre les batons
- Enfile tous les disques sur le premier baton}
Procedure Init(X,Y,Hauteur,Intervalle : Word);
{ La seule régle du jeu: déplacer les disques d'un baton à l'autre
sachant que l'on ne peut pas poser un disque d'un diamètre donné
sur un disque de diamètre plus petit. }
Procedure Deplace(var BatonO, BatonD : TBaton);
Procedure Joue;
Procedure Solution(Var Tour1, Tour2, Tour3 : TBaton; NbDisq : Byte);
Procedure Done;
End;
(**************** Declarations des CONSTANTES ******************************)
Const HautDisque = 30;
NoDisq : TDisque = (Diam : 0; Coul : 0);
Disq1 : TDisque = (Diam : 170; Coul : 9);
Disq2 : TDisque = (Diam : 150; Coul : 10);
Disq3 : TDisque = (Diam : 130; Coul : 11);
Disq4 : TDisque = (Diam : 110; Coul : 12);
Disq5 : TDisque = (Diam : 90; Coul : 13);
Disq6 : TDisque = (Diam : 70; Coul : 14);
Disq7 : TDisque = (Diam : 50; Coul : 15);
(***************** Code des OBJETS *****************************************)
(* --------------- Objet TPILE ------------ *)
Procedure TPile.Init;
Begin
Pile := NIL
End;
Procedure TPile.Empile;
Var ElemPile : TPtPile;
Begin
New (ElemPile);
ElemPile^.Disque := Disque;
ElemPile^.Reste_Pile := Pile;
Pile := ElemPile
End;
Procedure TPile.Depile;
Var ElemPile : TPtPile;
Begin
If Not EstVide
Then Begin
ElemPile := Pile;
Disque := ElemPile^.Disque;
Pile := ElemPile^.Reste_Pile;
Dispose (ElemPile)
End
Else Disque := NoDisq
End;
Function TPile.EstVide;
Begin
EstVide := (Pile=NIL)
End;
(* --------------- Objet TBATON ----------- *)
Procedure TBaton.Init;
Begin
SetLineStyle (SolidLn,0,NormWidth);
SetColor (Yellow);
Rectangle (X-3,Y-Haut,X+3,Y);
Position.X := X;
Position.Y := Y;
Hauteur := Haut;
NbDisques := 0;
AuDessus := NoDisq;
Pile.Init
End;
Function TBaton.GetNbDisques;
Begin
GetNbDisques := NbDisques
End;
Procedure TBaton.PoseDessus;
Begin
AuDessus := Disque
End;
Procedure TBaton.Enfile;
Var Haut : TPoint;
Bas : TPoint;
YCpt : Word;
Begin
If AuDessus.Diam = 0
Then Exit;
Haut.X := Position.X - AuDessus.Diam div 2;
Haut.Y := Position.Y - Hauteur - HautDisque - 20;
Bas.X := Position.X - AuDessus.Diam div 2;
Bas.Y := Position.Y - (HautDisque+1) * (NbDisques+1);
With Haut Do
Begin
SetFillStyle (SolidFill,AuDessus.Coul);
Bar (X, Y, X + AuDessus.Diam, Y + HautDisque);
For YCpt := Y To Bas.Y-1 Do
Begin
SetColor (Black);
Line(X, YCpt, X + AuDessus.Diam, YCpt);
If YCpt = Position.Y-Hauteur
Then Begin
SetColor (Yellow);
Line (Position.X - 3, YCpt, Position.X + 3, YCpt)
End;
If YCpt > Position.Y-Hauteur
Then Begin
PutPixel (Position.X - 3, YCpt,Yellow);
PutPixel (Position.X + 3, YCpt,Yellow)
End;
SetColor (AuDessus.Coul);
Line (X, YCpt + HautDisque + 1, X + AuDessus.Diam,YCpt + HautDisque + 1)
End
End;
Pile.Empile (AuDessus);
Inc (NbDisques);
AuDessus := NoDisq
End;
Procedure TBaton.Defile;
Var Haut : TPoint;
Bas : TPoint;
YCpt : Word;
Disque : TDisque;
Begin
If NbDisques=0
Then Exit;
If Pile.EstVide
Then Exit;
Pile.Depile(Disque);
If Disque.Diam=0
Then Exit;
Haut.X := Position.X - Disque.Diam div 2;
Haut.Y := Position.Y - Hauteur - 20;
Bas.X := Position.X - Disque.Diam div 2;
Bas.Y := Position.Y - (HautDisque+1) * (NbDisques-1)-1;
With Bas Do
Begin
SetFillStyle (SolidFill,Disque.Coul);
Bar (X, Y - HautDisque, X + Disque.Diam, Y);
For YCpt := Y DownTo Haut.Y+1 Do
Begin
SetColor (Black);
Line(X, YCpt, X + Disque.Diam, YCpt);
If YCpt = Position.Y-Hauteur
Then Begin
SetColor (Yellow);
Line (Position.X - 3, YCpt, Position.X + 3, YCpt)
End;
If YCpt > Position.Y-Hauteur
Then Begin
PutPixel (Position.X - 3, YCpt,Yellow);
PutPixel (Position.X + 3, YCpt,Yellow)
End;
SetColor (Disque.Coul);
Line (X, YCpt - HautDisque - 1, X + Disque.Diam,YCpt - HautDisque - 1)
End
End;
Dec (NbDisques);
AuDessus := Disque
End;
Procedure TBaton.Done;
Var Disque : TDisque;
Begin
While Not Pile.EstVide Do
Pile.Depile(Disque)
End;
(* --------------- Objet THANOI ----------- *)
Procedure InitGraphique; External;
Procedure THanoi.Init;
Var Place : Word;
Begin
InitGraphique;
SetLineStyle(SolidLn,0,NormWidth);
SetColor(Yellow);
Rectangle(X,Y,X + 3*intervalle, Y+10);
Place := X + Intervalle div 2;
Baton1.Init(Place, Y, Hauteur);
Place := Place + Intervalle;
Baton2.Init(Place, Y, Hauteur);
Place := Place + Intervalle;
Baton3.Init (Place, Y, Hauteur);
With Baton1 Do
Begin
PoseDessus(Disq1);
Enfile;
PoseDessus(Disq2);
Enfile;
PoseDessus(Disq3);
Enfile;
PoseDessus(Disq4);
Enfile;
PoseDessus(Disq5);
Enfile;
PoseDessus(Disq6);
Enfile;
PoseDessus(Disq7);
Enfile
End
End;
Procedure THanoi.Deplace;
Var Depart,Fin : TPoint;
Procedure DeplaceGD;
Var XCpt : Word;
Begin
For XCpt := Depart.X To Fin.X-1 Do
Begin
SetColor (BatonO.AuDessus.Coul);
Line (XCpt + BatonO.AuDessus.Diam + 1, Depart.Y,
XCpt + BatonO.AuDessus.Diam + 1, Depart.Y + HautDisque);
SetColor (Black);
Line (XCpt, Depart.Y, XCpt, Depart.Y + HautDisque)
End
End;
Procedure DeplaceDG;
Var XCpt : Word;
Begin
For XCpt := Depart.X DownTo Fin.X+1 Do
Begin
SetColor (BatonO.AuDessus.Coul);
Line (XCpt - 1, Depart.Y, XCpt - 1, Depart.Y + HautDisque);
SetColor (Black);
Line (XCpt + BatonO.AuDessus.Diam, Depart.Y,
XCpt + BatonO.AuDessus.Diam, Depart.Y + HautDisque)
End
End;
Begin
If BatonO.Position.X = BatonD.Position.X
Then Exit;
BatonO.Defile;
With Depart Do
Begin
X := BatonO.Position.X - BatonO.AuDessus.Diam div 2;
Y := BatonO.Position.Y - BatonO.Hauteur - HautDisque - 20
End;
With Fin Do
Begin
X := BatonD.Position.X - BatonO.AuDessus.Diam div 2;
Y := Depart.Y
End;
If (BatonO.Position.X < BatonD.Position.X)
Then DeplaceGD
Else DeplaceDG;
BatonD.PoseDessus (BatonO.AuDessus);
BatonO.AuDessus.Diam := 0;
BatonO.AuDessus.Coul := 0;
BatonD.Enfile
End;
Procedure THanoi.Joue;
Var Disque1, Disque2 : TDisque;
Ch : Char;
Continue : Boolean;
Orig, Fin : Byte;
Procedure Bip;
Begin
Sound (250);
Delay (100);
NoSound
End;
Begin
Repeat
SetFillStyle (SolidFill,0);
Bar (Baton1.Position.X - 1, Baton1.Position.Y + 11,
Baton3.Position.X, Baton3.Position.Y + 55);
SetTextJustify (LeftText, TopText);
SetTextStyle (SansSerifFont,HorizDir,2);
SetColor (White);
OutTextXY (Baton1.Position.X, Baton1.Position.Y + 30, 'De: ');
Repeat
Repeat
Repeat Until KeyPressed;
Ch := ReadKey
Until ( (Ord(Ch) > 48) And (Ord(Ch) < 52) ) Or (Ord(Ch) in [13,27]);
If Ch in [#13,#27]
Then Exit;
Orig := Ord(Ch) - 48;
Case Orig Of
1 : Begin
Continue := (Baton1.GetNbDisques > 0);
Baton1.Pile.Depile (Disque1);
Baton1.Pile.Empile (Disque1)
End;
2 : Begin
Continue := (Baton2.GetNbDisques > 0);
Baton2.Pile.Depile (Disque1);
Baton2.Pile.Empile (Disque1)
End;
3 : Begin
Continue := (Baton3.GetNbDisques > 0);
Baton3.Pile.Depile (Disque1);
Baton3.Pile.Empile (Disque1)
End
End;
If Not Continue
Then Bip
Until Continue;
SetColor (Red);
OutTextXY (Baton1.Position.X, Baton1.Position.Y + 30,'De: ');
OutTextXY (Baton1.Position.X + 35, Baton1.Position.Y + 30,Ch);
SetColor (15);
OutTextXY (Baton2.Position.X, Baton2.Position.Y + 30, 'Vers: ');
Repeat
Repeat
Repeat Until KeyPressed;
Ch := ReadKey
Until ( (Ord(Ch) > 48) And (Ord(Ch) < 52) ) Or (Ord(Ch) in [13,27]);
If Ch in [#13,#27]
Then Exit;
Fin := Ord(Ch) - 48;
Case Fin Of
1 : Begin
If Baton1.GetNbDisques > 0
Then Begin
Baton1.Pile.Depile (Disque2);
Baton1.Pile.Empile (Disque2);
Continue := (Disque2.Diam >= Disque1.Diam)
End
Else Continue := True
End;
2 : Begin
If Baton2.GetNbDisques > 0
Then Begin
Baton2.Pile.Depile (Disque2);
Baton2.Pile.Empile (Disque2);
Continue := (Disque2.Diam >= Disque1.Diam)
End
Else Continue := True
End;
3 : Begin
If Baton3.GetNbDisques > 0
Then Begin
Baton3.Pile.Depile (Disque2);
Baton3.Pile.Empile (Disque2);
Continue := (Disque2.Diam >= Disque1.Diam)
End
Else Continue := True
End
End;
If Not Continue
Then Bip
Until Continue;
SetColor (Red);
OutTextXY (Baton2.Position.X, Baton2.Position.Y + 30, 'Vers: ');
OutTextXY (Baton2.Position.X + 60, Baton2.Position.Y + 30, Ch);
Case Orig of
1 : Case Fin Of
2 : Deplace (Baton1, Baton2);
3 : Deplace (Baton1, Baton3)
End;
2 : Case Fin Of
1 : Deplace (Baton2, Baton1);
3 : Deplace (Baton2, Baton3)
End;
3 : Case Fin Of
1 : Deplace (Baton3, Baton1);
2 : Deplace (Baton3, Baton2)
End
End
Until Not Continue
End;
Procedure THanoi.Solution;
Begin
if keypressed then exit;
If NbDisq>0
Then Begin
Solution(Tour1, Tour3, Tour2, NbDisq-1);
Deplace(Tour1, Tour3);
Solution(Tour2, Tour1, Tour3, NbDisq - 1);
End;
End;
Procedure THanoi.Done;
Begin
CloseGraph;
Baton1.Done;
Baton2.Done;
Baton3.Done
End;
(********************** Autre Code *****************************************)
Procedure InitGraphique;
Var Driver : Integer;
Mode : Integer;
ErrCode : Integer;
RepBGI : string;
Begin
Driver := Detect;
RepBGI := ParamStr(0);
while RepBgi[ord(RepBgi[0])] <> '\' do dec(RepBgi[0]);
InitGraph(Driver, Mode,RepBGI);
ErrCode := GraphResult;
If ErrCode <> grOk
Then Begin
Writeln('Erreur graphique: ', GraphErrorMsg(ErrCode));
Halt(1)
End
End;
Var Hanoi : THanoi;
Begin
Hanoi.Init(20,400,300,200);
if paramcount = 0
then Hanoi.Joue
else Hanoi.Solution (Hanoi.Baton1, Hanoi.Baton2, Hanoi.Baton3, 7);
Readkey;
Hanoi.Done
End.