// Ханойские башни
uses GraphABC;

type
  /// Тип диска
  DiskType = record
    /// Диаметр диска
    Sz: integer;
    /// Цвет диска
    Color: GraphABC.Color;
  end;
  /// Тип массива дисков на стержне
  DiskArr = array of DiskType;

const
  /// Количество дисков
  CountDisks = 8;
  /// Высота диска
  DiskHeight = 12;
  /// Приращение ширины диска
  DiskWidthDelta = 12;
  h = CountDisks * DiskWidthDelta * 2 + 20; 
  /// y-координата основания пирамид дисков
  y0 = DiskHeight * CountDisks + 80;
  hh = 30;
  /// x-координата первого стержня
  x1 = h div 2 + hh;
  /// x-координата второго стержня
  x2 = x1 + h;
  /// x-координата третьего стержня
  x3 = x2 + h;
  /// Пауза, мс
  delay = 50;

var
  /// Массив пирамид дисков 
  Tower: array [1..3] of DiskArr;
  /// Массив количеств дисков в пирамидах
  DisksInTower: array [1..3] of integer;
  /// Номер хода
  MoveNumber: integer;

/// Рисование пирамиды
procedure DrawTower(a: DiskArr; n: integer; x0,y0: integer);
begin
  Brush.Color := clBlack;
  Rectangle(x0-5,y0,x0+5,y0-DiskHeight*CountDisks-10);
  for var i:=0 to n-1 do
  begin
    Brush.Color := a[i].Color;
    Rectangle(x0-a[i].sz*DiskWidthDelta,y0-DiskHeight*(i-1),x0+a[i].sz*DiskWidthDelta,y0-DiskHeight*i+1)
  end;
end;

/// Рисование всех пирамид и информационной строки
procedure DrawAll;
begin
  DrawTower(Tower[1],DisksInTower[1],x1,y0);
  DrawTower(Tower[2],DisksInTower[2],x2,y0);
  DrawTower(Tower[3],DisksInTower[3],x3,y0);
  Brush.Color := clWhite;
  TextOut(20,20,'Число перемещений дисков = '+MoveNumber);
  Redraw;
end;

/// Перемещение диска со стержня FromN на стержень ToN
procedure MoveDisk(FromN, ToN: integer);
begin
  Inc(MoveNumber);
  Inc(DisksInTower[ToN]);
  Tower[ToN][DisksInTower[ToN]-1] := Tower[FromN][DisksInTower[FromN]-1];
  Dec(DisksInTower[FromN]);
  Sleep(delay);
  ClearWindow;
  DrawAll;
end;

/// Основная екурсивная процедура алгоритма "Ханойские башни"
procedure MoveTower(n: integer; FromN, ToN, WorkN: integer);
begin
  if n=0 then exit;
  MoveTower(n-1, FromN, WorkN, ToN);
  MoveDisk(FromN, ToN);
  MoveTower(n-1, WorkN, ToN, FromN);
end;

/// Инициализация массивов
procedure InitTowers;
begin
  SetLength(Tower[1],CountDisks);
  SetLength(Tower[2],CountDisks);
  SetLength(Tower[3],CountDisks);
  DisksInTower[1] := CountDisks;
  DisksInTower[2] := 0;
  DisksInTower[3] := 0;
  for var i:=0 to DisksInTower[1]-1 do
  begin
    Tower[1][i].Sz := DisksInTower[1]-i+1;
    Tower[1][i].Color := clRandom;
  end;
end;

/// Инициализация окна
procedure InitWindow;
begin
  SetWindowSize(x3+x1,y0+50);
  CenterWindow;
  Window.Title := 'Ханойские башни';
  Font.Size := 14;
  Font.Name := 'Arial';
end;

begin
  InitWindow;
  InitTowers;
  LockDrawing;
  DrawAll;
  MoveTower(CountDisks,1,3,2);
end.


