八皇后问题求解动态图形演示

    这是我以前用Delphi写的一个教学软件。内容是关于“八皇后”问题的求解动态图形演示。这个软件采用多线程设计,包含了递归回溯与非递归回溯两种算法,还可随时调整演示速度,界面共有五种前景和五种背景图形。包含所有源程序和资源文件。
    以下是软件截图:

    其中的核心Unit如下: 

  
  
  
  
  1. unit Unit2;  
  2.  
  3. interface  
  4.  
  5. uses  
  6.   Windows, Messages, Classes, SysUtils, StdCtrls, Graphics;  
  7.  
  8. type  
  9.   TQS = function(n: integer): boolean of object;  
  10.   TQueenThread = class(TThread)  
  11.   private  
  12.     FBackgroundBitmap: TBitmap;  
  13.     FQueenIcon, FSeekIcon, FClashIcon: TIcon;  
  14.     FCanvas: TCanvas;  
  15.     FCounter: integer;  
  16.     FQueen: integer;  
  17.     FDemo: boolean;  
  18.     FDelay: integer;  
  19.     FClashRestoreIcon, FSeekQueenIcon: TIcon;  
  20.     FRecursion: boolean;  
  21.     QS: TQS;  
  22.     procedure SeekFinish(Sender: TObject);  
  23.     function QSeek(n: integer): boolean;  
  24.     function QSeekNonrecursion(n: integer): boolean;  
  25.     function QClash(n: integer): boolean;  
  26.     procedure ShowDelete;  
  27.     procedure ShowDraw;  
  28.     procedure ShowClashRestore;  
  29.     procedure SetRecursion(Value: boolean);  
  30.   protected  
  31.     procedure Execute; override;  
  32.   public 
  33.     constructor Create(ABackgroundBitmap: TBitmap; AQueenIcon, ASeekIcon, AClashIcon: TIcon; ACanvas: TCanvas);  
  34.     procedure ShowResult;  
  35.     property Demo: boolean write FDemo;  
  36.     property Delay: integer write FDelay;  
  37.     property Recursion: boolean write SetRecursion;  
  38.   end;  
  39.  
  40. implementation  
  41.  
  42. uses Unit1;  
  43.  
  44. constructor TQueenThread.Create(ABackgroundBitmap: TBitmap; AQueenIcon, ASeekIcon, AClashIcon: TIcon; ACanvas: TCanvas);  
  45. begin 
  46.   FBackgroundBitmap := ABackgroundBitmap;  
  47.   FQueenIcon := AQueenIcon;  
  48.   FSeekIcon := ASeekIcon;  
  49.   FClashIcon := AClashIcon;  
  50.   FCanvas := ACanvas;  
  51.   FCounter := 0;  
  52.   FDemo := true;  
  53.   FDelay := 400;  
  54.   SetRecursion(true);  
  55.   OnTerminate := SeekFinish;  
  56.   inherited Create(true);  
  57. end;  
  58.  
  59. procedure TQueenThread.SetRecursion(Value: boolean);  
  60. begin 
  61.   FRecursion := Value;  
  62.   if FRecursion then 
  63.     QS := QSeek  
  64.   else 
  65.     QS := QSeekNonrecursion;  
  66. end;  
  67.  
  68. procedure TQueenThread.SeekFinish(Sender: TObject);  
  69. begin 
  70.   PostMessage(Form1.Handle, WM_SEEKFINISH, 0, 0);  
  71. end;  
  72.  
  73. procedure TQueenThread.ShowClashRestore;  
  74. var  
  75.   i: integer;  
  76.   t: TRect;  
  77. begin 
  78.   for i := 1 to FQueen - 1 do  
  79.   begin 
  80.     if (Q[FQueen] = Q[i]) or (Abs(Q[FQueen] - Q[i]) = (FQueen - i)) then 
  81.     begin 
  82.       t := Rect((Q[i] - 1) * CellWidth, (i - 1) * CellHeight, Q[i] * CellWidth, i * CellHeight);  
  83.       FCanvas.CopyRect(t, FBackgroundBitmap.Canvas, t);  
  84.       FCanvas.Draw((Q[i] - 1) * CellWidth, (i - 1) * CellHeight, FClashRestoreIcon);  
  85.     end;  
  86.   end;  
  87. end;  
  88.  
  89. procedure TQueenThread.ShowDelete;  
  90. var  
  91.   t: TRect;  
  92. begin 
  93.   t := Rect((Q[FQueen] - 1) * CellWidth, (FQueen - 1) * CellHeight, Q[FQueen] * CellWidth, FQueen * CellHeight);  
  94.   FCanvas.CopyRect(t, FBackgroundBitmap.Canvas, t);  
  95. end;  
  96.  
  97. procedure TQueenThread.ShowDraw;  
  98. begin 
  99.   FCanvas.Draw((Q[FQueen] - 1) * CellWidth, (FQueen - 1) * CellHeight, FSeekQueenIcon);  
  100. end;  
  101.  
  102. procedure TQueenThread.ShowResult;  
  103. var  
  104.   i: integer;  
  105. begin 
  106.   FCanvas.Draw(0, 0, FBackgroundBitmap);  
  107.   FSeekQueenIcon := FQueenIcon;  
  108.   for i := 1 to 8 do  
  109.   begin 
  110.     FQueen := i;  
  111.     ShowDraw;  
  112.   end;  
  113. end;  
  114.  
  115. function TQueenThread.QSeek(n: integer): boolean;  
  116. begin 
  117.   if n > 0 then 
  118.   begin 
  119.     //==========demo begin==========  
  120.     if FDemo then 
  121.     begin 
  122.       FQueen := n; //Setup variable for call synchronize  
  123.       Synchronize(ShowDelete);  
  124.     end;  
  125.     //==========demo end============  
  126.     inc(Q[n]);  
  127.     //==========demo begin==========  
  128.     if FDemo then 
  129.     begin 
  130.       FSeekQueenIcon := FSeekIcon;  
  131.       Synchronize(ShowDraw);  
  132.       sleep(FDelay);  
  133.     end;  
  134.     //==========demo end============  
  135.     if Q[n] <= 8 then 
  136.       if QClash(n) then 
  137.       begin 
  138.         //==========demo begin==========  
  139.         if FDemo then 
  140.         begin 
  141.           FClashRestoreIcon := FClashIcon;  
  142.           Synchronize(ShowClashRestore);  
  143.           sleep(FDelay);  
  144.           FClashRestoreIcon := FQueenIcon;  
  145.           Synchronize(ShowClashRestore);  
  146.         end;  
  147.         //==========demo end============  
  148.         result := QSeek(n);  
  149.       end 
  150.       else 
  151.       begin 
  152.         //==========demo begin==========  
  153.         if FDemo then 
  154.         begin 
  155.           Synchronize(ShowDelete);  
  156.           FSeekQueenIcon := FQueenIcon;  
  157.           Synchronize(ShowDraw);  
  158.           sleep(FDelay);  
  159.         end;  
  160.         //==========demo end============  
  161.         result := true 
  162.       end 
  163.     else 
  164.     begin 
  165.       Q[n] := 0;  
  166.       if QSeek(n - 1) then 
  167.         result := Qseek(n)  
  168.       else 
  169.         result := false;  
  170.     end;  
  171.   end 
  172.   else 
  173.     result := false;  
  174. end;  
  175.  
  176. function TQueenThread.QSeekNonrecursion(n: integer): boolean;  
  177. var  
  178.   flag: boolean;  
  179.   m: integer;  
  180. begin 
  181.   m := n;  
  182.   flag := false;  
  183.   repeat  
  184.     //==========demo begin==========  
  185.     if FDemo then 
  186.     begin 
  187.       FQueen := n;  
  188.       Synchronize(ShowDelete);  
  189.     end;  
  190.     //==========demo end============  
  191.     inc(Q[n]);  
  192.     //==========demo begin==========  
  193.     if FDemo then 
  194.     begin 
  195.       FSeekQueenIcon := FSeekIcon;  
  196.       Synchronize(ShowDraw);  
  197.       sleep(FDelay);  
  198.     end;  
  199.     //==========demo end============  
  200.     if Q[n] > 8 then 
  201.     begin 
  202.       Q[n] := 0;  
  203.       dec(n);  
  204.     end 
  205.     else 
  206.       if not QClash(n) then 
  207.       begin 
  208.         //==========demo begin==========  
  209.         if FDemo then 
  210.         begin 
  211.           Synchronize(ShowDelete);  
  212.           FSeekQueenIcon := FQueenIcon;  
  213.           Synchronize(ShowDraw);  
  214.           sleep(FDelay);  
  215.         end;  
  216.         //==========demo end============  
  217.         if m = n then 
  218.           flag := true 
  219.         else 
  220.           inc(n);  
  221.       end 
  222.       else 
  223.         //==========demo begin==========  
  224.         if FDemo then 
  225.         begin 
  226.           FClashRestoreIcon := FClashIcon;  
  227.           Synchronize(ShowClashRestore);  
  228.           sleep(FDelay);  
  229.           FClashRestoreIcon := FQueenIcon;  
  230.           Synchronize(ShowClashRestore);  
  231.         end;  
  232.         //==========demo end============  
  233.   until flag or (n < 1);  
  234.   result := flag;  
  235. end;  
  236.  
  237. function TQueenThread.QClash(n: integer): boolean;  
  238. var  
  239.   flag: boolean;  
  240.   i: integer;  
  241. begin 
  242.   flag := false;  
  243.   i := 1;  
  244.   while (i < n) and not flag do  
  245.   begin 
  246.     flag := (Q[n] = Q[i]) or (Abs(Q[n] - Q[i]) = (n - i));  
  247.     inc(i);  
  248.   end;  
  249.   result := flag;  
  250. end;  
  251.  
  252. procedure TQueenThread.Execute;  
  253. var  
  254.   i: integer;  
  255. begin 
  256.   for i := 1 to 7 do  
  257.     QS(i);  
  258.   while QS(8) do  
  259.   begin 
  260.     if FDemo then 
  261.       Beep  
  262.     else 
  263.       Synchronize(ShowResult);  
  264.     inc(FCounter);  
  265.     PostMessage(Form1.Handle, WM_SEEKSUSPEND, 0, 0);  
  266.     Suspend;  
  267.   end;  
  268. end;  
  269.  
  270. end

    这个程序虽然是一个教学软件,但涉及到许多方面的知识,比如Win32下的图像处理、多线程等等。这里并没有使用信号量,而是使用了用户自定义消息来完成多线程的同步、等待、挂起等操作。
