A* (A-Star) Pathfinding Algorithm Display Grid

Post your working scripts, libraries and tools for AHK v1.1 and older
User avatar
SpeedMaster
Posts: 494
Joined: 12 Nov 2016, 16:09

A* (A-Star) Pathfinding Algorithm Display Grid

07 Feb 2018, 15:05

Hello,

I made a display grid to test the A* (A-Star) algorithm written by Fanaticguru. ;)
I don't know if it works on other PC but I wanted to share it with you. :)
Here is the display grid: :geek:

Code: Select all

; A* Pathfinding Display Grid - by Speedmaster
; topic: https://autohotkey.com/boards/viewtopic.php?f=6&t=43922
;
; autohotkey v.1.1.22 (32bit)
; ASTAR Pathfinder by FanaticGuru 
; https://autohotkey.com/boards/viewtopic.php?p=185714#p185714
; Maze generator:
; https://rosettacode.org/wiki/Maze_solving#AutoHotkey
; ASCII Gaming functions by Speedmaster
; https://autohotkey.com/boards/viewtopic.php?f=19&t=43403

SetBatchLines, -1
SetControlDelay, -1

pico8:={black:"000000", dark_blue:"1D2B53", dark_purple:"7E2553", dark_green:"008751", brown:"AB5236", dark_gray:"5F574F", light_gray:"C2C3C7", white:"FFF1E8", red:"FF004D", orange:"FFA300", yellow:"FFEC27", green:"00E436", blue:"29ADFF", indigo:"83769C", pink:"FF77A8", peach:"FFCCAA"}

path_player:=[]
COLUMNS:=61
ROWS:=46
CELLWIDTH:=15
CELLHEIGHT:=15
VSPACING:="-1"
HSPACING:="-1"
GRIDFONTSIZE:=15
PLAYER:="2_2_2"
target:="2_60_44"
MAP_WIDTH:=COLUMNS
MAP_HEIGHT:=ROWS

;// Tile Types
TILE_ROCKFLOOR  := 0
TILE_WALL       := 1


;TILE_TYPE:={value[character, color, passable=true, tag name]}
TILE_TYPE:={ 0:[  ""  ,pico8.dark_gray  ,true  , "Rock_floor" ]
            ,1:[  "g"  ,pico8.brown     ,false , "Wall"       ] }

gui, font, s12
gui, add, text, x10 y10  h30 cwhite, Press F2 to call the A* Pathfinder (by FanaticGuru)
gui, add, text, xs yp25  h30 cwhite, Left click or use arrow keys to move the player ( @ ) - use right click to move the target ( T )

;// create the Playing area (grid 1)
gui, font, , webdings
putgridtext(10,70,COLUMNS,ROWS,CELLWIDTH,CELLHEIGHT,GRIDFONTSIZE,"green",VSPACING,HSPACING, "0x201 center -border")

;// create the Playing area (grid 2)
gui, font, bold, helvetica
putgridtext(10,70,COLUMNS,ROWS,CELLWIDTH,CELLHEIGHT,12,"green",VSPACING,HSPACING, "0x201 center -border")

gui, font, normal, helvetica
putgridtext(10,70,61,45,15,15,12,"green","-1","-1", "0x201 center hidden border")


;// add help text
gui, add, text, xs yp25  h30 cwhite, F1: Debug Map     F2: Show Path      F3: New Map     F4: Clear Map     F5: Chasing Mode     F6:Show Grid     F7: Save Map
gui, add, text, xs yp25  h30 cwhite,  Crt+Left click : Add Wall    Ctr+Right click : Remove Wall
gui, font, italic s10, consolas
gui, add, text, x750 yp25  h30 cyellow, by Speedmaster

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; create maze
;https://rosettacode.org/wiki/Maze_solving#AutoHotkey
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

oMaze := []	 ; initialize 

loop,  22
  {
	row := A_Index
	loop, 15									     ; create oMaze[row,column] borders 
		col := A_Index, oMaze[row,col] :=  "LRTB"    ; i.e. oMaze[2,5] := LRTB (add all borders)
  }
maze:=Generate_maze(22, 15, oMaze)

world:=maze2text(oMaze)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


;// this function create a 2d array grid DataWorld:{} from a variable
AgLoadDataMap("world")

dataNodes:=[]

for i, j in dataworld
for k, l in j
 {
   if (TILE_TYPE[l].3)
    {
     dataNodes[i,k]:=0  ; (i=col   k=row)
    }
  else
    dataNodes[i,k]:=1  ; (i=col   k=row)
 }


;// Draw the world map 
AgDrawDataMap(dataworld,1,"Drawtile")

gui, +resize
gui, color, black
gui, show,, A* Pathfinding Display Grid v1.0


;// Draw the Player on the grid
drawchar(player, "@", pico8.green)


;// draw the target
drawchar(target, "T", pico8.yellow)


;See wat type of tile is at current player position
lookdata() ; this function look to the datagrid dataworld

return


;left click on cell
clickcell:    

if (click_debug)
msgbox, % a_guicontrol

if !(getKeyState("LCtrl", "P"))
if ispassable(agmove(a_guicontrol,"ex"),agmove(a_guicontrol,"ey"))
 {
   clearcell(player)
   player:=agmove(a_guicontrol,"z",1)
   drawchar(player,"@", pico8.green)
   gosub, find_target
 }

if (getKeyState("LCtrl", "P"))
 {
   drawtile(a_guicontrol,TILE_WALL)
   Dataworld[draw2][draw3]:=TILE_WALL
   dataNodes[draw2][draw3]:=TILE_WALL
 }
return


; right click on cell
GuiContextMenu: 
if chase
{
chase:=!chase
settimer, chaseme, off
} 

if (click_debug)
 msgbox, % a_guicontrol

if !(getKeyState("LCtrl", "P"))
if ispassable(agmove(a_guicontrol,"ex"),agmove(a_guicontrol,"ey"))
 {
  clearcell(target)
  target:=agmove(a_guicontrol,"z",1)
  drawchar(target, "T", "yellow")
  gosub, find_target
 }

if (getKeyState("LCtrl", "P"))
 {
  drawtile(a_guicontrol,Rock_floor)
  Dataworld[draw2][draw3]:=TILE_ROCKFLOOR
  dataNodes[draw2][draw3]:=TILE_ROCKFLOOR
 }

return


up::
player:=agmove(player, "y", -1)
gosub, check_if_passable
return

down::
player:=agmove(player, "y", 1)
gosub, check_if_passable
return

left::
player:=agmove(player, "x", -1)
gosub, check_if_passable
return

right::
player:=agmove(player, "x", 1)
gosub, check_if_passable
return


check_if_passable:
if ispassable(nx, ny)  ; nx= new pos x  ; ny= new pos y
 {
  ;Draw the previously saved tile value to the previous position
  drawtile(previous,TILE_EMPTY)

  ;// Draw the player to the new position
  drawchar(player,"@", pico8.green)

  lookdata() ; update currenttilevalue variable
 }
else
 {
  ;// Don't move the player >> restore previous player postition
  player:=previous
 }
return


IsPassable(npX, npy)   ; npx =new pos x , npy =new pos y
 {
 global
    ;// Store the value of the tile specified 
    tilevalue:= DataWorld[npX][npy]        ;npx = new pos x   npy = new pos y

    ;// Before we do anything, make sure that the coordinates are valid
    if % (npX < 1 || npX > MAP_WIDTH || npy < 1 || npy > MAP_HEIGHT)
      return false

    ;// Return true if it's passable
    ;if % ( TileValue == TILE_FLOOR || TileValue == TILE_WATER || TileValue == TILE_OPENDOOR )
     if Tile_type[TileValue].3
       return true

     ;// If execution get's here, it's not passable
       return False
 }


DrawTile( cellvar, TILE_Value)
 {
  global
  drawchar(cellvar, TILE_TYPE[TILE_Value].1)
  colorcell(cellvar, TILE_TYPE[TILE_Value].2)
 }


lookdata()  ; report wat there is at current player position in data grids 
 {
  global
  PlayerX:=agmove(player,"ex")   ;ex= extract X position of player
  PlayerY:=agmove(player,"ey")   ;ey= extract Y poisiotn of player
  currenttilevalue:= DataWorld[PlayerX][PlayerY]  
 }


Debugtile( cellvar, TILE_Value)
 {
  global
  CellFont(cellvar, "s11", "arial")
  drawchar(cellvar, TILE_Value)
  colorcell(cellvar, TILE_TYPE[TILE_Value].2)
 }


Restoretile( cellvar, TILE_Value)
 {
  global
  CellFont(cellvar, "s11", "webdings")
  drawchar(cellvar, TILE_TYPE[TILE_Value].1)
  colorcell(cellvar, TILE_TYPE[TILE_Value].2)
 }


F7::
; save map
FileSaveAs:
Gui +OwnDialogs  ; Force the user to dismiss the FileSelectFile dialog before returning to the main window.
FileSelectFile, SelectedFileName, S16,, Save File, Text Documents (*.txt)
if SelectedFileName =  ; No file selected.
    return
CurrentFileName = %SelectedFileName%
Gosub SaveCurrentFile
return

SaveCurrentFile:  ; Caller has ensured that CurrentFileName is not blank.
IfExist %CurrentFileName%
{
    FileDelete %CurrentFileName%
    if ErrorLevel
    {
        MsgBox The attempt to overwrite "%CurrentFileName%" failed.
        return
    }
}

Lines := []
text_out := ""
For i, j In Dataworld
   For k, l In j
        {
        Lines[j] .= l
        }
For Each, Line In Lines
   text_out .= Line . "`n"

FileAppend, %text_out%, %CurrentFileName%  ; Save the contents to the file.

msgbox, map saved to %CurrentFileName%

return


f5::
;chasing mode

chase:=!chase
if chase
settimer, chaseme, 500
else
settimer, chaseme, off
return

chaseme:

start:=A_TickCount

path_chase_Monster:=StrSplit(AGPathfind(dataNodes, target, player), ",")

if path_chase_Monster.maxindex()>2
 {

  for i, j in path_chase_Monster
   {
    now := A_TickCount-start
    ;if j
    
    if now > 8000
    break
    
    if !(chase)
    break

    sleep, 100

    clearcell(target)
    if (j!=path_chase_Monster[path_chase_Monster.maxindex()-1])
     {
       drawchar(j,"T", pico8.yellow)
       target:=j
     }
    else
     {
       drawchar(j,"T", pico8.yellow)
       target:=j
       break
     }
   }
 }

return




f1::
; debug map
debugmap:=!debugmap
if debugmap
  AgDrawDataMap(dataworld,1,"DebugTile")
else
  AgDrawDataMap(dataworld,1,"Restoretile")
return


f2::
;show the path

solve:=!solve

if chase
if solve
{
chase:=!chase
settimer, chaseme, off
}


find_target:

if !(solve)
 {
  for i, j in path_player
   {
     if (j!=player) && (j!=target)
     drawchar(j," ")
   }
  path_player:=""
  return
 }

for i, j in path_player
 {
  if (j!=player) && (j!=target)
    drawchar(j," ", pico8.pink)
 }

path_player:=[]
path:=""

path:=AGPathfind(dataNodes, player, target)
path_player:=StrSplit(path, ",")
for i, j in path_player
if (j!=player) && (j!=target)
drawchar(j,"+", pico8.pink)

return


f3::
; draw a new map

if solve
solve:=!solve

drawchar(player, "")
drawchar(target, "")

PLAYER:="2_2_2"
target:="2_60_44"

;// Draw the Player on the grid
drawchar(player, "@", pico8.green)
;// draw the target
drawchar(target, "T", pico8.yellow)


for i, j in path_player
 {
  if (j!=player) && (j!=target)
  drawchar(j," ", pico8.pink)
 }
path_player:=""

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; create new maze
;https://rosettacode.org/wiki/Maze_solving#AutoHotkey

oMaze := []		; initialize 
loop,  22
{
	row := A_Index
	loop, 15											; create oMaze[row,column] borders 
		col := A_Index, oMaze[row,col] :=  "LRTB"		; i.e. oMaze[2,5] := LRTB (add all borders)
}
maze:=Generate_maze(22, 15, oMaze)
world:=maze2text(oMaze)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

dataworld2:=ObjFullyClone(dataworld)

AgLoadDataMap("world")

dataNodes:=[]   ; grid of closed and open nodes

for i, j in dataworld
for k, l in j
 {
   if (TILE_TYPE[l].3) ; if tiletype is false
    {
     dataNodes[i,k]:=0  ; (i=col   k=row)
    }
   else  ; if true
     dataNodes[i,k]:=1  ; (i=col   k=row)
 }


;// Draw the world map
AgDrawDataMapb(dataworld,1,"Drawtile")
return


f9::
;debug click on cell
click_debug:=!click_debug
return


f4::
; clear the map
for i, j in dataworld ;i col k row
for k, l in j
 {
  if !(i=1) && !(k=1) && !(i=dataworld.maxindex()) && !(k=45)
   {
    drawtile("1_" i "_" k,Rock_floor)
    Dataworld[i][k]:=TILE_ROCKFLOOR
    dataNodes[i][k]:=TILE_ROCKFLOOR
   }
 }
return

f6::
showborders:=!showborders

if (showborders)
 {
  gridshow(3)
  gridshowborders(3)
 }
else
  gridhideborders(3)
return



ObjFullyClone(obj)
{
	nobj := obj.Clone()
	for k,v in nobj
		if IsObject(v)
			nobj[k] := A_ThisFunc.(v)
	return nobj
}


guiclose:
esc:: 
exitapp 
return

;Maze generator functions
;https://rosettacode.org/wiki/Maze_solving#AutoHotkey
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

maze2text(oMaze){
	width := oMaze.1.MaxIndex()
	BLK := "¦"
	for row, objRow in oMaze
	{
		for col, val in objRow											; add ceiling
		{
			ceiling := InStr(oMaze[row, col] , "1") && InStr(oMaze[row-1, col] , "1") ? "10" BLK "0" : "1000"
			grid .= (InStr(val, "T") ? "1111" : ceiling) (col = Width ? "1`n" : "")
		}
		for col, val in objRow											; add left wall
		{
			wall := SubStr(val, 0) = "1" ? BLK : "0"
			grid .= (InStr(val, "L") ? "10" : "00") wall "0" (col = Width ? "1`n" : "") ; add left wall if needed then outer right border
		}
	}
	Loop % Width
		Grid .= "1111"													; add bottom floor
	Grid .= "1"															; add right bottom corner
	return RegExReplace(grid , BLK "   (?=" BLK ")" ,  BLK BLK BLK BLK)	; fill gaps
}

Generate_maze(row, col, oMaze) {
	neighbors := row+1 "," col "`n" row-1 "," col  "`n" row "," col+1  "`n" row "," col-1
	Sort, neighbors, random												; randomize neighbors list
	Loop, parse, neighbors, `n											; for each neighbor
	{
		rowX := StrSplit(A_LoopField, ",").1							; this neighbor row
		colX := StrSplit(A_LoopField, ",").2							; this neighbor column
		if !instr(oMaze[rowX,colX], "LRTB") || !oMaze[rowX, colX]		; if visited (has a missing border) or out of bounds
			continue													; skip
 
		; remove borders
		if (row > rowX)													; Cell is below this neighbor
			oMaze[row,col] := StrReplace(oMaze[row,col], "T") , oMaze[rowX,colX] := StrReplace(oMaze[rowX,colX], "B")
		else if (row < rowX)											; Cell is above this neighbor
			oMaze[row,col] := StrReplace(oMaze[row,col], "B") , oMaze[rowX,colX] := StrReplace(oMaze[rowX,colX], "T")
		else if (col > colX)											; Cell is right of this neighbor
			oMaze[row,col] := StrReplace(oMaze[row,col], "L") , oMaze[rowX,colX] := StrReplace(oMaze[rowX,colX], "R")
		else if (col < colX)											; Cell is left of this neighbor
			oMaze[row,col] := StrReplace(oMaze[row,col], "R") , oMaze[rowX,colX] := StrReplace(oMaze[rowX,colX], "L")
 
		Generate_maze(rowX, colX, oMaze)								; recurse for this neighbor
	}
	return, oMaze
}

; Astar_Grid and supporting functions by FanaticGuru 
;topic: https://autohotkey.com//boards/viewtopic.php?p=185714#p185714
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

Astar_Grid(X1, Y1, X2, Y2, closed)  
{

	if !IsObject(Closed)
		Closed := {}
	Open := {}, From := {}, G := {}, F := {}
	Open[X1, Y1] := true, G[X1, Y1] := 0
	F[X1, Y1] := Estimate_F(X1, Y1, X2, Y2)
	while Open.MaxIndex()
	{
		Lowest_F_Set(X, Y, F, Open)
		if (X = X2 and Y = Y2)
			return From_Path(From, X, Y)
		Open[X].Delete(Y)
		if !Open[X].MaxIndex()
			Open.Delete(X)
		Closed[X, Y] := true
		for index, Near in [{"X": X, "Y": Y-1},{"X": X-1, "Y": Y},{"X": X+1, "Y": Y},{"X": X, "Y": Y+1}]
		{
			if (Closed[Near.X, Near.Y] = true)
				continue
			Open[Near.X, Near.Y] := true, tG := G[X, Y] + 1
			if (IsObject(G[Near.X, Near.Y]) and tG >= G[Near.X, Near.Y])
				continue
			From[Near.X, Near.Y] := {"X": X, "Y": Y}
			G[Near.X, Near.Y] := tG
			F[Near.X, Near.Y] := G[Near.X, Near.Y] + Estimate_F(Near.X, Near.Y, X2, Y2)
		}
	}
}

Estimate_F(X1, Y1, X2, Y2)
{
	return Abs(X1-X2) + Abs(Y1-Y2)
}

Lowest_F_Set(ByRef X, ByRef Y, ByRef F, ByRef Set)
{
	l := 0x7FFFFFFF
	for tX , element in Set
		for tY, val in element
			if (F[tX, tY] < l)
				l := F[tX, tY], X := tX, Y := tY
	return l
}

From_Path(From, X, Y)
{
	Path := {}, pb := [], XY := {"X": X, "Y": Y}
	Path.InsertAt(1, XY)


	while (IsObject(From[XY.X, XY.Y]))
		Path.InsertAt(1, XY:= From[XY.X, XY.Y])
		return Path	


}


;ASCII Gaming functions by Speedmaster
;https://autohotkey.com/boards/viewtopic.php?f=19&t=43403
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

AgDrawDataMapb(datagrid, gridnumber:="", function_name:="", Bypass_Values_List:="")
{

global
  For Col, Rows In datagrid
   For Row, value In Rows
    {
     if (gridnumber)
     cell_to_draw=%gridnumber%_%col%_%row%
     else
     cell_to_draw=%col%_%row%

     if value not in %Bypass_Values_List%
     if (dataworld[col][row]!=dataworld2[col][row])
        %function_name%(cell_to_draw, value)
    }
}


AGPathfind(Datagrid, StartCell:="", TargetCell:="")
{

  Closed := {}
  for i, j in Datagrid
  for k, l in j
   {
    if (l = "1")
    Closed[i,k]:= true 
   }

stringsplit, sta, StartCell, _
stringsplit, targ, TargetCell, _

For Key, Node In Astar_Grid(sta2, sta3, targ2, targ3, Closed)
pb .= sta1 . "_" . node.X "_" node.y ","
stringtrimright,pb,pb, 1
return pb

}


 PutGridText(GridPosX="10",GridPosY=10, number_of_columns=3, number_of_raws=3, width_of_cell=100, height_of_cell=100,fontsize:=18,fontcolor:="red", XCellSpacing=0, YCellSpacing=0, options="center 0x200", fill:=" ")
{
 ; create a grid with borders
global

if gridnumber=
GridNumber:=0

GridNumber:=GridNumber+1
MaxCols_Grid%GridNumber%:=number_of_columns
MaxRows_Grid%GridNumber%:=number_of_raws

gui, font, s%fontsize%

gui, add, text,  hidden w0 h0 x%GridPosX% y%GridPosY% section


Row:=0 Col:=0

  loop, %number_of_raws% {
     Row:= ROw+1

     loop, %number_of_columns% {
           Col:= Col+1
           if Col=1
              gui, add, text, section   %options% c%fontcolor% 0x200 BackGroundTrans border hidden0 w%width_of_cell% h%height_of_cell% xs y+%YCellSpacing% v%GridNumber%_%Col%_%Row% gclickcell, %fill%
           else 
              gui, add, text,          %options% c%fontcolor% 0x200 BackGroundTrans border hidden0  w%width_of_cell% h%height_of_cell%  x+%XCellSpacing% ys v%GridNumber%_%Col%_%Row% gclickcell, %fill%
     }
      Col:=0

  }


}

AgLoadDataMap(InputGridMap:="Walls", colsep:="", cols:="maxcols_grid1", rows:="maxrows_grid1")
{
 global
 ;create a col major data grid (create a real 2d data matrix)
 data%InputGridMap%:=[]

 Loop, Parse, %InputGridMap%, `n
  {
    Row := A_Index
    Loop, Parse, A_LoopField, %colsep% , %A_Space%%A_Tab%
     {
        Col := A_Index
        Data%InputGridMap%[Col,Row] := A_LoopField
     }
  }

}

AgDrawDataMap(datagrid, gridnumber:=1, function_name:="", Bypass_Values_List:="")
{
  global
  For Col, Rows In datagrid
  For Row, value In Rows
   {
    cell_to_draw=%gridnumber%_%col%_%row%
    if value is xdigit
    if value not in %Bypass_Values_List%
       %function_name%(cell_to_draw, value)
   }
}

drawchar(varname, chartodraw:="@", color:="")
{
 global
 stringsplit, draw, varname, _
 out:=  draw1 . "_" . draw2 . "_" . draw3
 guicontrol,, %out%, %chartodraw%
 colorcell(out, color)
}

ClearCell(parameters)
{
 DrawChar(parameters, " ")
}

ColorCell(cell_to_paint, color:="red")
{
 GuiControl, +c%color%  , %cell_to_paint%
 GuiControl, hide  , %cell_to_paint%
 GuiControl, show  , %cell_to_paint%
}

CellFont(cell, params:="", fontname:="")
{
 Gui, Font, %params%, %fontname% 
 GuiControl, font , %cell% 
 GuiControl, hide  , %cell%
 GuiControl, show  , %cell%
}

GridShow(gridnumber="1")
{
 global
 Row:=0 Col:=0
  loop, % MaxRows_Grid%gridnumber% {
    Row:= ROw+1
     loop, % MaxCols_Grid%gridnumber% {
        Col:= Col+1
        guicontrol, hide0, %GridNumber%_%Col%_%Row%
     }
    Col:=0
  }
}

GridshowBorders(gridnum="1")
{
 global
 Row:=0 Col:=0
  loop, % MaxRows_Grid%gridnum% {
     Row:= ROw+1

     loop, % MaxCols_Grid%gridnum% {
           Col:= Col+1
           guicontrol, +border, %gridnum%_%Col%_%Row%
         }
      Col:=0
  }
 gui, color,
}

GridHideBorders(gridnum="1")
{
 global
 Row:=0 Col:=0
  loop, % MaxRows_Grid%gridnum% {
     Row:= ROw+1
     loop, % MaxCols_Grid%gridnum% { 
      Col:= Col+1
      guicontrol, -border, %GridNum%_%Col%_%Row%
     }
      Col:=0
  }
 gui, color,
}


AGMove(Varname,axes,value1:=1,value2:=1,value3:=1)
{
  global
 ; Increment Cell variable name in the grid for ex. if you are on cell 1_1_1 to go to the cell "1_2_1" do AGMove("1_1_1", "x", 1)
 ; for ex. if you are on cell 1_1_1 (=grid1 col1 row1) to jump to 2_1_3 (=grid2 col1 row3) do AGMove("1_1_1", "zxy", 1,0,2) 
 ; for ex. if you are on cell 1_1_1 to go to cell 1_2_2 do AGMove("1_1_1", "xy", 1,1)

 ;Call the main function AGM()
AGM(varname,value1,value2,value3)
StringSplit, ar, varname , _

;increment the grid number only
if axes = z
  {
   nz:=value1+ar1
   ny:=ar3
   nx:=ar2
  }

;increment column only
if axes = x
  {
   nz:=ar1
   nx:=value1+ar2
   ny:=ar3
  }

; increment row only
if axes = y
  {
   nz:=ar1
   nx:=ar2
   ny:=value1+ar3
  }

; increment column and row (add value1 to column and value2 to row)
if axes = xy
  {
   nz:=ar1
   nx:=value1+ar2
   ny:=value2+ar3
  }

; select a grid and increment column and row
if axes = zxy
  {
   nz:=value1+ar1
   nx:=value2+ar2
   ny:=value3+ar3
  }

;EZ = extract Z  (return the grid number) 
if axes = EZ
  return ar1

;EX = extract x  (return the column number) 
if axes = EX
  return ar2

;EY = extract y  (return the row number) 
if axes = EY
  return ar3

;SX = set x  (set the colum number) 
if axes = SX
 {
  nz:=ar1
  nx:=value1
  ny:=ar3
  return % nz . "_" . nX . "_" . nY
 }

;SY = set y  (set the row number) 
if axes = SY
 {
  nz:=ar1
  nx:=ar2
  ny:=value1
  return % nz . "_" . nX . "_" . nY
 }

;SZ = set Z  (set the Grid number) 
if axes = SZ
 {
  nz:=value1
  nx:=ar2
  ny:=ar3
  return % nz . "_" . nX . "_" . nY
 }
return % nz . "_" . nX . "_" . nY
}


;AGM is ASCII GAMING MAIN FUNCTION
AGM(varname,NewZ:="1",NewX:="0", NewY:="0")
{
 global Previous, nx, ny, nz
 nx:=0
 ny:=0
 nz:=NewZ
 previous:=varname

 StringSplit, ar, varname , _
 nx:=newX+ar2
 ny:=newY+ar3
 return % nz . "_" . nX . "_" . nY
}
ASTAR.png
ASTAR.png (20.82 KiB) Viewed 2235 times
Instructions: (you can toggle the shortcuts)
Crt+Left click : Add a wall
Ctr+Right click : Remove a wall
F1: Debug Map
F2: Show the path
F3: New Map
F4: Clear Map
F5: Chasing Mode : the target will chase the player
F6: Show Grid
F7: Save Map
f9: Debug click

Any suggestion on how to improve the code are welcome. :roll:

Most of the functions are recycled from my previous ASCII game:
https://autohotkey.com/boards/viewtopic ... 19&t=43403
You can find the pathfinder algorithm (by FanaticGuru) here:
topic: https://autohotkey.com/boards/viewtopic ... ca#p185714
I also used a map generator found here:
https://rosettacode.org/wiki/Maze_solving#AutoHotkey

Other A* pathfinding related topics
https://autohotkey.com/board/topic/3616 ... ng-editor/
https://autohotkey.com/board/topic/7761 ... ng-with-a/
https://autohotkey.com/board/topic/4902 ... m-in-grid/
https://autohotkey.com/board/topic/1470 ... ple-nodes/
Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

Re: A* (A-Star) Pathfinding Algorithm Display Grid

08 Feb 2018, 07:29

:bravo: Very nice, thanks for sharing. It works very well.

Cheers.
User avatar
SpeedMaster
Posts: 494
Joined: 12 Nov 2016, 16:09

Re: A* (A-Star) Pathfinding Algorithm Display Grid

08 Feb 2018, 10:23

Helgef wrote::bravo: Very nice, thanks for sharing. It works very well.

Cheers.
Thanks for your feedback :thumbup:

Return to “Scripts and Functions (v1)”

Who is online

Users browsing this forum: No registered users and 75 guests