Skip to content

Instantly share code, notes, and snippets.

@sli
Created January 25, 2012 01:06
Show Gist options
  • Select an option

  • Save sli/1673933 to your computer and use it in GitHub Desktop.

Select an option

Save sli/1673933 to your computer and use it in GitHub Desktop.
Dijkstra's algo implementation for Arkham Asylum
from __future__ import generators
class priorityDictionary(dict):
def __init__(self):
'''Initialize priorityDictionary by creating binary heap
of pairs (value,key). Note that changing or removing a dict entry will
not remove the old pair from the heap until it is found by smallest() or
until the heap is rebuilt.'''
self.__heap = []
dict.__init__(self)
def smallest(self):
'''Find smallest item after removing deleted items from heap.'''
if len(self) == 0:
raise IndexError, "smallest of empty priorityDictionary"
heap = self.__heap
while heap[0][1] not in self or self[heap[0][1]] != heap[0][0]:
lastItem = heap.pop()
insertionPoint = 0
while 1:
smallChild = 2*insertionPoint+1
if smallChild+1 < len(heap) and \
heap[smallChild] > heap[smallChild+1]:
smallChild += 1
if smallChild >= len(heap) or lastItem <= heap[smallChild]:
heap[insertionPoint] = lastItem
break
heap[insertionPoint] = heap[smallChild]
insertionPoint = smallChild
return heap[0][1]
def __iter__(self):
'''Create destructive sorted iterator of priorityDictionary.'''
def iterfn():
while len(self) > 0:
x = self.smallest()
yield x
del self[x]
return iterfn()
def __setitem__(self,key,val):
'''Change value stored in dictionary and add corresponding
pair to heap. Rebuilds the heap if the number of deleted items grows
too large, to avoid memory leakage.'''
dict.__setitem__(self,key,val)
heap = self.__heap
if len(heap) > 2 * len(self):
self.__heap = [(v,k) for k,v in self.iteritems()]
self.__heap.sort() # builtin sort likely faster than O(n) heapify
else:
newPair = (val,key)
insertionPoint = len(heap)
heap.append(None)
while insertionPoint > 0 and \
newPair < heap[(insertionPoint-1)//2]:
heap[insertionPoint] = heap[(insertionPoint-1)//2]
insertionPoint = (insertionPoint-1)//2
heap[insertionPoint] = newPair
def setdefault(self,key,val):
'''Reimplement setdefault to call our customized __setitem__.'''
if key not in self:
self[key] = val
return self[key]
def Dijkstra(G,start,end=None):
D = {}
P = {}
Q = priorityDictionary()
Q[start] = 0
for v in Q:
D[v] = Q[v]
if v == end: break
for w in G[v]:
#vwLength = D[v] + G[v][w]
vwLength = D[v] + 1
if w in D:
if vwLength < D[w]:
raise ValueError, "Dijkstra: found better path to already-final vertex"
elif w not in Q or vwLength < Q[w]:
Q[w] = vwLength
P[w] = v
return (D,P)
def shortestPath(G,start,end):
D,P = Dijkstra(G,start,end)
Path = []
while 1:
Path.append(end)
if end == start: break
end = P[end]
Path.reverse()
return Path
### TEST ###
if __name__ == '__main__':
import time
graph = {
# Streets
'Downtown Streets': ['Bank of Arkham', 'Arkham Asylum', 'Independence Square', 'Northside Streets', 'Easttown Streets'],
'Easttown Streets': ["Hibb's Roadhouse", "Velma's Diner", 'Police Station', 'Downtown Streets', 'Rivertown Streets'],
'French Hill Streets': ['The Witch House', 'Silver Twilight Lodge', 'Miskatonic University Streets', 'Rivertown Streets', 'Southside Streets'],
'Merchant District Streets': ['Unvisited Isle', 'River Docks', 'The Unnamable', 'Rivertown Streets', 'Miskatonic University Streets', 'Northside Streets', 'Downtown Streets'],
'Miskatonic University Streets': ['Science Building', 'Administration', 'Library', 'Merchant District Streets', 'French Hill Streets', 'Uptown Streets'],
'Northside Streets': ['Train Station', 'Newspaper', 'Curiositie Shoppe', 'Downtown Streets', 'Merchant District Streets'],
'Rivertown Streets': ['Graveyard', 'Black Cave', 'General Store', 'Easttown Streets', 'Merchant District Streets', 'French Hill Streets'],
'Southside Streets': ["Ma's Boarding House", 'South Church', 'Historical Society', 'Uptown Streets', 'French Hill Streets'],
'Uptown Streets': ["St. Mary's Hospital", 'Ye Olde Magick Shoppe', 'Woods', 'Southside Streets', 'Miskatonic University Streets'],
# Locations
'Administration': ['Miskatonic University Streets'],
'Arkham Asylum': ['Downtown Streets'],
'Bank of Arkham': ['Downtown Streets'],
'Black Cave': ['Rivertown Streets'],
'Curiositie Shoppe': ['Northside Streets'],
'General Store': ['Rivertown Streets'],
'Graveyard': ['Rivertown Streets'],
"Hibb's Roadhouse": ['Easttown Streets'],
'Historical Society': ['Southside Streets'],
'Independence Square': ['Downtown Streets'],
'Library': ['Miskatonic University Streets'],
"Ma's Boarding House": ['Southside Streets'],
'Newspaper': ['Northside Streets'],
'Police Station': ['Easttown Streets'],
'River Docks': ['Merchant District Streets'],
'Science Building': ['Miskatonic University Streets'],
'Silver Twilight Lodge': ['French Hill Streets'],
'South Church': ['Southside Streets'],
"St. Mary's Hospital": ['Uptown Streets'],
'The Unnamable': ['Merchant District Streets'],
'The Witch House': ['French Hill Streets'],
'Train Station': ['Northside Streets'],
'Unvisited Isle': ['Merchant District Streets'],
"Velma's Diner": ['Easttown Streets'],
'Woods': ['Uptown Streets'],
'Ye Olde Magick Shoppe': ['Uptown Streets']
}
s = time.time()
path = shortestPath(graph, 'Train Station', 'South Church')
e = time.time()
print 'Path: %s' % ' -> '.join(path)
print 'Time taken: %.5fs' % (e-s)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment