Code archives/Algorithms/Dijkstra Map Pathfinding

This code has been declared by its author to be Public Domain code.

Download source code

Dijkstra Map Pathfinding by zoqfotpik2014
Dijkstra maps are a way of caching pathfinding using the Dijkstra algorithm. The caching method was discovered by Brian Walker. Because they are cached, they are much faster than A* or similar runtime pathfinders; the tradeoff is size, and for tilemap games with reasonable sized world maps the size of the pathfinding maps is minimal.

The algorithm has the bonus of being easy to understand and implement, much more so than other pathfinders which are also error prone. As Brian explains on the article where he introduced Dijkstra maps to the world, they can be used for all manner of AI behaviors.

For smooth runtime recalculation of dijkstra maps, you could amortize out the recalculation over many frames.

Just to clarify, the slowness of maze navigation is because of my extremely quick and dirty implementation of the code that actually animates this, not because of any deficiency in the map algorithm.
' Dijkstra map pathfinding, as discovered by Brian Walker, author of the excellent roguelike Brogue.
' Read the below article and hopefully my code makes sense.
' http://www.roguebasin.com/index.php?title=The_Incredible_Power_of_Dijkstra_Maps
' ~ZFP
Global map:Int[64,64]
Global dmap:Int[64,64]

Graphics 640,480

Function initdmap()
'This sets up the initial high value of squares in the dijkstra map
	For x = 0 To 63
	For y = 0 To 63
	dmap[x,y]=66666 ' arbitrary
	Next
	Next
	
End Function

Function initmap()
'Randomly initialize the wall map.  0 is not wall, 1 is wall.
	For i = 0 To 63
	For j = 0 To 63
	If Rand(10)>6 map[i,j]=1
	Next
	Next
End Function

Function calcdmap:Int()
' This performs one pass through the dijkstra map.
	changes = 0 ' how many changes have been made this pass through the dmap.
	For x = 1 To 62
	For y = 1 To 62
		If map[x,y]=0
			lowestvalue = 66666
			For i = x-1 To x+1
				For j=y-1 To y+1
					If i=x And j=y i=i+1
					If dmap[i,j]<lowestvalue lowestvalue = dmap[i,j]
				Next
			Next
			If dmap[x,y]>lowestvalue+1
				dmap[x,y]=lowestvalue+1
				changes=changes+1
			EndIf
		EndIf
	Next
	Next
	Print changes
	Return changes
End Function

Function procdmap()
' Perform multiple passes on the map.  Do it until changestomap = 0
	changestomap = 10000
	While changestomap  > 0 
		changestomap =calcdmap()
	Wend
	
End Function

Function drawdmap()
' Draw a basic heat map for dmap number values
	For i = 0 To 63 
		For j = 0 To 63
			SetColor dmap[i,j]*2,0,0
			If dmap[i,j]=66666 SetColor 255,255,255
			DrawRect i*10,j*10,9,9
		Next
	Next
End Function

initmap()
initdmap()
dmap[1,1]=0
procdmap()
	x = 20 
	y = 20

While Not KeyDown(KEY_ESCAPE)
	Cls
	
	If MouseDown(1)	' Set a new x and y of the navigator dot
		x = MouseX()/10
		y = MouseY()/10
	EndIf
	
	If MouseDown(2) ' set a new goal square and reprocess the dijkstra map
		initdmap()
		dmap[MouseX()/10,MouseY()/10] = 0
		procdmap()
	EndIf
		
	' The below code moves the navigator along the dmap in a very barebones way
	' the slowness of the display is because of this
	nx = x+Rand(3)-2
	ny = y+Rand(3)-2
	If dmap[nx, ny] < dmap[x,y] 
		x = nx
		y = ny
	EndIf
			
	'calcdmap()
	drawdmap()
	SetColor 0,255,0
	DrawRect(x*10,y*10,9,9)
	Flip
Wend

Comments

virtlands2014
This is neat. Thanks to zoqfotpik.
Left-clicking on any spot of the maze shall give the green square a new starting point.

Dijkstra's algorithm :: https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm
Dij's algorithm in C++ :: https://github.com/xtaci/algorithms/blob/master/include/dijkstra.h
Dij's algorithm in C :: http://www.rawbytes.com/dijkstras-algorithm-in-c/
Dij's algorithm in Boost :: http://www.boost.org/doc/libs/1_43_0/libs/graph/doc/dijkstra_shortest_paths.html

A* search algorithm :: http://tinyurl.com/bsv34jm


zoqfotpik2014
And rightclicking reprocesses the map and gives a new goal square.


GW2014
Nice job.

I was able to shave off a few ms by unrolling the inner loops.


zoqfotpik2014
I'm surprised it was only that much. I'm going to be using this in a game and I'll be amortizing the map updates in various ways. It's actually a fairly fast algorithm considering.

Another thing that makes it much faster on map navigation is to have it try the same direction it went last tick first-- that way it moves in straight lines very fast and on map generation algorithms that are more rational this will be basically all the time.


Matty2014
Yeah I used this method or something very similar for years after I worked out how to do it myself just from first principles. I had never heard of the name of it until I saw it somewhere much later.

Pre calculating every grid square to every grid square makes it even faster in real time (of course) but can take a while to precalculate or at least it did on a Pentium 3.


zoqfotpik2014
It probably won't nowadays :)

I'm going to do every room to every room.


Code Archives Forum