下面是另一个Unit的源码: 

  
  
  
  
  1. unit Unit1;  
  2.  
  3. interface  
  4.  
  5. uses  
  6.   Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,  
  7.   Dialogs, StdCtrls, ExtCtrls, ImgList, ComCtrls;  
  8.  
  9. const  
  10.   WM_SEEKFINISH = WM_USER + $1;  
  11.   WM_SEEKSUSPEND = WM_USER + $2;  
  12.   CellWidth = 50;  
  13.   CellHeight = 50;  
  14.  
  15. type  
  16.   TForm1 = class(TForm)  
  17.     GroupBox1: TGroupBox;  
  18.     GroupBox2: TGroupBox;  
  19.     GroupBox3: TGroupBox;  
  20.     GroupBox4: TGroupBox;  
  21.     GroupBox5: TGroupBox;  
  22.     GroupBox6: TGroupBox;  
  23.     Panel1: TPanel;  
  24.     Image1: TImage;  
  25.     Label1: TLabel;  
  26.     Label2: TLabel;  
  27.     Label3: TLabel;  
  28.     Label4: TLabel;  
  29.     Label5: TLabel;  
  30.     CheckBox1: TCheckBox;  
  31.     CheckBox2: TCheckBox;  
  32.     TrackBar1: TTrackBar;  
  33.     ComboBox1: TComboBox;  
  34.     ComboBox2: TComboBox;  
  35.     ListBox1: TListBox;  
  36.     Button1: TButton;  
  37.     ImageList1: TImageList;  
  38.     procedure FormCreate(Sender: TObject);  
  39.     procedure FormDestroy(Sender: TObject);  
  40.     procedure Button1Click(Sender: TObject);  
  41.     procedure CheckBox1Click(Sender: TObject);  
  42.     procedure CheckBox2Click(Sender: TObject);  
  43.     procedure TrackBar1Change(Sender: TObject);  
  44.     procedure ComboBox1Change(Sender: TObject);  
  45.     procedure ComboBox2Change(Sender: TObject);  
  46.     procedure ListBox1DblClick(Sender: TObject);  
  47.   private  
  48.     BG: TBitmap;  
  49.     QIcon, SIcon, CIcon: TIcon;  
  50.     QResult: array of array[1..8] of integer;  
  51.     RunFlag: boolean;  
  52.   public 
  53.     procedure MsgSeekSuspend(var Msg: TMessage); message WM_SEEKSUSPEND;  
  54.     procedure MsgSeekFinish(var Msg: TMessage); message WM_SEEKFINISH;  
  55.   end;  
  56.  
  57. var  
  58.   Form1: TForm1;  
  59.   Q: array[1..8] of integer;  
  60.  
  61. implementation  
  62.  
  63. {$R *.dfm}  
  64.  
  65. uses Unit2;  
  66.  
  67. var  
  68.   QueenThread: TQueenThread;  
  69.   CurrentResultIndex: integer;  
  70.  
  71. procedure TForm1.MsgSeekSuspend(var Msg: TMessage);  
  72. var  
  73.   i: integer;  
  74. begin 
  75.   CurrentResultIndex := high(QResult) + 1;  
  76.   setlength(QResult, CurrentResultIndex + 1);  
  77.   for i := 1 to 8 do  
  78.     QResult[CurrentResultIndex, i] := Q[i];  
  79.   with ListBox1 do  
  80.   begin 
  81.     Items.Add(format('%u, %u, %u, %u, %u, %u, %u, %u [%u]', [Q[1], Q[2], Q[3], Q[4], Q[5], Q[6], Q[7], Q[8], CurrentResultIndex + 1]));  
  82.     ItemIndex := Count - 1;  
  83.   end;  
  84.   RunFlag := false;  
  85.   Button1.Caption := '&Seek';  
  86. end;  
  87.  
  88. procedure TForm1.MsgSeekFinish(var Msg: TMessage);  
  89. begin 
  90.   MessageBox(Handle, 'End of seek.'+ #13#10#13#10 + 'Restart seek from first queen.', PWChar(Caption), MB_ICONINFORMATION or MB_OK);  
  91.   ListBox1.Clear;  
  92.   Image1.Canvas.Draw(0, 0, BG);  
  93.   QueenThread := nil;  
  94.   CurrentResultIndex := -1;  
  95.   setlength(QResult, 0);  
  96.   Button1.Caption := '&Seek';  
  97. end;  
  98.  
  99. procedure TForm1.Button1Click(Sender: TObject);  
  100. var  
  101.   i: integer;  
  102. begin 
  103.   if not Assigned(QueenThread) then 
  104.   begin 
  105.     QueenThread := TQueenThread.Create(BG, QIcon, SIcon, CIcon, Image1.Canvas);  
  106.     QueenThread.Demo := CheckBox1.Checked;  
  107.     QueenThread.Delay := TrackBar1.Position;  
  108.     QueenThread.Recursion := CheckBox2.Checked;  
  109.   end;  
  110.   if QueenThread.Suspended then 
  111.   begin 
  112.     with ListBox1 do  
  113.     begin 
  114.       if (CurrentResultIndex <> high(QResult)) and not RunFlag then 
  115.       begin 
  116.         for i := 1 to 8 do  
  117.           Q[i] := QResult[high(QResult), i];  
  118.         QueenThread.ShowResult;  
  119.       end;  
  120.       ItemIndex := Count - 1;  
  121.     end;  
  122.     QueenThread.Resume;  
  123.     Button1.Caption := '&Pause';  
  124.   end 
  125.   else 
  126.   begin 
  127.     QueenThread.Suspend;  
  128.     Button1.Caption := '&Resume';  
  129.   end;  
  130.   RunFlag := true;  
  131. end;  
  132.  
  133. procedure TForm1.CheckBox1Click(Sender: TObject);  
  134. begin 
  135.   TrackBar1.Enabled := CheckBox1.Checked;  
  136.   if Assigned(QueenThread) then 
  137.     QueenThread.Demo := CheckBox1.Checked;  
  138. end;  
  139.  
  140. procedure TForm1.CheckBox2Click(Sender: TObject);  
  141. begin 
  142.   if Assigned(QueenThread) then 
  143.     QueenThread.Recursion := CheckBox2.Checked;  
  144. end;  
  145.  
  146. procedure TForm1.ComboBox1Change(Sender: TObject);  
  147. var  
  148.   n: integer;  
  149. begin 
  150.   n :=  + ComboBox1.ItemIndex * 3;  
  151.   ImageList1.GetIcon(0 + n, QIcon);  
  152.   ImageList1.GetIcon(1 + n, SIcon);  
  153.   ImageList1.GetIcon(2 + n, CIcon);  
  154.   if Assigned(QueenThread) then 
  155.     QueenThread.ShowResult;  
  156. end;  
  157.  
  158. procedure TForm1.ComboBox2Change(Sender: TObject);  
  159. begin 
  160.   BG.LoadFromResourceName(hInstance, 'BG' + IntToStr(ComboBox2.ItemIndex + 1));  
  161.   if Assigned(QueenThread) then 
  162.     QueenThread.ShowResult  
  163.   else 
  164.     Image1.Canvas.Draw(0, 0, BG);  
  165. end;  
  166.  
  167. procedure TForm1.TrackBar1Change(Sender: TObject);  
  168. begin 
  169.   if Assigned(QueenThread) then 
  170.     QueenThread.Delay := TrackBar1.Position;  
  171. end;  
  172.  
  173. procedure TForm1.ListBox1DblClick(Sender: TObject);  
  174. var  
  175.   i: integer;  
  176. begin 
  177.   if Assigned(QueenThread) and not RunFlag then 
  178.   begin 
  179.     CurrentResultIndex := ListBox1.ItemIndex;  
  180.     for i := 1 to 8 do  
  181.       Q[i] := QResult[CurrentResultIndex, i];  
  182.     QueenThread.ShowResult;  
  183.   end;  
  184. end;  
  185.  
  186. procedure TForm1.FormCreate(Sender: TObject);  
  187. var  
  188.   i: integer;  
  189. begin 
  190.   for i := 1 to 8 do  
  191.     Q[i] := 0;  
  192.   BG := TBitmap.Create;  
  193.   QIcon := TIcon.Create;  
  194.   SIcon := TIcon.Create;  
  195.   CIcon := TIcon.Create;  
  196.   ComboBox1Change(self);  
  197.   ComboBox2Change(self);  
  198.   CurrentResultIndex := -1;  
  199. end;  
  200.  
  201. procedure TForm1.FormDestroy(Sender: TObject);  
  202. begin 
  203.   BG.Free;  
  204.   QIcon.Free;  
  205.   SIcon.Free;  
  206.   CIcon.Free;  
  207. end;  
  208.  
  209. end

    可以从后面的附件或者如下链接下载完整的源码项目(包含一个编译好的可执行文件):
http://img1.51cto.com/attachment/201101/876134_1293891480.rar

你可能感兴趣的:(八皇后,休闲,递归回溯算法,八皇后动态图形演示,非递归回溯算法)