A*算法实践录1

        接触A*其实就是这个礼拜, 以前基本不知道.但是深度优先和广度优先还是知道一点点.其实以前在数据结构中就学过,只是没学明白 也没有机会应用和再学习,就淡忘了. 这是比较悲哀的事. 然而我现在有机会重新学习他们了.

       对于这些理论的描述似乎已经没有意义. 因为网络上随处一搜都有很经典权威的诠释. 我只是想写下我接触A*的全过程, 以便我以后的学习. 作为我学习的积累,也希望能得到通道中朋友的指正,或者能给需要帮助的人一些启示.

  好的.马上贴代码..

时间过得好快.  ....  写出来的代码, 还是最基本的东西..   贴出来.    
 
有时间了再写心得.总结.

unit main;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, Buttons, Grids, ExtCtrls, Menus;

type
  {节点定义   vG 代表某节点的G值, vH 代表某节点的H值。 A×中的F值通过vG+ vH 获得}
  PGridNode = ^TGridNode;
  TGridNode = record
    Col: Integer;
    Row: Integer;
    vG : Integer;         {vG 值 是节点到起始节点的距离}
    vH : Integer;         {vH 值 是节点到终结节点的距离}
    Parent: PGridNode;
  end;

  TForm1 = class(TForm)
    DrawGrid1: TDrawGrid;
    Panel1: TPanel;
    Panel2: TPanel;
    BitBtn1: TBitBtn;
    RadioGroup1: TRadioGroup;
    Button1: TButton;
    Panel3: TPanel;
    Memo1: TMemo;
    Button2: TButton;
    procedure DrawGrid1SelectCell(Sender: TObject; ACol, ARow: Integer;
      var CanSelect: Boolean);
    procedure BitBtn1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure Button1Click(Sender: TObject);
    procedure DrawGrid1DrawCell(Sender: TObject; ACol, ARow: Integer;
      Rect: TRect; State: TGridDrawState);
    procedure Button2Click(Sender: TObject);
  private
    FDes, FSrc: PGridNode;                    {FDes是目标节点, 代表终点; FSrc是起始节点,代表起点。}
    function GetMaxCol: integer;
    function GetMaxRow: integer;
    function GetptDes: PGridNode;
    function GetptSrc: PGridNode;
    procedure SetptDes(const Value: PGridNode);
    procedure SetptSrc(const Value: PGridNode);
    function IsExist(FList: TList; vNode: PGridNode): Boolean; overload;
    function IsExist(FList: TList; Col, Row: Integer): Boolean; overload;
    function IsExist(FList: TList; Col, Row: Integer; var pt: PGridNode): Boolean; overload;
    { Private declarations }
  public
    { Public declarations }
    Gred: array[0..9] of array[0..9] of Byte;  {0: 空; 1: 障碍物; 2: 起点; 3: 目标}
    pt: array of TPoint;
    OpenList, CloseList: TList;                {开启列表和关闭列表, 负责可搜索和已搜索节点}
    Found : Boolean;
    function Go(cDes,rDes,cSrc,rSrc: integer): Boolean;

    function FindWithA: Boolean;
    function GetMinF: PGridNode;
    //function GetMinG:
    procedure AddOpenList(pt: PGridNode);
    procedure AddCloseList(pt: PGridNode);
    function NextIsTrue(pt: PGridNode): Boolean;
    procedure AddRoundToOpenList(pt: PGridNode);
    procedure SetCountG(var Node: PGridNode);
    procedure SetCountH(var Node: PGridNode);
    procedure ClearList(var List: TList);
    property ptDes: PGridNode read GetptDes write SetptDes;
    property ptSrc: PGridNode read GetptSrc write SetptSrc;     {以属性的形式 向外部提供起始和终结节点}
    property MaxCol: Integer read GetMaxCol;
    property MaxRow: Integer read GetMaxRow;
  end;

var
  Form1: TForm1;

implementation

uses StdConvs;

{$R *.dfm}

procedure TForm1.DrawGrid1SelectCell(Sender: TObject; ACol, ARow: Integer;
  var CanSelect: Boolean);
begin
  CanSelect := False;
  if Gred[ACol, ARow] > 0 then exit;
  if RadioGroup1.ItemIndex = 0 then
  begin
    DrawGrid1.Canvas.Brush.Color := clRed;
    Gred[acol, arow] := 1;
  end
  else
  begin
    if Assigned(FSrc) and Assigned(FDes) then exit;
    if not Assigned(FSrc) then
    begin          
      Gred[acol,arow] := 2;
      New(FSrc);
      FSrc.Col := ACol;
      FSrc.Row := ARow;
      FSrc.vG := 0;
     // SetCountH(FSrc);
      FSrc.vH := 100;
      FSrc.Parent := nil;
    end
    else //if not Assigned(FDes) then
    begin       
      Gred[ACol, ARow] := 3;
      New(FDes);
      FDes.Col := ACol;
      FDes.Row := ARow;
      FDes.vH := 0;
      //SetCountG(FDes);
    end;
  //  else exit;
    DrawGrid1.Canvas.Brush.Color := clGreen;
  end;
  DrawGrid1.Canvas.Ellipse(DrawGrid1.CellRect(acol, arow));
 // Caption := 'col: ' + IntToStr(ACol) + '   row: ' + IntToStr(ARow);
end;

procedure TForm1.BitBtn1Click(Sender: TObject);
var
  i,j: integer;
begin
  DrawGrid1.Repaint;
  for i := 0 to 9 do
    for j := 0 to 9 do
      Gred[i, j] := 0;

  {Dispose(FDes);
  Dispose(FSrc);}
  if Assigned(FDes) then
  begin
    if OpenList.IndexOf(FDes) > -1 then
      OpenList.Remove(FDes);
    if CloseList.IndexOf(FDes) > -1 then
      CloseList.Remove(FDes);
  end;
  if Assigned(FSrc) then
  begin
    if OpenList.IndexOf(FSrc) > -1 then
      OpenList.Remove(FSrc);
    if CloseList.IndexOf(FSrc) > -1 then
      CloseList.Remove(FSrc);
  end;
  ClearList(OpenList);
  ClearList(CloseList);
  { }
 // SetLength(pt, 0);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  BitBtn1Click(nil);
  OpenList := TList.Create;
  CloseList := TList.Create;
end;

function TForm1.Go(cDes,rDes,cSrc,rSrc: integer): Boolean;
begin
  Result := False;
  Result := True;
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  ClearList(OpenList);
  OpenList.Free;
  ClearList(CloseList);
  CloseList.Free;
end;

procedure TForm1.AddOpenList(pt: PGridNode);
begin
  OpenList.Add(pt);
end;

procedure TForm1.AddCloseList(pt: PGridNode);
begin
  try
    CloseList.Add(pt);
    OpenList.Remove(pt);
  except
    RaiseLastWin32Error;
  end;
end;

procedure TForm1.AddRoundToOpenList(pt: PGridNode);
  procedure AddIn(vCol, vRow: Integer);
  var
    NewPt: PGridNode;
  begin
    if IsExist(CloseList, vCol, vRow) or (Gred[vCol, vRow] = 1) then   {如果该节点是障碍物或者该节点已经存在于关闭列表中则跳过}
      Exit;
    if IsExist(OpenList, vCol, vRow, NewPt) then                       {如果该节点已经存在于开启列表}
    begin
      if NewPt.vG + NewPt.vH < pt.vG + pt.vH then                                         {比较G值,较小的话作为父节点,并重新计算G,H}
      begin
        NewPt.Parent := pt;
        SetCountG(NewPt);
        SetCountH(NewPt);
      end;
    end
    else begin                                                         {否则创建该新节点,添加到开启列表。}
      New(NewPt);
      Newpt.Col := vCol;
      Newpt.Row := vRow;
      NewPt.Parent := pt;
      SetCountG(NewPt);
      SetCountH(NewPt);
      if NewPt.vH = 0 then
      begin
        Dispose(NewPt);
        NewPt := ptDes;
        NewPt.Parent := pt;
        Found := True;
      end;
      OpenList.Add(NewPt);
    end;
  end;
begin
  if (pt.Col - 1 >= 0) then        {左节点}
    AddIn(pt.Col - 1, pt.Row);
  if (pt.Col + 1 < MaxCol) then   {右节点}
    AddIn(pt.Col + 1, pt.Row);
  if (pt.Row - 1 >= 0) then        {上节点}
    AddIn(pt.Col, pt.Row - 1);
  if (pt.Row + 1 < MaxRow) then   {下节点}
    AddIn(pt.Col, pt.Row + 1);
end;

function TForm1.GetMaxCol: integer;
begin
  Result := DrawGrid1.ColCount;
end;

function TForm1.GetMaxRow: integer;
begin
  Result := DrawGrid1.RowCount;
end;
{}
procedure TForm1.SetCountG(var Node: PGridNode);
begin
  if Node.Parent <> nil then
    Node.vG := Node.Parent.vG + 1
  else Node.vG := 0;
end;

function TForm1.GetptDes: PGridNode;
begin
  Result := FDes;
end;

function TForm1.GetptSrc: PGridNode;
begin
  Result := FSrc;
end;

procedure TForm1.SetptDes(const Value: PGridNode);
begin
  FDes := Value;
end;

procedure TForm1.SetptSrc(const Value: PGridNode);
begin
  FSrc := Value;
end;

procedure TForm1.SetCountH(var Node: PGridNode);
begin
  Node.vH := Abs(Node.Col - ptDes.Col) + abs(Node.Row - ptDes.Row);
end;

function TForm1.FindWithA: Boolean;
var
  CurNode: PGridNode;
 // iCount : Integer;
begin
  Result := False;
  AddOpenList(ptSrc);
  CurNode := ptSrc;
  while (not Found) and (OpenList.Count <> 0) do
  begin
    CurNode := GetMinF;
    AddCloseList(CurNode);
    AddRoundToOpenList(CurNode);
  end;

  if OpenList.Count = 0 then
    Exit
  else begin
    CurNode := ptDes;
    Memo1.Lines.Add('-------搜索路径如下:-------');
    Memo1.Lines.Add('Row: ' + IntToStr(CurNode^.Row)
                + '  Col: ' + IntToStr(CurNode^.Col));
    DrawGrid1.Canvas.Pen.Color := cl3DDkShadow;
    DrawGrid1.Canvas.Pen.Width := 3;
    DrawGrid1.Canvas.MoveTo(CurNode^.Col * 24 + 15, CurNode^.Row * 24 + 15 );
    while (CurNode.Parent <> ptSrc) do
    begin
      CurNode := CurNode.Parent;
      DrawGrid1.Canvas.LineTo(CurNode^.Col * 24 + 15, CurNode^.Row * 24 + 15 );
      Memo1.Lines.Add('Row: ' + IntToStr(CurNode^.Row)
                  + '  Col: ' + IntToStr(CurNode^.Col));
    end;
    DrawGrid1.Canvas.LineTo(ptSrc^.Col * 24 + 15, ptSrc^.Row * 24 + 15 );
    Found := False;
  end;   {}
  Result := True;
end;

function TForm1.IsExist(FList: TList; vNode: PGridNode): Boolean;
var
  i:Integer;
begin
  Result := False;
  for i := 0 to FList.Count - 1 do
    if (PGridNode(FList.Items[i]).Col = vNode.Col)
        and (PGridNode(FList.Items[i]).Row = vNode.Row) then
      Result := True;
end;

function TForm1.IsExist(FList: TList; Col, Row: Integer): Boolean;
var
  i:Integer;
begin
  Result := False;
  for i := 0 to FList.Count - 1 do
    if (PGridNode(FList.Items[i])^.Col = Col)
        and (PGridNode(FList.Items[i])^.Row = Row) then
      Result := True;
end;

function TForm1.GetMinF: PGridNode;
var
  i: Integer;
begin
  try
    Result := OpenList.Items[0];
    for i := 1 to OpenList.Count - 1 do
      if (Result.vG + Result.vH) > (PGridNode(OpenList.Items[i]).vG + PGridNode(OpenList.Items[i]).vH) then
      Result := OpenList.Items[i];
  except
    raise Exception.Create('No OpenList');
  end;
end;

function TForm1.NextIsTrue(pt: PGridNode): Boolean;
begin
  Result := False;
  if pt.vH = 1 then
    Result := True;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  if not FindWithA then
    MessageDlg('无法到达目标', mtInformation, [mbOK], 0);
end;

function TForm1.IsExist(FList: TList; Col, Row: Integer;
  var pt: PGridNode): Boolean;
var
  i:Integer;
begin
  Result := False;
  for i := 0 to FList.Count - 1 do
    if (PGridNode(FList.Items[i])^.Col = Col)
        and (PGridNode(FList.Items[i])^.Row = Row) then
    begin
      pt := PGridNode(FList.Items[i]);
      Result := True;
    end;
end;

procedure TForm1.DrawGrid1DrawCell(Sender: TObject; ACol, ARow: Integer;
  Rect: TRect; State: TGridDrawState);
begin
  if Gred[ACol, ARow] = 1 then
  Begin
    DrawGrid1.Canvas.Brush.Color := clRed;
    DrawGrid1.Canvas.Ellipse(DrawGrid1.CellRect(ACol, ARow));
  end
  else if (Gred[ACol, ARow] = 2) or (Gred[ACol, ARow] = 3) then
  begin
    DrawGrid1.Canvas.Brush.Color := clGreen;
    DrawGrid1.Canvas.Ellipse(DrawGrid1.CellRect(ACol, ARow));
  end;
  //DrawGrid1.Canvas.TextOut(Acol*24 +2, ARow*24+2, IntToStr(ACol) +', ' + IntToStr(ARow));
end;

procedure TForm1.ClearList(var List: TList);
var
  i: Integer;
  Pt: PGridNode;
begin
  if Assigned(List) then
  for i := list.Count - 1 downto 0 do
  begin
    Pt := PGridNode(List.Items[i]);
    List.Delete(i);
    Dispose(Pt);
  end;
end;

procedure TForm1.Button2Click(Sender: TObject);
var
  iCount: Integer;
begin
  Memo1.Lines.Clear;
  for iCount := 0 to OpenList.Count - 1 do
    Memo1.Lines.Add('Row: ' + IntToStr(PGridNode(OpenList.Items[iCount])^.Row)
                + '  Col: ' + IntToStr(PGridNode(OpenList.Items[iCount])^.Col));
end;

end.

posted @ 2005-07-29 13:59  JustLive  阅读(473)  评论(0编辑  收藏  举报