Advertisement
SmnVadik

Tower of Hanoi (Delphi)

Aug 19th, 2023 (edited)
419
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Delphi 8.47 KB | None | 0 0
  1. unit untView;
  2.  
  3. interface
  4.  
  5. uses
  6.     Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  7.     Dialogs, untHTypes, ComCtrls;
  8.  
  9. type
  10.     TfrmView = class(TForm)
  11.         tbOperation: TTrackBar;
  12.         procedure FormPaint(Sender: TObject);
  13.         procedure FormCreate(Sender: TObject);
  14.         procedure tbOperationChange(Sender: TObject);
  15.     private
  16.         FTowers: TTowers;
  17.         FAction: TAction;
  18.  
  19.         procedure RestoreDisk(size, actionIndex, actionCount, fromAxe,
  20.           atAxe: Integer);
  21.         procedure RestoreTowers;
  22.     end;
  23.  
  24. var
  25.     frmView: TfrmView;
  26.  
  27. implementation
  28.  
  29. uses Math, GraphUtil;
  30.  
  31. {$R *.dfm}
  32.  
  33. function GetThirdIndex(index1, index2: Integer): Integer;
  34. begin
  35.     Assert(index1 <> index2);
  36.     case index1 of
  37.         0:
  38.             if index2 = 1 then
  39.                 Result := 2
  40.             else
  41.                 Result := 1;
  42.         1:
  43.             if index2 = 2 then
  44.                 Result := 0
  45.             else
  46.                 Result := 2;
  47.         2:
  48.             if index2 = 0 then
  49.                 Result := 1
  50.             else
  51.                 Result := 0;
  52.     else
  53.         Assert(False, 'wrong indeces');
  54.     end;
  55. end;
  56.  
  57. { TfrmView }
  58.  
  59. procedure TfrmView.FormCreate(Sender: TObject);
  60. begin
  61.     tbOperation.Max := 2 shl (MaxRingCount - 1) - 2;
  62.     RestoreTowers;
  63. end;
  64.  
  65. procedure TfrmView.FormPaint(Sender: TObject);
  66.     function GetTowerAreaRect(index: Integer): TRect;
  67.     var
  68.         w: Integer;
  69.     begin
  70.         w := ClientWidth div Length(FTowers);
  71.         Result.Left := w * index;
  72.         Result.Right := w * (index + 1);
  73.         Result.Top := 100;
  74.         Result.Bottom := ClientHeight - 40;
  75.         InflateRect(Result, -20, -20);
  76.     end;
  77.     function GetBaseRect(TowerRect: TRect): TRect;
  78.     begin
  79.         Result := TowerRect;
  80.         Result.Top := Result.Bottom - (TowerRect.Bottom - TowerRect.Top)
  81.           div (MaxRingCount * 2);
  82.     end;
  83.     function GetAxeRect(TowerRect: TRect): TRect;
  84.     var
  85.         w: Integer;
  86.     begin
  87.         w := TowerRect.Right - TowerRect.Left;
  88.         Result := TowerRect;
  89.         Result.Left := (TowerRect.Left + TowerRect.Right) div 2;
  90.         Result.Right := Result.Left;
  91.         InflateRect(Result, Trunc(w * 0.25 * (1) / (MaxRingCount)), 0);
  92.     end;
  93.     function GetRingsRect(TowerRect: TRect): TRect;
  94.     begin
  95.         Result := TowerRect;
  96.         Result.Bottom := Result.Bottom - (TowerRect.Bottom - TowerRect.Top)
  97.           div (MaxRingCount * 2);
  98.     end;
  99.     function GetRingRect(index: Integer; size: Integer; rect: TRect): TRect;
  100.     var
  101.         w, h: Integer;
  102.     begin
  103.         w := rect.Right - rect.Left;
  104.         h := rect.Bottom - rect.Top;
  105.  
  106.         Result.Bottom := Trunc(rect.Bottom - h * index / MaxRingCount);
  107.         Result.Top := Trunc(rect.Bottom - h * (index + 1) / MaxRingCount);
  108.         Result.Left := (rect.Left + rect.Right) div 2;
  109.         Result.Right := Result.Left;
  110.         InflateRect(Result, -2 + Trunc(w * 0.5 * (size + 2) /
  111.           (MaxRingCount + 2)), -1);
  112.     end;
  113.     procedure GetRingColors(size: Integer; var pencolor, brushcolor: TColor);
  114.     var
  115.         hue: DWORD;
  116.     begin
  117.         hue := Trunc(240 * size / MaxRingCount);
  118.         pencolor := ColorHLSToRGB(hue, 160, 240);
  119.         brushcolor := ColorHLSToRGB(hue, 200, 240);
  120.     end;
  121.     procedure MaxRoundRect(rct: TRect);
  122.     var
  123.         h, w: Integer;
  124.     begin
  125.         w := rct.Right - rct.Left;
  126.         h := rct.Bottom - rct.Top;
  127.         Canvas.RoundRect(rct, Min(w, h), Min(w, h));
  128.     end;
  129.  
  130. var
  131.     i, j: Integer;
  132.     towerarea: TRect;
  133.     basearea: TRect;
  134.     ringsarea: TRect;
  135.     ring: TRect;
  136.  
  137.     pcol, bcol: TColor;
  138.  
  139.     curve: array [0 .. 3] of TPoint;
  140. begin
  141.     Canvas.Brush.Color := clWindow;
  142.     Canvas.Brush.Style := bsSolid;
  143.     Canvas.FillRect(Canvas.ClipRect);
  144.  
  145.     Canvas.Pen.Width := 3;
  146.     for j := 0 to Length(FTowers) - 1 do
  147.     begin
  148.         towerarea := GetTowerAreaRect(j);
  149.         basearea := GetBaseRect(towerarea);
  150.         ringsarea := GetRingsRect(towerarea);
  151.  
  152.         Canvas.Pen.Color := clBlack;
  153.         Canvas.Brush.Color := clBlack;
  154.         Canvas.Brush.Style := bsSolid;
  155.         Canvas.Rectangle(basearea);
  156.         MaxRoundRect(GetAxeRect(towerarea));
  157.         for i := 0 to Length(FTowers[j].Rings) - 1 do
  158.         begin
  159.             if FTowers[j].Rings[i] > 0 then
  160.             begin
  161.                 GetRingColors(FTowers[j].Rings[i], pcol, bcol);
  162.                 Canvas.Pen.Color := pcol;
  163.                 Canvas.Brush.Color := bcol;
  164.                 Canvas.Brush.Style := bsSolid;
  165.                 ring := GetRingRect(i, FTowers[j].Rings[i], ringsarea);
  166.                 MaxRoundRect(ring);
  167.             end;
  168.         end;
  169.     end;
  170.  
  171.     if FAction.FromIndex = FAction.AtIndex then
  172.         Exit;
  173.     Canvas.Pen.Color := clRed;
  174.  
  175.     towerarea := GetTowerAreaRect(FAction.FromIndex);
  176.     curve[0] := Point((towerarea.Left + towerarea.Right) div 2,
  177.       towerarea.Top - 20);
  178.     curve[1] := Point((towerarea.Left + towerarea.Right) div 2, 0);
  179.     towerarea := GetTowerAreaRect(FAction.AtIndex);
  180.     curve[2] := Point((towerarea.Left + towerarea.Right) div 2, 0);
  181.     curve[3] := Point((towerarea.Left + towerarea.Right) div 2,
  182.       towerarea.Top - 20);
  183.     Canvas.PolyBezier(curve);
  184.     Canvas.MoveTo(curve[3].X, curve[3].Y);
  185.     Canvas.LineTo(curve[3].X + 15, curve[3].Y - 15);
  186.     Canvas.MoveTo(curve[3].X, curve[3].Y);
  187.     Canvas.LineTo(curve[3].X - 15, curve[3].Y - 15);
  188. end;
  189.  
  190. procedure TfrmView.RestoreDisk(size, actionIndex, actionCount, fromAxe,
  191.   atAxe: Integer);
  192. var
  193.     pivot: Integer;
  194.     i: Integer;
  195.     thirdAxe: Integer;
  196. begin
  197.     pivot := actionCount div 2;
  198.     thirdAxe := GetThirdIndex(fromAxe, atAxe);
  199.  
  200.     if actionIndex = pivot then
  201.  
  202.     begin
  203.         FTowers[fromAxe].PutRing(size);
  204.         for i := size - 1 downto 1 do
  205.             FTowers[thirdAxe].PutRing(i);
  206.         FAction.FromIndex := fromAxe;
  207.         FAction.AtIndex := atAxe;
  208.     end
  209.     else if actionIndex < pivot then
  210.     begin
  211.         FTowers[fromAxe].PutRing(size);
  212.         RestoreDisk(size - 1, actionIndex, actionCount - pivot - 1, fromAxe,
  213.           thirdAxe);
  214.     end
  215.     else
  216.     begin
  217.         FTowers[atAxe].PutRing(size);
  218.         RestoreDisk(size - 1, actionIndex - pivot - 1, actionCount - pivot - 1,
  219.           thirdAxe, atAxe);
  220.     end;
  221. end;
  222.  
  223. procedure TfrmView.RestoreTowers;
  224. var
  225.     index: Integer;
  226. begin
  227.     ClearTowers(FTowers);
  228.     index := tbOperation.Position;
  229.     RestoreDisk(MaxRingCount, index, 2 shl (MaxRingCount - 1) - 1, 0, 1);
  230.     Invalidate;
  231. end;
  232.  
  233. procedure TfrmView.tbOperationChange(Sender: TObject);
  234. begin
  235.     RestoreTowers;
  236. end;
  237.  
  238. end.
  239.  
  240.  
  241. unit untHTypes;
  242.  
  243. interface
  244.  
  245. const
  246.     MaxRingCount = 8;
  247.  
  248. type
  249.     TTower = record
  250.         RingCount: Integer;
  251.         Rings: array [0 .. MaxRingCount - 1] of Integer;
  252.         procedure MoveRing(var AtTower: TTower);
  253.         procedure PutRing(size: Integer);
  254.     end;
  255.  
  256.     TTowers = array [0 .. 2] of TTower;
  257.  
  258.     TAction = record
  259.         FromIndex: Integer;
  260.         AtIndex: Integer;
  261.     end;
  262.  
  263. procedure InitTowers(var towers: TTowers);
  264. procedure ClearTowers(var towers: TTowers);
  265.  
  266. implementation
  267.  
  268. procedure InitTowers(var towers: TTowers);
  269. var
  270.     i: Integer;
  271. begin
  272.     towers[0].RingCount := MaxRingCount;
  273.     towers[1].RingCount := 0;
  274.     towers[2].RingCount := 0;
  275.     for i := 0 to MaxRingCount - 1 do
  276.     begin
  277.         towers[0].Rings[i] := MaxRingCount - i;
  278.         towers[1].Rings[i] := 0;
  279.         towers[2].Rings[i] := 0;
  280.     end;
  281. end;
  282.  
  283. procedure ClearTowers(var towers: TTowers);
  284. var
  285.     i: Integer;
  286. begin
  287.     towers[0].RingCount := 0;
  288.     towers[1].RingCount := 0;
  289.     towers[2].RingCount := 0;
  290.     for i := 0 to MaxRingCount - 1 do
  291.     begin
  292.         towers[0].Rings[i] := 0;
  293.         towers[1].Rings[i] := 0;
  294.         towers[2].Rings[i] := 0;
  295.     end;
  296. end;
  297.  
  298. { TTower }
  299.  
  300. procedure TTower.MoveRing(var AtTower: TTower);
  301. begin
  302.     Assert(RingCount > 0);
  303.     Assert(AtTower.RingCount - 1 < MaxRingCount);
  304.     if AtTower.RingCount > 0 then
  305.         Assert(Rings[RingCount - 1] < AtTower.Rings[AtTower.RingCount - 1]);
  306.  
  307.     Dec(RingCount);
  308.     AtTower.Rings[AtTower.RingCount] := Rings[RingCount];
  309.     Rings[RingCount] := 0;
  310.     Inc(AtTower.RingCount);
  311. end;
  312.  
  313. procedure TTower.PutRing(size: Integer);
  314. begin
  315.     Assert(RingCount - 1 < MaxRingCount);
  316.     if RingCount > 0 then
  317.         Assert(size < Rings[RingCount - 1]);
  318.  
  319.     Rings[RingCount] := size;
  320.     Inc(RingCount);
  321. end;
  322.  
  323. end.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement