发个A*寻径算法....
时间:2011-10-19
来源:互联网
刚刚看到有位同学找类似的算法,就把它发出来,很久以前写的....
Delphi(Pascal) code
unit Formmain; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, Grids,XPMan; type //运动方向定义 TComPassirection = (cdNorth,cdNorthEast,cdEast,cdSouthEast,cdSouth,cdSouthWest,cdWest,cdNorthWest); //北, 东北 东 东南 南 西南 西 西北 // (北) // | // | // (西)---------|------------- (东) // | // | // | // (南) //为某个方向上定义相对于当前点的偏移量 TDirectionOffset = array[TComPassirection] of TPoint; //记录经过的点 TNode = record Direction : TComPassirection; GridPt : TPoint; end; PNode = ^TNode; type TfrmMain = class(TForm) strngrdGridPath: TStringGrid; btnClearMap: TButton; btnFindPath: TButton; btnSetStart: TButton; lbl1: TLabel; procedure btnClearMapClick(Sender: TObject); procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure strngrdGridPathMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure strngrdGridPathDrawCell(Sender: TObject; ACol, ARow: Integer; Rect: TRect; State: TGridDrawState); procedure btnFindPathClick(Sender: TObject); procedure btnSetStartClick(Sender: TObject); private { Private declarations } public { Public declarations } procedure ClearPathQueue; end; var frmMain: TfrmMain; StartPt,Endpt : TPoint; //起始点和终点 SetStart : Boolean; //开始移动 PathQueue : TList; //路径节点记录 MapGrid : array[0..20,0..30] of Byte ; //地图坐标 0 表示可访问, 1 表示为障碍物 VistedNotes : array[0..20,0..30] of Boolean; //记录哪些节点已经被访问过 const DirectionOffset : TDirectionOffset = ( //为某个方向上定义相对于当前点的实际偏移量 (X : 0; y : -1),(X : 1; y : -1),(X : 1; y : 0), (X : 1; y : 1),(X : 0; y : 1),(X : -1; y : 1), (X : -1; y : 0),(X : -1; y : -1)); //定义每种节点类型 NODECLEAR = ''; NODEOBSTACLE = '1'; NODESTART = '2'; NODEEND = '3'; NODEPATH = '4'; NODEVISITED = '5'; implementation {$R *.dfm} procedure TfrmMain.btnClearMapClick(Sender: TObject); var i , j : Integer; begin for i := 0 to 20 do begin for j := 0 to 30 do strngrdGridPath.Cells[i,j] := ''; end; end; procedure TfrmMain.FormCreate(Sender: TObject); begin StartPt := Point(-1,-1); Endpt := Point(-1,-1); //默认情况下用鼠标左键设置起点 SetStart := True; PathQueue := TList.Create; end; procedure TfrmMain.FormDestroy(Sender: TObject); begin ClearPathQueue; PathQueue.Free; end; procedure TfrmMain.strngrdGridPathMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); var aRow,aCol : Integer; begin strngrdGridPath.MouseToCell(x,y,aCol,aRow); if Button = mbright then begin //设置或清除障碍点 if strngrdGridPath.Cells[aCol,aRow] = NODEOBSTACLE then strngrdGridPath.Cells[aCol,aRow] := NODECLEAR else strngrdGridPath.Cells[aCol,aRow] := NODEOBSTACLE; end else //设置起始和结束点 if SetStart then begin //如果用户再次设置起始点,则清除原来的起点 if StartPt.X <> - 1 then strngrdGridPath.Cells[StartPt.X,StartPt.Y] := NODECLEAR; //设置新起点 strngrdGridPath.Cells[aCol,aRow] := NODESTART; StartPt := Point(aCol,aRow); end else begin //如果用户再次设置终点,则清除原来的终点 if Endpt.X <> - 1 then strngrdGridPath.Cells[Endpt.X,Endpt.Y] := NODECLEAR; //设置新终点 strngrdGridPath.Cells[aCol,aRow] := NODEEND; Endpt := Point(aCol,aRow); end; end; procedure TfrmMain.strngrdGridPathDrawCell(Sender: TObject; ACol, ARow: Integer; Rect: TRect; State: TGridDrawState); begin with strngrdGridPath do begin Canvas.Brush.Color := clWhite; //根据方格类型决定其颜色 if Cells[ACol,ARow] = NODEOBSTACLE then Canvas.Brush.Color := clBlack; if Cells[ACol,ARow] = NODESTART then Canvas.Brush.Color := clBlue; if Cells[ACol,ARow] = NODEEND then Canvas.Brush.Color := clRed; if Cells[ACol,ARow] = NODEPATH then Canvas.Brush.Color := clPurple; if Cells[ACol,ARow] = NODEVISITED then Canvas.Brush.Color := clGreen; Canvas.FillRect(Rect); end; end; procedure TfrmMain.ClearPathQueue; var aCount : Integer; begin for aCount := 0 to PathQueue.Count - 1 do begin FreeMem(PathQueue[aCount],SizeOf(TNode)); end; PathQueue.Clear; end; //A*寻径搜索算法原理: // 判断本身与目标之间的方向,先选择一个方向,然后移动到该方向上的下一个点,同时计算该点不同方向上的下一个点离终点的距离, //移动到最近的一个点上,若下一个点是障碍,则回退到该点,再次检查并将刚刚的点视为障碍物 procedure TfrmMain.btnFindPathClick(Sender: TObject); var iCount,iCount2 : Integer; Curpt,EvalPt,NewPt : TPoint; TempNode : PNode; Dist,EvalDist : DWORD; Dir,NewDir : TComPassirection; SearchDirs : array[0..2] of TComPassirection; begin if (StartPt.X = -1) or (Endpt.X = -1) then Exit; //清除已经访问节点的数组 FillChar(VistedNotes,SizeOf(VistedNotes),0); //设置障碍 for iCount := 0 to 20 do begin for iCount2 := 0 to 30 do begin if strngrdGridPath.Cells[iCount,iCount2] = NODEOBSTACLE then MapGrid[iCount,iCount2] := 1 else MapGrid[iCount,iCount2] := 0; end; end; //删除当前路径 ClearPathQueue; //初始化跟踪变量 Curpt := StartPt; VistedNotes[Curpt.X,Curpt.Y] := True; //决定起始方向 终点在起始方向左边 if Endpt.X < StartPt.X then begin if Endpt.Y > StartPt.Y then //西南 Dir := cdSouthWest else if Endpt.Y < StartPt.Y then //西北 Dir := cdNorthWest else dir := cdWest; //西边 end else if Endpt.X > StartPt.X then begin if Endpt.Y > StartPt.Y then //东南 Dir := cdSouthEast else if Endpt.Y < StartPt.Y then Dir := cdNorthEast //东北 else Dir := cdEast; //西 end else //正上方或正下方 if Endpt.Y > StartPt.Y then Dir := cdSouth //北 else if Endpt.Y < StartPt.Y then Dir := cdNorth; //南 GetMem(TempNode,SizeOf(TNode)); //用当前节点的信息初始化节点对象 TempNode^.Direction := Dir; TempNode^.GridPt.X := Curpt.X; TempNode^.GridPt.Y := Curpt.Y; //将该节点添加到路径中 PathQueue.Add(TempNode); //开始搜索路径,直到找到为止 while(Curpt.X <> Endpt.X) or (Curpt.Y <> Endpt.Y) do begin //重置新坐标,表明未找到 NewPt := Point(-1,-1); //将距离设为可能的最大值 Dist := $FFFFFFFF; //确定3个搜索方向 SearchDirs[0] := Pred(Dir); if Ord(SearchDirs[0]) < Ord(cdNorth) then SearchDirs[0] := cdNorthWest; SearchDirs[1] := Dir; SearchDirs[2] := Succ(Dir); if Ord(SearchDirs[2]) > Ord(cdNorthWest) then SearchDirs[2] := cdNorth; //估计3个方向上的网格位置 for iCount := 0 to 2 do begin //根据当前面对的方向,获取相对于当前节点的下一个即将要检查的点的坐标 EvalPt.X := Curpt.X + DirectionOffset[SearchDirs[iCount]].X; EvalPt.Y := Curpt.Y + DirectionOffset[SearchDirs[iCount]].Y; //确保该节点在地图范围内 if (EvalPt.X > - 1) and (EvalPt.X < 20) and (EvalPt.Y > -1) and (EvalPt.Y < 30) then begin //该节点没有被访问过 if not VistedNotes[EvalPt.X,EvalPt.Y] then begin //该节点不是障碍 if MapGrid[EvalPt.X,EvalPt.Y] = 0 then begin EvalDist := (Endpt.X - EvalPt.X) * (Endpt.X - EvalPt.X) + (Endpt.Y - EvalPt.Y) * (Endpt.Y - EvalPt.Y); //如果发现某个节点的距离更近,则将该节点置为当前节点 if EvalDist < Dist then begin //记录新的节点和距离 Dist := EvalDist; NewPt := EvalPt; NewDir := SearchDirs[icount]; end; end; end; end; end; //此时如果newpt仍是(-1,-1) 则说明遇到障碍物,故要回退一步重新查找,否则将该点添加到路径中 if NewPt.X <> - 1 then begin //将该节点设为新节点 Curpt := NewPt; //将该节点的方向设为新节点的方向 Dir := NewDir; //设置节点为已经访问 VistedNotes[Curpt.X,Curpt.Y] := True; //创建一个节点对象 GetMem(TempNode,SizeOf(TNode)); //用新的节点信息初始化节点 TempNode^.Direction := Dir; TempNode^.GridPt.X := Curpt.X; TempNode^.GridPt.Y := Curpt.Y; //保存路径 PathQueue.Add(TempNode); if PathQueue.Count > 100 then Break; end else //已经退回到不可退回的节点,表明该方向无法找到路径,改善算法,重新计算起始方向并再次搜索路径,直到搜索完所有可能的方向 begin if PathQueue.Count = 1 then Break; //设置为上一节点的方向 (回退) dir := TNode(PathQueue[PathQueue.Count - 2]^).Direction; //检索上一节点的坐标,并将其置为当前节点 Curpt := TNode(PathQueue[PathQueue.Count - 2]^).GridPt; // MapGrid[TNode(PathQueue[PathQueue.Count - 2]^).GridPt.X,TNode(PathQueue[PathQueue.Count - 2]^).GridPt.Y] := 1; //释放并清除列表中最后一个节点 FreeMem(PathQueue[PathQueue.Count - 1],SizeOf(TNode)); PathQueue.Delete(PathQueue.Count - 1); end; //指定路径上的节点 for iCount := 0 to PathQueue.Count - 1 do begin strngrdGridPath.Cells[TNode(PathQueue[iCount]^).GridPt.X,TNode(PathQueue[iCount]^).GridPt.Y] := NODEPATH; end; strngrdGridPath.Cells[StartPt.X,StartPt.Y] := NODESTART; strngrdGridPath.Cells[Endpt.X,Endpt.Y] := NODEEND; end; end; procedure TfrmMain.btnSetStartClick(Sender: TObject); begin SetStart := not SetStart; if SetStart then btnSetStart.Caption := '设置起点' else btnSetStart.Caption := '设置终点'; end; end.
作者: mdejtod 发布时间: 2011-10-19
窗体文件:
object frmMain: TfrmMain
Left = 312
Top = 144
BorderStyle = bsDialog
Caption = 'A*'#26368#30701#36335#24452#23547#24452#31639#27861
ClientHeight = 651
ClientWidth = 952
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'MS Sans Serif'
Font.Style = []
OldCreateOrder = False
OnCreate = FormCreate
OnDestroy = FormDestroy
PixelsPerInch = 96
TextHeight = 13
object lbl1: TLabel
Left = 392
Top = 614
Width = 185
Height = 13
AutoSize = False
Caption = #40736#26631#22312#34920#26684#19978#21491#38190#35774#32622#38556#30861#28857
end
object strngrdGridPath: TStringGrid
Left = 8
Top = 16
Width = 929
Height = 577
ColCount = 15
DefaultColWidth = 60
FixedCols = 0
RowCount = 21
FixedRows = 0
TabOrder = 0
OnDrawCell = strngrdGridPathDrawCell
OnMouseDown = strngrdGridPathMouseDown
end
object btnClearMap: TButton
Left = 280
Top = 608
Width = 75
Height = 25
Caption = #28165#31354#22320#22270
TabOrder = 1
OnClick = btnClearMapClick
end
object btnFindPath: TButton
Left = 168
Top = 608
Width = 75
Height = 25
Caption = #25628#32034#36335#24452
TabOrder = 2
OnClick = btnFindPathClick
end
object btnSetStart: TButton
Left = 56
Top = 608
Width = 75
Height = 25
Caption = #35774#32622#36215#28857
TabOrder = 3
OnClick = btnSetStartClick
end
end
object frmMain: TfrmMain
Left = 312
Top = 144
BorderStyle = bsDialog
Caption = 'A*'#26368#30701#36335#24452#23547#24452#31639#27861
ClientHeight = 651
ClientWidth = 952
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'MS Sans Serif'
Font.Style = []
OldCreateOrder = False
OnCreate = FormCreate
OnDestroy = FormDestroy
PixelsPerInch = 96
TextHeight = 13
object lbl1: TLabel
Left = 392
Top = 614
Width = 185
Height = 13
AutoSize = False
Caption = #40736#26631#22312#34920#26684#19978#21491#38190#35774#32622#38556#30861#28857
end
object strngrdGridPath: TStringGrid
Left = 8
Top = 16
Width = 929
Height = 577
ColCount = 15
DefaultColWidth = 60
FixedCols = 0
RowCount = 21
FixedRows = 0
TabOrder = 0
OnDrawCell = strngrdGridPathDrawCell
OnMouseDown = strngrdGridPathMouseDown
end
object btnClearMap: TButton
Left = 280
Top = 608
Width = 75
Height = 25
Caption = #28165#31354#22320#22270
TabOrder = 1
OnClick = btnClearMapClick
end
object btnFindPath: TButton
Left = 168
Top = 608
Width = 75
Height = 25
Caption = #25628#32034#36335#24452
TabOrder = 2
OnClick = btnFindPathClick
end
object btnSetStart: TButton
Left = 56
Top = 608
Width = 75
Height = 25
Caption = #35774#32622#36215#28857
TabOrder = 3
OnClick = btnSetStartClick
end
end
作者: mdejtod 发布时间: 2011-10-19
顶楼主. 算法要支持
作者: warrially 发布时间: 2011-10-19
csdn 图片显示这个问题,一直没改正啊。。。鄙视一下
作者: mdejtod 发布时间: 2011-10-19
相关阅读 更多
热门阅读
-
office 2019专业增强版最新2021版激活秘钥/序列号/激活码推荐 附激活工具
阅读:74
-
如何安装mysql8.0
阅读:31
-
Word快速设置标题样式步骤详解
阅读:28
-
20+道必知必会的Vue面试题(附答案解析)
阅读:37
-
HTML如何制作表单
阅读:22
-
百词斩可以改天数吗?当然可以,4个步骤轻松修改天数!
阅读:31
-
ET文件格式和XLS格式文件之间如何转化?
阅读:24
-
react和vue的区别及优缺点是什么
阅读:121
-
支付宝人脸识别如何关闭?
阅读:21
-
腾讯微云怎么修改照片或视频备份路径?
阅读:28