Kiedyś popełniłem z ciekawości:
unit MainForm;
interface uses
Windows,
Messages,
SysUtils,
Classes,
Graphics,
Controls,
Forms,
Dialogs,
ExtCtrls;
type
THanoiPin=0..2;
THanoiLevel=0..15;
TMain=class;
THanoiThread=class(TThread)
private
FShift:THanoiPin;
protected
FOwner:TMain;
procedure DoTerminate;override;
procedure Execute;override;
public
constructor Create(AOwner:TMain);
procedure MoveTower(ToPin,FromPin:THanoiPin;Level:THanoiLevel);
end;
TMain=class(TForm)
Timer: TTimer;
procedure FormCreate(Sender:TObject);
procedure FormResize(Sender:TObject);
procedure FormDestroy(Sender:TObject);
procedure TimerTimer(Sender:TObject);
private
Panels:array[THanoiLevel]of TPanel;
Pins:array[THanoiLevel]of THanoiPin;
Levels:array[THanoiLevel]of THanoiLevel;
FThread:THanoiThread;
FDest:THanoiPin;
FLevel:THanoiLevel;
FColors:Boolean;
public
procedure SetColors;
procedure MoveDisc;
procedure Reset;
end;
var Main:TMain;
implementation
{$R *.DFM}
constructor THanoiThread.Create(AOwner:TMain);
begin
inherited Create(true);
Priority:=tpLowest;
FreeOnTerminate:=true;
FOwner:=AOwner;
FOwner.FThread:=Self;
FShift:=0;
Resume;
end;
procedure THanoiThread.DoTerminate;
begin
FOwner.FThread:=nil;
inherited DoTerminate;
end;
procedure THanoiThread.Execute;
var I:Integer;
begin
while not Terminated do
begin
MoveTower(0,1,Low(THanoiLevel));
with FOwner do
begin
for I:=1 to 6 do
begin
FColors:=(((I)and(1))>0);
Synchronize(SetColors);
end;
end;
if FShift=2 then
begin
FShift:=0;
end
else
begin
Inc(FShift);
end;
end;
end;
procedure THanoiThread.MoveTower(ToPin,FromPin:THanoiPin;Level:THanoiLevel);
begin
if Level<=High(THanoiLevel) then
begin
if Terminated then Exit;
MoveTower(ToPin,3-ToPin-FromPin,Level+1);
with FOwner do
begin
FDest:=(FShift+FromPin)mod(3);
FLevel:=Level;
Synchronize(MoveDisc);
end;
MoveTower(3-ToPin-FromPin,FromPin,Level+1);
end;
end;
procedure TMain.SetColors;
var I:THanoiLevel;
begin
for I:=0 to High(THanoiLevel) do
begin
with Panels[I] do
begin
if FColors then
begin
Color:=clLime;
end
else
begin
ParentColor:=true;
end;
Invalidate;
end;
end;
Invalidate;
with Timer do
begin
Enabled:=true;
while Enabled do Application.ProcessMessages;
end;
end;
procedure TMain.MoveDisc;
var I,K:THanoiLevel;
begin
K:=0;
for I:=0 to High(THanoiLevel) do
begin
if Pins[I]=FDest then
begin
Inc(K);
end;
end;
Pins[FLevel]:=FDest;
Levels[FLevel]:=K;
FormResize(nil);
end;
procedure TMain.FormCreate(Sender:TObject);
var I:THanoiLevel;
var P:TPanel;
begin
for I:=0 to High(THanoiLevel) do
begin
P:=TPanel.Create(Self);
P.Parent:=Self;
Panels[I]:=P;
end;
FThread:=nil;
THanoiThread.Create(Self);
Reset;
end;
procedure TMain.Reset;
var I:THanoiLevel;
begin
for I:=0 to High(THanoiLevel) do
begin
Pins[I]:=0;
Levels[I]:=I;
end;
FormResize(nil);
end;
procedure TMain.FormResize(Sender:TObject);
var H,W,Nh,Nw,Sw:Integer;
var I:THanoiLevel;
begin
Nh:=High(THanoiLevel)+1;
Nw:=High(THanoiPin)+1;
H:=(ClientHeight)div(Nh);
W:=((ClientWidth)div(Nw))div(Nh+Nh);
Sw:=(ClientWidth-W*Nw*(Nh+Nh))shr(1);
for I:=0 to High(THanoiLevel) do
begin
with Panels[I] do
begin
Width:=W*(Nh-I)*2;
Height:=H;
Left:=Sw+Pins[I]*W*(Nh+Nh)+W*I;
Top:=Self.ClientHeight-H*(Levels[I]+1);
Repaint;
end;
end;
Sleep(20);
end;
procedure TMain.FormDestroy(Sender:TObject);
begin
if FThread<>nil then FThread.Terminate;
while FThread<>nil do Application.ProcessMessages;
end;
procedure TMain.TimerTimer(Sender:TObject);
begin
Timer.Enabled:=false;
end;
end.